NFS (Network File System) is a protocol that allows for easy sharing of files, primarily within a Linux environment. However, with that ease comes a number of security weaknesses, particularly if servers are poorly configured.
In particular, NFS typically relies on the client to enforce access controls – in corporate networks where all systems are centrally controlled, this isn’t a problem. If you can connect a rogue device however (or compromise another device on the network), then you can access files belonging to other users just by having the same user ID as the owner of the file. From a Linux system you have root access to, that’s fairly easy to achieve :-). In some cases, if you’re root on your machine, the NFS server will let you access any files root can.
NFS typically runs on port 2049, and uses the Linux Portmapper service – it will show up in NMap results like this
You can then enumerate any shares on the server with the “showmount” command, which is part of the “nfs-common” package on Debian based systems, and “nfs-utils” on RedHat based systems:
In this instance, we can see that “/public” and “/home” are shared. Mounting the NFS shares to browse them is fairly easy, and can be done by running the following commands as root:
mkdir /mnt/home-nfs/ mount -t nfs 10.13.37.146:home /mnt/home-nfs
You can then just browse to them as if they were a local file:
In this case we can see a list of user directories on the remote system. If we then try to access one, we can see that access is denied:
This would suggest that “root squashing” is enabled on the filesystem, as we were accessing it as the root user, but couldn’t access the content.
Accessing Other Users’ Content
If root squashing is enabled, then in most cases you can access folders belonging to other users by creating a user with the same user ID (UID) as that user (other than UID 0 – root).
If this doesn’t work, then it’s likely that all users are “squashed” (i.e. have their UID set to “nfsnobody” or similar). This means you won’t be able to access any files belonging to other users.
In this example, only the root user is squashed. We can therefore access the “aaron” folder if we have a UID of 1018. The fact that we are seeing the UID tells us that no local user exists with that UID, so we will need to create one. This can be done with the following command (as root):
useradd -u 1018 pentest
To switch to the newly created user, just run:
su - pentest
We can then browse to the directory and see what’s inside:
The presence of the “.bash_history” and “.ssh” folders suggest that this is a user’s home directory, and the “public_html” folder suggests that the Apache “UserDir” plugin is in use.
If you already have a user with a UID that corresponds to one of folders you want to access, the username of the local user will be listed instead of the UID:
You can then just access the files as that user:
Getting a Shell
Depending on the folders that are shared, it may be possible to view or modify files with a view to gaining a shell – of particular interest are the following:
- config or history files containing passwords
- writeable web directories
- writeable directories containing executables (such as /sbin or /bin)
- writeable user profiles
It’s worth looking through any configuration files for passwords – of particular value can be files within the web root, such as wp-config.php, web.config, .htaccess files or similar; as well as user or administrator scripts, which may contain hard coded passwords. If you’ve got lots to search through, some clever grepping may be in order.
User command history files can also be a treasure trove of passwords, especially if users type in the password as part of the command, or paste it into the terminal by mistake.
If you have write access to a web directory (such as /var/www/html or /home/user/public_html), depending on the configuration, it may be possible to upload a custom PHP file containing a web shell, such as the following:
This can then be called via HTTP to execute arbitrary commands on the server:
If you have write access to a user’s home directory, and the server also has SSH listening, then you could add your own SSH key to the authorized_keys file. If the “.ssh” directory within the user profile doesn’t already exist, creating it is quite simple.
If you don’t already have an SSH key, you will need to create one:
You can then just copy your public key into the authorized_keys file with the following command:
cat ~/.ssh/id_rsa.pub >> .ssh/authorized_keys
Make sure that the file permissions are appropriately set on the authorized_keys file (it should be 600).
Next SSH into the server as that user:
If you have a method of executing code on a system, and have access to an NFS share that doesn’t utilise root squashing, then it might be possible to gain elevated (root) privileges on the system 🙂
Simply put, the lack of root squashing will let you upload your own binary files that have a Set UID to root – if you then run these as a normal user on the remote system, they will execute with root privileges.
It turns out Bash won’t run with root privileges if it has the SetUID bit set; but other tools, like Nano or VIM will.
Setting the SUID Bit
To set the SUID bit, connect to the share as root and run the following command against your uploaded file:
chmod u+s uploadedfile
If you then run “ls -la”, you will see that the “s” flag appears in the user permissions, indicating that it is a SUID binary:
Privilege Escalation with a Text Editor
If you have access to a SUID text editor, then you access any file that root can, with the permissions that root has. This means you can read the shadow file, or modify any number of configuration files. In this instance, we’re going to add an entry to the sudoers file.
To do this, launch the copy of nano in the NFS folder, and tell it to open /etc/sudoers:
Then add a sudoers entry to allow our user to run any command as root, without the password (as we don’t know it):
Save the file, and then you should be able to sudo: