Skip to content

5_2_1 PrivEsc Client, no_root_squash enabled

Michael Eder edited this page Dec 29, 2024 · 1 revision

Clients should always use the nodev and nosuid mount options when mounting an NFS export. If one of these options is omitted, it is possible to escalate privileges on the client if an attacker is able to upload files to the export as root which requires the no_root_squash option to be enabled on the server.

This attack is well-known and has been used many times. A modified version of it does not even require the no_root_squash option to be set.

Preconditions

  • Server side: An export has the option `no_root_squash set.
  • Client side: The export is mounted without the nosuid or nodev option, the attack is possible if at least one of these two options is missing.
  • Attacker: The attacker must either have root access on a(nother) client or has to be able to send manipulated traffic to the NFS server.

Attack

There are two versions of this attack depending on which of the two options has been omitted when the export was mounted on the client.

Without the nosuid option

To perform this attack, use the machine where you have root privileges to upload a setuid binary to the NFS server and allow everyone to execute it. You can then simply execute the file on the other clients and get root access.

The typical code for a setuid binary that starts a shell looks like this.

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

int main(void) {
    setuid(0);
    setgid(0);
    system("sh");
}

It can be compiled, given the correct permissions and tested using the following command. At the end you should get a root shell.

gcc -o setuid setuid.c && sudo chown root:root setuid && sudo chmod 6755 setuid && ./setuid

You can now upload this file to the NFS export and run it on the client to get root access.

A detailed description of the attack can be found here.

Without the nodev option

If the export was mounted with nosuid but without the nodev option, the process is more complicated.

The background behind this version of the attack is that the NFS protocol also supports block and character devices files. They contain a major and minor number which are used to identify a device on a machine. If these special files are accessed via NFS, their major and minor numbers are transferred to the client which means that they will always refer to the devices on the client, not those on the server. In order to prevent users on the client machine from accessing these device files, NFS exports should be mounted with the nodev option enabled. For security reasons only NFS clients with root privileges can create devices files in exports. The attack is therefore not possible if no_root_squash is not enabled.

To perform the attack, use the machine where you have root access to create a block device in the export which has the same major and minor number as the operating system drive of the client where you want to escalate privileges. Make the device accessible to everyone and log in to the client. You can now use this file to access raw data on the hard drive while bypassing all security checks of the operating system.

If the client uses an ext file system, you can use debugfs to interact with the disk.

WARNING: This attack is only useful for reading files that can only be read by root. Writing directly to the disk can corrupt the file system, lead to data loss and make the system unbootable especially if the disk is modified while it is mounted. Be extremely careful and only use this method for writing on a machine with no important data and which you can recover if it fails to boot. While testing this attack, creating a file or overwriting /etc/shadow on the operating system partition using debugfs resulted in a corrupted file system.

You can use the mount command to find out on which device the operating system is installed. If you want to see the major and minor of a specific device you can run ls -l /dev/NAME on the target. For example, you might get the following result:

$ ls -l /dev/sd*
brw-rw---- 1 root disk 8, 0 May 27 13:56 /dev/sda
brw-rw---- 1 root disk 8, 1 May 27 13:56 /dev/sda1
brw-rw---- 1 root disk 8, 2 May 27 13:56 /dev/sda2

In this case the operating system is installed on the ext partition on /dev/sda2 which has the major id 8 and minor id 2. debugfs requires a device file that refers to the ext partition, not the entire disk. In the output of ls you can also see that the disks are accessible to a group called disk which does not matter now but will be relevant for another attack.

On the attacker machine you can now create a device file called priv_esc_sda2 in the export and make it accessible to anyone.

$ sudo mknod priv_esc_sda2 b 8 2
$ sudo chmod 666 priv_esc_sda2

You can then access the disk on the client using debugfs by simply running debugfs priv_esc_sda2. This will start an interactive session where you can use familiar commands like cd, ls and cat to perform read operations on the file system. The debugfs binary might not be in your path as an unprivileged user because it is located in the sbin directory, so you may have to use the full path /usr/sbin/debugfs to run it.

You can also use debugfs to write data to the disk, however this is not useful in practice because it may cause data corruption.

WARNING: The following commands resulted in a corrupted file system, but after rebooting and running e2fsck the content of /etc/shadow was overwritten. More work would be needed to find a corruption-free way to modify data on a mounted disk, as debugfs was not designed for this use case.

When you are in debugfs, you can use cat /etc/shadow to read /etc/shadow. You can copy the content to a new file and edit it. To overwrite the file, run rm /etc/shadow and write <PATH_TO_THE_FILE> /etc/shadow.

Choosing the right attack

In order to determine which version of the attack you can use, run the mount command on the client and check the line that contains the NFS export. Consider the following example.

$ mount
...
192.168.247.129:/nfs_test on /mnt/nfs_export type nfs (rw,nosuid,relatime,vers=3,rsize=262144,wsize=262144,...)
...

In this example, the nosuid option is enabled but the nodev option isn't which means that only the second version of this attack is going to work. If the export is mounted with neither of the two options, the first version of the attack is much easier and safer.