learn/phase-3/p3-w12/lesson 06
Milestone 12 · lesson 6

Linux Capabilities for Privilege Escalation

Hands-on. Capabilities are SUID's fine-grained cousin, and the dangerous ones hand you root just the same.
Lab: Cap It Off

Enumerate file capabilities, find the dangerous one, and read the root flag it grants.

What you'll learn

  • Explain what a Linux capability is and how it differs from the all-or-nothing SUID bit.
  • List every file that carries capabilities with getcap, the enumeration command.
  • Recognise the capabilities that mean root: cap_setuid, cap_dac_read_search, cap_dac_override.
  • Abuse a cap_setuid binary (like python) to become root, and know the fix.

Linux Capabilities for Privilege Escalation

You've seen SUID, where a binary runs with its owner's full privileges. Capabilities are the modern, fine-grained version: instead of giving a program all of root's power, the kernel splits root into ~40 separate capabilities and hands a binary only the specific ones it needs. Safer in theory, but the wrong capability on the wrong binary is still a straight line to root.

SUID root
all-or-nothing
👑 the entire crown — every root power at once
Capabilities
root split into ~40 keys
cap_net_rawcap_setuidcap_dac_override…~40 total

Fewer powers is safer — but the wrong single key (e.g. cap_setuid) is still a full root shell.

The idea

Take ping. It needs to open a raw network socket, a root-only action, but it doesn't need the rest of root's power. The old way was to make it SUID root (over-privileged). The capability way is to grant it only cap_net_raw:

/usr/bin/ping = cap_net_raw+ep

Now ping can open its socket and nothing more. That's the whole point of capabilities: least privilege, one power at a time. The letters after the +:

  • e (Effective) , the capability is active the moment the binary runs.
  • p (Permitted) , the binary is allowed to use it.

+ep is what you'll see on anything actually exploitable.

Enumerate them

One command lists every file carrying capabilities:

getcap -r / 2>/dev/null

Read the output looking for dangerous capabilities on general-purpose binaries (interpreters, shells, editors). cap_net_raw on ping is fine. cap_setuid on python is a root shell.

The capabilities that mean root

CapabilityWhat it grantsWhy it's game over
cap_setuidset any user IDbecome uid 0, straight to root
cap_dac_read_searchbypass file read checksread /etc/shadow, /root/*, any file
cap_dac_overridebypass read/write/exec checksread and write any file (edit /etc/passwd)
cap_sys_admina huge grab-bag of admin powersmany paths to root

Exploiting cap_setuid

If a program that can run other code has cap_setuid, tell it to become root and spawn a shell. With Python:

$ getcap -r / 2>/dev/null
/usr/bin/python3.11 = cap_setuid+ep

$ /usr/bin/python3.11 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# id
uid=0(root) ...

GTFOBins lists the exact payload for each binary+capability pair (perl, ruby, node, gdb, and more), the same idea as SUID GTFOBins.

Exploiting cap_dac_read_search

You don't even need a shell, just read what you shouldn't:

# a binary with cap_dac_read_search can read root-only files
$ ./reader /etc/shadow      # dump the hashes, then crack offline

The fix (what you report)

Grant capabilities sparingly and never on interpreters or shells. Audit with getcap -r /, remove any capability a binary doesn't strictly need (setcap -r <file>), and prefer capabilities over SUID only when the capability set is truly minimal. Report the exact file and capability.

Common questions

"How is this different from SUID? They both give root." SUID hands over all of root at once. A capability hands over one specific power. cap_net_raw on ping is harmless because opening a socket isn't enough to own the box; cap_setuid on python is game over because "become any user" includes becoming root. The danger is the specific capability, not the fact that one exists.

"getcap -r / printed nothing. Does that mean I'm safe here?" It means no files carry capabilities, so this vector is a dead end, move on to SUID, sudo, cron, or writable files. An empty result is a normal, common outcome; capabilities are a sometimes win, not an always.

"Which capabilities actually matter?" Memorise three: cap_setuid (become root), cap_dac_read_search (read any file, e.g. /etc/shadow), cap_dac_override (read and write any file, e.g. /etc/passwd). cap_sys_admin is a grab-bag with many paths too. The rest are rarely the direct route.

"What do +ep, +ei, +p mean at the end?" They're the capability's states. e = Effective (active as soon as it runs), p = Permitted (allowed to use). +ep is the exploitable combo; a capability that's only Permitted or Inheritable (+i) may need extra steps to activate.

Why this matters

Capabilities look obscure, so they're often overlooked by both defenders and beginners, which is exactly why they're a reliable privesc. getcap -r / takes one second and, on a surprising number of boxes, prints your way to root.

Check your understanding

4 questions

Type an answer and press Check. Grading is keyword-based and forgiving, so short answers are fine.

  1. 1

    Write the command that recursively lists every file on the system that has Linux capabilities set.

  2. 2

    You find /usr/bin/python3.11 = cap_setuid+ep. Write the one-liner that uses it to become root.

  3. 3

    Which capability lets a binary read ANY file on the system, bypassing normal read permissions?

  4. 4

    In cap_setuid+ep, what does the +ep mean?