Why setuid Is Bad and What You Can Do
Feb 26, 2013 - 11 minutesWhy setuid
is Bad
setuid
allows a binary to be run as a different user then the one invoking it. For example, ping needs to use low level system interfaces (socket
, PF_INET
, SOCK_RAW
, etc) in order to function properly. We can watch this in action by starting ping in another terminal window ( ping google.com
) and then using strace
to see the syscall’s being made:
sudo strace -p PID
and we get the following:
1munmap(0x7f329e7ea000, 4096) = 0stat("/etc/resolv.conf", {st_mode=S_IFREG|0644, st_size=185, ...}) = 0
2socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 4
3connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("8.8.8.8")}, 16) = 0
We can find all setuid programs installed by issuing the command:
1sudo find / -xdev \( -perm -4000 \) -type f -print0 -exec ls -l {} \;
This will find all commands that have the root setuid bit set in their permission bit.
setuid
list for a few popular operating systems:
Of particular interest in OpenBSD, where a lot of work was done to remove and switch programs from needing to use setuid/gid permissions. OpenIndiana is the worst offender and has the widest vector for attack.
- Ubuntu (22 binaries)
- CentOS (21 binaries)
- OpenBSD (3 binaries)
- OpenIndiana (53 binaries)
setuid
escalation is a common attack vector and can allow unprivileged code to be executed by a regular user, and then escalate itself to root and drop you in on the root shell.
Here are a few examples:
CVE-2012-0056: Exploiting /proc/pid/mem
http://blog.zx2c4.com/749 - C code that uses a bug in the way the Linux kernel checked permissions on /proc/pid/mem and then uses that to exploit the su binary to give a root shell.
CVE-2010-3847: Exploiting via $ORIGIN and file descriptors
http://www.exploit-db.com/exploits/15274/ - By exploiting a hole in the way the $ORIGIN is checked, a symlink can be made to a program that uses setuid
and exec
’d ’to obtain the file descriptors which then lets arbitrary code injection (in this case a call to system("/bin/bash")
).
More of these can be found at http://www.exploit-db.com/shellcode/ and just searching google for setuid
exploits.
So you may not want to completely disable the setuid
flag on all the binaries for your distribution, but we can turn on some logging to watch when they’re getting called and install a kernel patch that will secure the OS and help prevent 0-days that may prey on setuid
vulnerabilities.
How to log setuid calls
I will detail the steps to do this on Ubuntu, but they should apply to the other audit daemons on CentOS.
Let’s first install auditd: sudo apt-get install auditd
Let’s open up /etc/audit/audit.rules
, and with a few tweaks with vim, we can insert the list we generated with find into the audit rule set (explanation of each flag after the jump):
1# This file contains the auditctl rules that are loaded# whenever the audit daemon is started via the initscripts.
2# The rules are simply the parameters that would be passed
3# to auditctl.
4
5# First rule - delete all
6-D
7
8# Increase the buffers to survive stress events.
9# Make this bigger for busy systems
10-b 320
11
12# Feel free to add below this line. See auditctl man page
13
14-a always,exit -F path=/usr/lib/pt_chown -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
15-a always,exit -F path=/usr/lib/eject/dmcrypt-get-device -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
16-a always,exit -F path=/usr/lib/dbus-1.0/dbus-daemon-launch-helper -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
17-a always,exit -F path=/usr/lib/openssh/ssh-keysign -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
18-a always,exit -F path=/usr/sbin/uuidd -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
19-a always,exit -F path=/usr/sbin/pppd -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
20-a always,exit -F path=/usr/bin/at -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
21-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
22-a always,exit -F path=/usr/bin/mtr -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
23-a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
24-a always,exit -F path=/usr/bin/traceroute6.iputils -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
25-a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
26-a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
27-a always,exit -F path=/usr/bin/chfn -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
28-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
29-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
30-a always,exit -F path=/bin/fusermount -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
31-a always,exit -F path=/bin/umount -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
32-a always,exit -F path=/bin/ping -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
33-a always,exit -F path=/bin/ping6 -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
34-a always,exit -F path=/bin/su -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
35-a always,exit -F path=/bin/mount -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged
1-a: appends the always, and exit rules. This says to always make a log at syscall entry and syscall exit.
2-F
3 path= says filter to the executable being called
4 perm=x says filter on the program being executable
5 auid>= says log all calls for users who have a UID above 500 (regular user accounts start at 1000 generally)
6 auid!=4294967295 sometimes a process may start before the auditd, in which case it will get a auid of 4294967295
7-k passes a filter key that will be put into the record log, in this case its "privileged"
So now when we run ping google.com we can see a full audit trail in /var/log/audit/audit.log
:
1type=SYSCALL msg=audit(1361852594.621:48): arch=c000003e syscall=59 success=yes exit=0 a0=f43de8 a1=d40488 a2=ed8008 a3=7fffc9c9a150 items=2 ppid=1464 pid=1631 auid=1000 uid=1000 gid=1000 euid=0 suid=0 fsuid=0 egid=1000 sgid=1000 fsgid=1000 tty=pts1 ses=6 comm="ping" exe="/bin/ping" key="privileged"type=EXECVE msg=audit(1361852594.621:48): argc=2 a0="ping" a1="google.com"
2type=BPRM_FCAPS msg=audit(1361852594.621:48): fver=0 fp=0000000000000000 fi=0000000000000000 fe=0 old_pp=0000000000000000 old_pi=0000000000000000 old_pe=0000000000000000 new_pp=ffffffffffffffff new_pi=0000000000000000 new_pe=ffffffffffffffff
3type=CWD msg=audit(1361852594.621:48): cwd="/home/ubuntu"
4type=PATH msg=audit(1361852594.621:48): item=0 name="/bin/ping" inode=131711 dev=08:01 mode=0104755 ouid=0 ogid=0 rdev=00:00
5type=PATH msg=audit(1361852594.621:48): item=1 name=(null) inode=934 dev=08:01 mode=0100755 ouid=0 ogid=0 rdev=00:00
Next steps: Patching and upgrading the kernel with GRSecurity
GRSecurity is an awesome tool in the security-minded system administrators toolbag. It will prevent zero days (like the proc mem exploit explained above 1 ) by securing which areas a user can access. A full list can be seen at http://en.wikibooks.org/wiki/Grsecurity/Appendix/Grsecurity_and_PaX_Configuration_Options and http://en.wikipedia.org/wiki/Grsecurity#Miscellaneous_features, I suggest going through these and seeing if you want to continue with this.
The following below is for advanced users. Not responsible for any issues you may run into, please make sure to test this in a staging/test environment.
Here are the steps I followed to install the patch:
1# Start by downloading the latest kernel
2wget http://www.kernel.org/pub/linux/kernel/v3.0/linux-3.2.39.tar.bz2
3
4# Next extract it
5tar xjvf linux-3.2.39.tar.bz2
6cd linux-3.2.39
7
8# Copy over your current kernel configuration:
9cp -vi /boot/config-`uname -r` .config
10
11# Updates the config file to match old config and prompts for any new kernel options.
12make oldconfig
13
14# This will make sure only modules get compiled only if they are in your kernel.
15make localmodconfig
16
17# Bring up the configuration menu
18make menuconfig
Once your in the menu config you can browse to the Security
section and go to Grsecurity
and enable it. I set the configuration method to automatic and then went to Customize. For example, you can now go to Kernel Auditing -> Exec logging
to turn on some additional logging to shell activities (WARNING: this will generate a lot of log activity, decide if you want to use this or not). I suggest going through all of these and reading through their menu help descriptions (when selecting one, press the ?
key to bring up the help).
Now we’ll finish making the kernel and compiling it:
1# Now we can compile the kernel
2make -j2 # where 2 is the # of CPU's + 1
3
4# Install and load the dynamic kernel modules
5sudo make modules_install
6
7# Finally install kernel
8sudo make install
We can now reboot and boot into our GRsecurity patched kernel!
Hopefully this article has provided some insight into what the setuid
flag does, how it has and can be exploited, and what we can do to prevent this in the future.
Here are a few links to useful books on the subject of shellcode and exploits that I reccomend:
Below is the list of setuid
binaries on each OS
Ubuntu 12.04 LTS (22)
1-rwsr-xr-x 1 root root 31304 Mar 2 2012 /bin/fusermount-rwsr-xr-x 1 root root 94792 Mar 30 2012 /bin/mount
2-rwsr-xr-x 1 root root 35712 Nov 8 2011 /bin/ping
3-rwsr-xr-x 1 root root 40256 Nov 8 2011 /bin/ping6
4-rwsr-xr-x 1 root root 36832 Sep 12 18:29 /bin/su
5-rwsr-xr-x 1 root root 69096 Mar 30 2012 /bin/umount
6-rwsr-sr-x 1 daemon daemon 47928 Oct 25 2011 /usr/bin/at
7-rwsr-xr-x 1 root root 41832 Sep 12 18:29 /usr/bin/chfn
8-rwsr-xr-x 1 root root 37096 Sep 12 18:29 /usr/bin/chsh
9-rwsr-xr-x 1 root root 63848 Sep 12 18:29 /usr/bin/gpasswd
10-rwsr-xr-x 1 root root 62400 Jul 28 2011 /usr/bin/mtr
11-rwsr-xr-x 1 root root 32352 Sep 12 18:29 /usr/bin/newgrp
12-rwsr-xr-x 1 root root 42824 Sep 12 18:29 /usr/bin/passwd
13-rwsr-xr-x 2 root root 71288 May 31 2012 /usr/bin/sudo
14-rwsr-xr-x 2 root root 71288 May 31 2012 /usr/bin/sudoedit
15-rwsr-xr-x 1 root root 18912 Nov 8 2011 /usr/bin/traceroute6.iputils
16-rwsr-xr-- 1 root messagebus 292944 Oct 3 13:03 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
17-rwsr-xr-x 1 root root 10408 Dec 13 2011 /usr/lib/eject/dmcrypt-get-device
18-rwsr-xr-x 1 root root 240984 Apr 2 2012 /usr/lib/openssh/ssh-keysign
19-rwsr-xr-x 1 root root 10592 Oct 5 16:08 /usr/lib/pt_chown
20-rwsr-xr-- 1 root dip 325744 Feb 4 2011 /usr/sbin/pppd
21-rwsr-sr-x 1 libuuid libuuid 18856 Mar 30 2012 /usr/sbin/uuidd
CentOS 6.3 (21)
1-rwsr-xr-x. 1 root root 76056 Nov 5 05:21 /bin/mount-rwsr-xr-x. 1 root root 40760 Jul 19 2011 /bin/ping
2-rwsr-xr-x. 1 root root 36488 Jul 19 2011 /bin/ping6
3-rwsr-xr-x. 1 root root 34904 Jun 22 2012 /bin/su
4-rwsr-xr-x. 1 root root 50496 Nov 5 05:21 /bin/umount
5-rwsr-x---. 1 root dbus 46232 Sep 13 13:04 /lib64/dbus-1/dbus-daemon-launch-helper
6-rwsr-xr-x. 1 root root 10272 Apr 16 2012 /sbin/pam_timestamp_check
7-rwsr-xr-x. 1 root root 34840 Apr 16 2012 /sbin/unix_chkpwd
8-rwsr-xr-x. 1 root root 54240 Jan 30 2012 /usr/bin/at
9-rwsr-xr-x. 1 root root 66352 Dec 7 2011 /usr/bin/chage
10-rws--x--x. 1 root root 20184 Nov 5 05:21 /usr/bin/chfn
11-rws--x--x. 1 root root 20056 Nov 5 05:21 /usr/bin/chsh
12-rwsr-xr-x. 1 root root 47520 Jul 19 2011 /usr/bin/crontab
13-rwsr-xr-x. 1 root root 71480 Dec 7 2011 /usr/bin/gpasswd
14-rwsr-xr-x. 1 root root 36144 Dec 7 2011 /usr/bin/newgrp
15-rwsr-xr-x. 1 root root 30768 Feb 22 2012 /usr/bin/passwd
16---s--x--x. 2 root root 219272 Aug 6 2012 /usr/bin/sudo
17---s--x--x. 2 root root 219272 Aug 6 2012 /usr/bin/sudoedit
18-rwsr-xr-x. 1 root root 224912 Nov 9 07:49 /usr/libexec/openssh/ssh-keysign
19-rws--x--x. 1 root root 14280 Jan 31 06:30 /usr/libexec/pt_chown
20-rwsr-xr-x. 1 root root 9000 Sep 17 05:55 /usr/sbin/usernetctl
OpenBSD 5.2 (3)
1-r-sr-xr-x 1 root bin 242808 Aug 1 2012 /sbin/ping-r-sr-xr-x 1 root bin 263288 Aug 1 2012 /sbin/ping6
2-r-sr-x--- 1 root operator 222328 Aug 1 2012 /sbin/shutdown
OpenIndiana 11 (53)
1-rwsr-xr-x 1 root bin 64232 Jun 30 2012 /sbin/wificonfig--wS--lr-x 1 root root 0 Dec 11 15:20 /media/.hal-mtab-lock
2-r-sr-xr-x 1 root bin 206316 Dec 11 21:00 /usr/lib/ssh/ssh-keysign
3-rwsr-xr-x 1 root adm 12140 Jun 30 2012 /usr/lib/acct/accton
4-r-sr-xr-x 1 root bin 23200 Jun 30 2012 /usr/lib/fs/ufs/quota
5-r-sr-xr-x 1 root bin 111468 Jun 30 2012 /usr/lib/fs/ufs/ufsrestore
6-r-sr-xr-x 1 root bin 106964 Jun 30 2012 /usr/lib/fs/ufs/ufsdump
7-r-sr-xr-x 1 root bin 18032 Jun 30 2012 /usr/lib/fs/smbfs/umount
8-r-sr-xr-x 1 root bin 18956 Jun 30 2012 /usr/lib/fs/smbfs/mount
9-r-sr-xr-x 1 root bin 12896 Jun 30 2012 /usr/lib/utmp_update
10-r-sr-xr-x 1 root bin 35212 Jun 30 2012 /usr/bin/fdformat
11-r-s--x--x 2 root bin 188080 Jun 30 2012 /usr/bin/sudoedit
12-r-sr-xr-x 1 root sys 34876 Jun 30 2012 /usr/bin/su
13-r-sr-xr-x 1 root bin 42504 Jun 30 2012 /usr/bin/login
14-r-sr-xr-x 1 root bin 257288 Jun 30 2012 /usr/bin/pppd
15-r-sr-xr-x 1 root sys 46208 Jun 30 2012 /usr/bin/chkey
16-r-sr-xr-x 1 root sys 29528 Jun 30 2012 /usr/bin/amd64/newtask
17-r-sr-xr-x 2 root bin 24432 Jun 30 2012 /usr/bin/amd64/w
18-r-sr-xr-x 1 root bin 3224200 Jun 30 2012 /usr/bin/amd64/Xorg
19-r-sr-xr-x 2 root bin 24432 Jun 30 2012 /usr/bin/amd64/uptime
20-rwsr-xr-x 1 root sys 47804 Jun 30 2012 /usr/bin/at
21-r-sr-xr-x 1 root bin 8028 Jun 30 2012 /usr/bin/mailq
22-r-sr-xr-x 1 root bin 33496 Jun 30 2012 /usr/bin/rsh
23-r-sr-xr-x 1 root bin 68704 Jun 30 2012 /usr/bin/rmformat
24-r-sr-sr-x 1 root sys 31292 Jun 30 2012 /usr/bin/passwd
25-rwsr-xr-x 1 root sys 23328 Jun 30 2012 /usr/bin/atrm
26-r-sr-xr-x 1 root bin 97072 Jun 30 2012 /usr/bin/xlock
27-r-sr-xr-x 1 root bin 78672 Jun 30 2012 /usr/bin/rdist
28-r-sr-xr-x 1 root bin 27072 Jun 30 2012 /usr/bin/sys-suspend
29-r-sr-xr-x 1 root bin 29304 Jun 30 2012 /usr/bin/crontab
30-r-sr-xr-x 1 root bin 53080 Jun 30 2012 /usr/bin/rcp
31-r-s--x--x 2 root bin 188080 Jun 30 2012 /usr/bin/sudo
32-r-s--x--x 1 uucp bin 70624 Jun 30 2012 /usr/bin/tip
33-rwsr-xr-x 1 root sys 18824 Jun 30 2012 /usr/bin/atq
34-r-sr-xr-x 1 root bin 281732 Jun 30 2012 /usr/bin/xscreensaver
35-r-sr-xr-x 1 root bin 2767780 Jun 30 2012 /usr/bin/i86/Xorg
36-r-sr-xr-x 1 root sys 22716 Jun 30 2012 /usr/bin/i86/newtask
37-r-sr-xr-x 2 root bin 22020 Jun 30 2012 /usr/bin/i86/w
38-r-sr-xr-x 2 root bin 22020 Jun 30 2012 /usr/bin/i86/uptime
39-rwsr-xr-x 1 root sys 13636 Jun 30 2012 /usr/bin/newgrp
40-r-sr-xr-x 1 root bin 39224 Jun 30 2012 /usr/bin/rlogin
41-rwsr-xr-x 1 svctag daemon 108964 Jun 30 2012 /usr/bin/stclient
42-r-sr-xr-x 1 root bin 29324 Jun 30 2012 /usr/xpg4/bin/crontab
43-rwsr-xr-x 1 root sys 47912 Jun 30 2012 /usr/xpg4/bin/at
44-r-sr-xr-x 3 root bin 41276 Jun 30 2012 /usr/sbin/deallocate
45-rwsr-xr-x 1 root sys 32828 Jun 30 2012 /usr/sbin/sacadm
46-r-sr-xr-x 1 root bin 46512 Jun 30 2012 /usr/sbin/traceroute
47-r-sr-xr-x 1 root bin 18016 Jun 30 2012 /usr/sbin/i86/whodo
48-r-sr-xr-x 1 root bin 55584 Jun 30 2012 /usr/sbin/ping
49-r-sr-xr-x 3 root bin 41276 Jun 30 2012 /usr/sbin/allocate
50-r-sr-xr-x 1 root bin 37320 Jun 30 2012 /usr/sbin/pmconfig
51-r-sr-xr-x 3 root bin 41276 Jun 30 2012 /usr/sbin/list_devices
52-r-sr-xr-x 1 root bin 24520 Jun 30 2012 /usr/sbin/amd64/whodo