When an executable with the suid bit is run, it will always run as the user who owns the file, irrespective of the current user. A familiar example is the ping utility. Ping must run as the root user because it opens raw IP sockets, so it has the suid bit set. When an ordinary user runs ping, the process is running as root because /bin/ping is owned by root.
Examining the permissions of /bin/ping
To view the permissions of a file, the stat -c "%a"
command is used
4755
root@b6386528aa87:/# stat -c %a /bin/bash
755
root@b6386528aa87:/#
Looking at the /bin/ping
file, we can see it has an extra permission bit (4), which bash does not have. This is the suid bit.
Adding and removing the suid bit
The chmod
utility can be used to add the suid
bit to an executable file. Let's look at what happens when we remove suid
from ping
and add it to the whoami
executable
root@b6386528aa87:/# chmod -s /bin/ping
root@b6386528aa87:/# sudo -u nobody ping -c1 127.0.0.1
ping: Lacking privilege for raw socket.
root@b6386528aa87:/# sudo -u nobody whoami
root
root@b6386528aa87:/#
After removing setuid
from ping, we cannot ping as an unprivileged user. Conversely, after adding the suid
bit, whoami
reports root
even when running as nobody
.
Finding all SUID binaries
The find
command can be used to search for all the executables with the SUID permission (-perm -4000). In the following example, find is passing its output to ls -ldb
. The -user root
can be used to restrict the search to files owned by root.
-rwsr-xr-x. 1 root root 40000 Mar 29 2015 /bin/mount
-rwsr-xr-x. 1 root root 70576 Oct 28 2014 /bin/ping
-rwsr-xr-x. 1 root root 61392 Oct 28 2014 /bin/ping6
-rwsr-xr-x. 1 root root 40168 Feb 24 2017 /bin/su
-rwsr-xr-x. 1 root root 27416 Mar 29 2015 /bin/umount
-rwsr-xr-x. 1 root root 53616 Feb 24 2017 /usr/bin/chfn
-rwsr-xr-x. 1 root root 44464 Feb 24 2017 /usr/bin/chsh
-rwsr-xr-x. 1 root root 75376 Feb 24 2017 /usr/bin/gpasswd
-rwsr-xr-x. 1 root root 39912 Feb 24 2017 /usr/bin/newgrp
-rwsr-xr-x. 1 root root 54192 Feb 24 2017 /usr/bin/passwd
Disabling SUID Globally
Warning: This may break things
The SUID permission can be ignored globally by using the -o nosuid
flag when mounting root. This will break things like sudo
or su
or services that drop privileges.
rohan@localhost:~$ sudo whoami
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?
Disabling SUID in Containers
The SUID
capability can be dropped in containers via the --cap-drop=setuid
option. See this page for more information https://www.redhat.com/en/blog/secure-your-containers-one-weird-trick
Replacing SUID with Granular Capabilities
The SUID
permission does not provide granular privilege escalation. When a binary (for instance, /bin/ping
) is elevated to root, it can do anything and everything, such as writing to system directories, installing kernel modules, or messing with hardware. This is poor security practice as it violates the principle of least privilege.
Going back to the example of /bin/ping
, it runs as root because it requires the cap_net_raw
privileged capability. So rather than elevating it to root, we can tell the kernel to grant that capability to that executable, even if invoked by an unprivileged user.
[root@centos7 ~]# sudo -u nobody ping -c1 localhost
ping: socket: Operation not permitted
[root@centos7 ~]# setcap cap_net_raw+p /bin/ping
[root@centos7 ~]# sudo -u nobody ping -c1 localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.045 ms
That's all for now. Thanks for reading!