TryHackMe: Mr Robot CTF Log

syIsTyping
don’t code me on that
9 min readNov 29, 2020

Can you root this Mr. Robot styled machine? This is a virtual machine meant for beginners/intermediate users. https://tryhackme.com/room/mrrobot

Note: This is a log and not a writeup — It’s a record of steps taken to capture the flag, including detours.

Recon

I started with the usualnmap scan ($ip refers to the env var with the box ip):

nmap -sV --script vuln -oN nmap-$ip.out $ip

The interesting parts of the scan were:

  • Port 22 is shown running ssh, but closed
  • Port 80 and 443 are open, running http

At this point I ignored port 22 since it was closed, and port 443 (my assumption was that port 80 was the same and easier to break). The details for port 80 are:

80/tcp  open   http     Apache httpd
| http-csrf:
| Spidering limited to: maxdepth=3; maxpagecount=20; withinhost=10.10.148.27
| Found the following possible CSRF vulnerabilities:
|
| Path: http://10.10.148.27:80/js/BASE_URL
| Form id:
| Form action: http://10.10.148.27/
|
| Path: http://10.10.148.27:80/js/BASE_URL
| Form id:
| Form action: http://10.10.148.27/
|
| Path: http://10.10.148.27:80/js/u;c.appendChild(o);'+(n?'o.c=0;o.i=setTimeout(f2,100)':'')+'}}catch(e){o=0}return
| Form id:
| Form action: http://10.10.148.27/
|
| Path: http://10.10.148.27:80/js/u;c.appendChild(o);'+(n?'o.c=0;o.i=setTimeout(f2,100)':'')+'}}catch(e){o=0}return
| Form id:
| Form action: http://10.10.148.27/
|
| Path: http://10.10.148.27:80/js/rs;if(s.useForcedLinkTracking||s.bcf){if(!s."
| Form id:
| Form action: http://10.10.148.27/
|
| Path: http://10.10.148.27:80/js/rs;if(s.useForcedLinkTracking||s.bcf){if(!s."
| Form id:
| Form action: http://10.10.148.27/
|
| Path: http://10.10.148.27:80/js/vendor/null,this.tags.length=0%7d,t.get=function()%7bif(0==this.tags.length)return
| Form id:
| Form action: http://10.10.148.27/
|
| Path: http://10.10.148.27:80/js/vendor/null,this.tags.length=0%7d,t.get=function()%7bif(0==this.tags.length)return
| Form id:
| Form action: http://10.10.148.27/
|
| Path: http://10.10.148.27:80/wp-login.php
| Form id: loginform
|_ Form action: http://10.10.148.27/wp-login.php
|_http-dombased-xss: Couldn't find any DOM based XSS.
| http-enum:
| /admin/: Possible admin folder
| /admin/index.html: Possible admin folder
| /wp-login.php: Possible admin folder
| /robots.txt: Robots file
| /feed/: Wordpress version: 4.3.1
| /wp-includes/images/rss.png: Wordpress version 2.2 found.
| /wp-includes/js/jquery/suggest.js: Wordpress version 2.5 found.
| /wp-includes/images/blank.gif: Wordpress version 2.6 found.
| /wp-includes/js/comment-reply.js: Wordpress version 2.7 found.
| /wp-login.php: Wordpress login page.
| /wp-admin/upgrade.php: Wordpress login page.
| /readme.html: Interesting, a readme.
| /0/: Potentially interesting folder
|_ /image/: Potentially interesting folder
|_http-server-header: Apache
|_http-stored-xss: Couldn't find any stored XSS vulnerabilities.

I noticed it was running Wordpress, so I started a wpscan scan in the background, while I poked around the website.

wpscan --url $ip | tee wpscan-$ip.out

I loaded the ip in the browser and poked around proxied via Burp. The website was pretty cool to be honest (couldn’t believe it’s on Wordpress!), I went through all the commands and noticed that in the join page, I could input an email and it was presumably uploaded before responding. I KIV’d this info.

Next I tried to access some random path from the browser (like http://$ip/asdf) and got redirected to a “proper” Wordpress site. Poking around I reached the login page and forget-password page. Again, KIV’d for later.

The interesting parts of the wpscan results from earlier was:

ESC[32m[+]ESC[0m robots.txt found: http://10.10.212.63/robots.txt
| Found By: Robots Txt (Aggressive Detection)
| Confidence: 100%
ESC[32m[+]ESC[0m XML-RPC seems to be enabled: http://10.10.212.63/xmlrpc.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
| References:
| - http://codex.wordpress.org/XML-RPC_Pingback_API
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_ghost_scanner
| - https://www.rapid7.com/db/modules/auxiliary/dos/http/wordpress_xmlrpc_dos
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_xmlrpc_login
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_pingback_access
ESC[32m[+]ESC[0m The external WP-Cron seems to be enabled: http://10.10.212.63/wp-cron.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 60%
| References:
| - https://www.iplocation.net/defend-wordpress-from-ddos
| - https://github.com/wpscanteam/wpscan/issues/1299
ESC[32m[+]ESC[0m WordPress version 4.3.1 identified (Insecure, released on 2015-09-15).
| Found By: Emoji Settings (Passive Detection)
| - http://10.10.212.63/1b06af6.html, Match: 'wp-includes\/js\/wp-emoji-release.min.js?ver=4.3.1'
| Confirmed By: Meta Generator (Passive Detection)
| - http://10.10.212.63/1b06af6.html, Match: 'WordPress 4.3.1'
ESC[32m[+]ESC[0m WordPress theme in use: twentyfifteen
| Location: http://10.10.212.63/wp-content/themes/twentyfifteen/
| Last Updated: 2020-08-11T00:00:00.000Z
| Readme: http://10.10.212.63/wp-content/themes/twentyfifteen/readme.txt
| ESC[33m[!]ESC[0m The version is out of date, the latest version is 2.7
| Style URL: http://10.10.212.63/wp-content/themes/twentyfifteen/style.css?ver=4.3.1
| Style Name: Twenty Fifteen
| Style URI: https://wordpress.org/themes/twentyfifteen/
| Description: Our 2015 default theme is clean, blog-focused, and designed for clarity. Twenty Fifteen's simple, st...
| Author: the WordPress team
| Author URI: https://wordpress.org/
|
| Found By: Css Style In 404 Page (Passive Detection)
|
| Version: 1.3 (80% confidence)
| Found By: Style (Passive Detection)
| - http://10.10.212.63/wp-content/themes/twentyfifteen/style.css?ver=4.3.1, Match: 'Version: 1.3'
ESC[32m[+]ESC[0m Enumerating All Plugins (via Passive Methods)
ESC[34m[i]ESC[0m No plugins Found.

The First Key

Then I went to some “interesting” pages and folders from the nmap scan. robots.txt was the most useful, as it pointed to 2 excluded files: key-1-of-3.txt, and a wordlist fsocity.dic. The first key was captured in http://$ip/key-1-of-3.txt and I downloaded the other file for later use.

The Second Key

I figured I would need to compromise the Wordpress admin account to proceed. Looking at the recon earlier, I noticed a few potential entrypoints:

  • Via xmlrpc, there are a few brute-force exploits
  • Via metasploit module scanner/http/wordpress_login_enum
  • Via wpscan options -P and -U

I didn’t know the username yet, so I had to find that first. At first I assumed the admin user was called user (since the blog’s called “user’s blog”) but that turned out to be wrong. I tried the 3 methods in here but none worked:

  • Using wpscan --enumerate u
  • Using Wordpress query param ?author=0
  • Using Wordpress REST api /wp-json/v2/users

Eventually (after 1 day!) I managed to discover the user using 2 approaches.

Discovering user using Burp

On the lost-passwords page, I could test the validity of any user. I setup Intruder to Sniper mode with fsocity.dic as wordlist. Since all the responses returns 200, I sorted by Length and found 1 valid user.

Discovering user using Metasploit

Burp took pretty long to check each user, so I wanted to check whether I could do it faster using Metasploit. I used the scanner/http/wordpress_login_enum module with fsocity.dic as USER_FILE and ran it. Surprisingly, the module did not recognise it as a Wordpress site and did not continue the brute-force.

After searching around, I found that there is an advanced option (viewable in show advanced) called WPCHECK. If set to false, the module skips the Wordpress check. The module worked as expected afterwards and found the user.

On to the password!

Detour to find the wordlist

I tried to discover the password first using Metasploit with rockyou.txt, but after letting that run for some time, I looked around for another wordlist to use. I installed SecLists and tried to use some of the password wordlists but no luck there either. Then I thought, why not try fsocity.dic again? So I did, but that didn’t get anywhere either.

Discovering password using Metasploit

Eventually, this was what worked:

  • use scanner/http/wordpress_xmlrpc_login
  • set USERNAME elliot
  • tac fsocity.doc > fsocity_reversed.dic
  • set PASS_FILE fsocity_reversed.dic

Discovering password using Burp

Just for completeness I tried using Burp too. Since I already know the password, I created a small wordlist and tried using the xmlrpc method from the getUsersBlogs section of this article. Again the response was always 200, but the length difference is more obvious this time.

(As I later found out, there was a much easier way using /license page which can be found via gobuster. I had indeed started gobuster during the recon step, but killed it as it was taking too long — lesson learnt not to be impatient)

Having fun with the admin Wordpress account

Now that I can login as admin, I poked around expecting to see some hidden posts with the key. Unfortunately it wasn’t so easy. I clicked around all the sections, images, settings etc. I attempted to install plugins, but the page took so long to load that I assumed the box must have blocked it. Then, I noticed that there’s another user mich05654 with this “hint” of “another key?”, so I turned my focus to this user.

Long detour to mich05654 and “another key?”

I first reset the password of the user and used that to login. After finding nothing on their account, I thought I must have messed up. Resetting the box, I tried cracking their password using the same steps above (Burp/Metasploit), but got nothing. After some time I managed to locate the password in one of the images in Elliot’s account!

However logging in to mich05654 this way didn’t get me closer to the key. There remains no posts/comments, and posting or commenting didn’t do anything. I checked the cookies as well to no avail.

Another long detour to js files

Putting mich05654 aside, I went back to the website. I had noticed during the recon step that in join command, one single quote (in the sentence “I’ve been fighting”) is not encoded properly and appears as special characters, so I poked around the js files using the browser’s Inspect mode, and using CyberChef to decode in many ways, hoping to find some leads.

Not finding anything useful, I focused next on the email input “form” in the join page. It does a POST to a /join api, so naturally I tried using Burp to try SQL injection. Frustratingly, it kept returning 404 in Burp. I assumed I needed some token or nonce, or that there was some mechanism that could detect if the request was sent from the webpage or Burp. However, after digging through the js scripts further, I noticed that the “real” request also got 404, and concluded that the whole email “upload” was just a UI-driven “feature” which did not actually validate the api response.

(Side note, while doing this I found a easter-egg command 420)

Detour to Metasploit exploits

I tried with these 2 modules, using different settings, but they didn’t work:

  • unix/webapp/wp_admin_shell_upload
  • unix/webapp/php_xmlrpc_eval

Finally breaking in

At this point I got small hints from a friend who had just captured key 2:

  • The key is not on Wordpress itself but it involves Wordpress
  • The exploit needed the admin user’s privileges
  • He had used Metasploit

I then remember something I had seen in Metasploit many times earlier while searching for modules related to Wordpress: a bunch of plugin-based exploits! Time to try installing plugins again!

I noticed that the WPTouch plugin was installed, but of a higher version than desired, so I installed an older version that was vulnerable (the version can be found withinfo exploit/unix/webapp/wp_wptouch_file_upload in Metasploit)

Once installed, the wp_wptouch_file_upload exploit worked, and I had a meterpreter session!

(I later learn that it could be done without Metasploit or plugins, but by editing the PHP script and netcat, which was really an “oh damn” moment because I had done exactly that before in a previous TryHackMe room!)

Getting to the key

I found a user in /home and the key in their dir /home/robot, but had no access. The same dir had a passwords file hashed in raw-md5. I copied the file, and found the plaintext password using john.

john --format=raw-md5 --wordlist=/usr/share/wordlists/rockyou.txt password.md5

With the password, I attempted to change user with su, but ran into an error:

su: must be run from a terminal

Following this handy article, I upgraded my shell using python, su into robot, and then captured the second key.

shell
python -c 'import pty; pty.spawn("/bin/bash")'
su robot
head /home/robot/key-2-of-3.txt

The Third Key

I had a feeling that the 3rd key will need root access, so I tried to do that using meterpreter’s migrate, but couldn’t find any process I recognise (via ps). I tried the SUID approach, looking for systemctl (it was in one of my previous rooms) but could not find it.

Searching around, I found an article explaining how to exploit SUID executables and followed that to gain root:

find / -perm -u=s -type f 2>/dev/null # find programs that has suid
nmap –interactive # nmap interactive
!sh # escape to system shell

Once I had root, the key is easily captured in /root.

--

--

syIsTyping
don’t code me on that

Security engineer and new dad in Japan. I've learnt a lot from the community, so I hope to contribute back. I write technical articles and how-to guides.