def win_money(block1, guessed_state, odds=4): """ With a given block1 and internal md5 state, craft md5s hashes that will meet the game's requirements. Play until enough money has been won. md5_compress(state, block1 + attack padding + forged block2 + padding) """ set_bet_all() set_odds(odds) for i in range(2**16-1): block2 = '_{}'.format(str(i)) fake_pad = padding((16+len(block1))*8) # server nonce is 16 bytes pad = padding((16+len(block1 + fake_pad + block2))*8) h = _encode(md5_compress(guessed_state, block2 + pad), 16).encode('hex') # will I win with this hash? if (int(h, 16) & ((2<<(odds-1))-1)) == 0: print("I should win with this: {} (md5 will be: {})".format(block2, h)) reply = play(block1 + fake_pad + block2) if 'Holy shit you have a lot of money.' in reply: return reply set_bet_all() # show some progress if (i % 1000) == 0: print("working hard...")
def main(): # Take in URL and parse it apiUrl = sys.argv[1] parseURL = urlparse(apiUrl) #Split out the commands and splitCommands = parseURL.query[6:] splitCommands = splitCommands.split('&') #get md5 token from input md5Token = splitCommands[0] #Put commands back together with & symbol commands = ((map('&{0}'.format, splitCommands[1:]))) msg = ''.join(str(p) for p in commands) #Subtract one from length to account for and sybol included at the beginning msgLen = 8 + len(msg) - 1 #Find bits and set md5 hash state bits = (msgLen + len(padding(msgLen * 8))) * 8 h = md5(state=bytes.fromhex(md5Token), count=bits) #Update hash to include new command x = "&command=UnlockSafes" h.update(x) padd = padding((msgLen) * 8) print(parseURL.scheme + '://' + parseURL.netloc + parseURL.path + parseURL.params + '?token=' + h.hexdigest() + msg + quote(padd) + x)
def win_money(block1, guessed_state, odds=4): """ With a given block1 and internal md5 state, craft md5s hashes that will meet the game's requirements. Play until enough money has been won. md5_compress(state, block1 + attack padding + forged block2 + padding) """ set_bet_all() set_odds(odds) for i in range(2**16 - 1): block2 = '_{}'.format(str(i)) fake_pad = padding((16 + len(block1)) * 8) # server nonce is 16 bytes pad = padding((16 + len(block1 + fake_pad + block2)) * 8) h = _encode(md5_compress(guessed_state, block2 + pad), 16).encode('hex') # will I win with this hash? if (int(h, 16) & ((2 << (odds - 1)) - 1)) == 0: print("I should win with this: {} (md5 will be: {})".format( block2, h)) reply = play(block1 + fake_pad + block2) if 'Holy shit you have a lot of money.' in reply: return reply set_bet_all() # show some progress if (i % 1000) == 0: print("working hard...")
def main(): if len(sys.argv) < 2: print("There were no URL's entered as a command line argument") else: for i in range(1, len(sys.argv)): address = sys.argv[i] new_address = "" split_address = address.split("&", 1) #Splits directly after the token get_token = split_address[0].split("=") #Splits directly before the token new_address += get_token[0] + "=" #Gets the token token = get_token[1] #Gets the message behind the token message = split_address[1] #Calculates the length of the message to mimic length_of_m = PASSWORD_LENGTH + len(message) #Calculates the bits of message bits = (length_of_m + len(padding(length_of_m * 8))) * 8 #"Preps" the md5 algorigthm h = md5(state=decode(token, "hex"), count=bits) #Hashes the message to be appended with the old message h.update(NEW_MESSAGE) #Creates the new URL with the binary padding new_address += h.hexdigest() + "&" + message + quote( padding(length_of_m * 8)) + NEW_MESSAGE print(new_address)
def bruteforce_block1_state(block1): """ * Perform a one block md5 where we control partially what's in block1. * Grab 112 bits of state out of this one-block md5 from the server. * Perform a two-block md5 where block1 is the same as our one-block md5, hash-length extend it (w/ home-made padding) and reach a second block. * Grab 112 bits of state out of this two-block md5 from the server. * Locally, use md5's internal functions (md5_compress) directly to brute force the missing bits of the leaked state of the 1-block md5. Use the bits from the two-block md5 leak to know when you guessed state1 correctly. Returns the state that can be used to predict future two-block md5 hashes """ # set odds to 112 to get the largest server leak set_odds(112) # small bet, lets gather intel first set_bet(1) # gather information on state1 state1_leak = play(block1, return_leak=True) print("State 1 server leak: {}".format(state1_leak)) # generate a two block md5 block2 = str(1) fake_pad = padding((16 + len(block1)) * 8) # server nonce is 16 bytes combined = block1 + fake_pad + block2 # play with our two-block md5, grab leaked information of resulting hash target_hash = play(combined, return_leak=True) print("Target hash server leak: {}".format(target_hash)) # to validate that we guessed state1 correctly, lets try to predict the # result of a 2-block hash where state1 is fixed by us. Compare that with # target_hash from the server and if we have a match we know that we guessed # state1 correctly. found = False guessed_state = "" pad = padding((16 + len(combined)) * 8) for i in range(2**16 - 1): attempt = "{:04x}{}".format(i, state1_leak) guessed_state = _decode(unhexlify(attempt), 16) h = _encode(md5_compress(guessed_state, block2 + pad), 16).encode('hex') # have I guessed state1 right? if (target_hash in h): print("Hash found: {} / mid-state guessed: {}".format(h, attempt)) found = True break if not found: print("Couldn't find the state. I won't be able to cheat. Goodbye") sys.exit(1) return guessed_state
def bruteforce_block1_state(block1): """ * Perform a one block md5 where we control partially what's in block1. * Grab 112 bits of state out of this one-block md5 from the server. * Perform a two-block md5 where block1 is the same as our one-block md5, hash-length extend it (w/ home-made padding) and reach a second block. * Grab 112 bits of state out of this two-block md5 from the server. * Locally, use md5's internal functions (md5_compress) directly to brute force the missing bits of the leaked state of the 1-block md5. Use the bits from the two-block md5 leak to know when you guessed state1 correctly. Returns the state that can be used to predict future two-block md5 hashes """ # set odds to 112 to get the largest server leak set_odds(112) # small bet, lets gather intel first set_bet(1) # gather information on state1 state1_leak = play(block1, return_leak=True) print("State 1 server leak: {}".format(state1_leak)) # generate a two block md5 block2 = str(1) fake_pad = padding((16+len(block1))*8) # server nonce is 16 bytes combined = block1 + fake_pad + block2 # play with our two-block md5, grab leaked information of resulting hash target_hash = play(combined, return_leak=True) print("Target hash server leak: {}".format(target_hash)) # to validate that we guessed state1 correctly, lets try to predict the # result of a 2-block hash where state1 is fixed by us. Compare that with # target_hash from the server and if we have a match we know that we guessed # state1 correctly. found = False guessed_state = "" pad = padding((16+len(combined))*8) for i in range(2**16-1): attempt = "{:04x}{}".format(i, state1_leak) guessed_state = _decode(unhexlify(attempt), 16) h = _encode(md5_compress(guessed_state, block2 + pad), 16).encode('hex') # have I guessed state1 right? if (target_hash in h): print("Hash found: {} / mid-state guessed: {}".format(h, attempt)) found = True break if not found: print("Couldn't find the state. I won't be able to cheat. Goodbye") sys.exit(1) return guessed_state
def verify(key='key', data='data', append='append'): init = key + data originalHash = md5(init).hexdigest() pad = padding(len(key + data) * 8) padded = key + data + pad appended = padded + append appendedHash = md5(appended).hexdigest() passLen = len(key) passCmdLen = passLen + len(data) paddingLen = len(padding(passCmdLen * 8)) bits = (passCmdLen + paddingLen) * 8 newToken = GenerateToken(originalHash, append, bits) print '\nH(key||data): \n', originalHash print 'H(key||data||pad||append): \n', appendedHash print 'LEA Generated Hash: \n', newToken
def problem1(): flag = "" #your code here admin_str = b'&role=admin' url_orig = make_query('one', 'hunterythompson', '') url_split0 = url_orig.split(b'&') url_split1 = url_split0[0].split(b'=') #splits string to get md5 md5dig = url_split1[1] str0 = url_split0[1] + b'&' + url_split0[ 2] #creates string of uname & role md5dig = bytes.fromhex( md5dig.decode('utf8')) #convert to bytes to make state h = md5(state=md5dig, count=512) #set state of md5 for future md5dig_admin = h.update(admin_str) #make new md5 hash n_hash = h.hexdigest() n_hashbytes = bytes(h.hexdigest(), 'utf-8') for s in range(1, 65): padding0 = padding((len(str0) + s) * 8) #make padding for string url_new = url_split1[ 0] + b'=' + n_hashbytes + b'&' + str0 + padding0 + admin_str #build new url if (str(make_query('one', 'hunterythompson', url_new), 'utf-8') == 'Incorrect hash'): continue else: return make_query('one', 'hunterythompson', url_new) return
def compute_new_hash(token, user_param): cnt = (8 + len(user_param) + len(padding((len(user_param) + 8) * 8))) * 8 new_hash = md5(state=token.decode("hex"), count=cnt) append_Str = "&command3=UnlockAllSafes" new_hash.update(append_Str) return new_hash.hexdigest()
def extend(self): msg_len = len(self.data) + self.secret_len pad = padding(msg_len * 8) bits_msg = (msg_len + len(pad)) * 8 self.hashB = md5(state=self.signature.decode("hex"), count=bits_msg) self.hashB.update(self.append) return self.getNewData()
def build_new_url(new_token, user_param, path): new_query = "token=" + new_token new_query = new_query + "&" + user_param pad = padding((8 + len(user_param)) * 8) new_query = new_query + quote(pad) new_query = new_query + "&command3=UnlockAllSafes" new_url = path + "?" + new_query return new_url
def problem1(): flag = "" #Msg I want to inject admin = b"&role=admin" #Original Message msg = make_query("one", "amiller68", "") s1 = msg msg = msg.decode('utf-8').split('&', 1)[1] msg = msg.encode() #State I want to build off of s1 = s1.decode('utf-8') s1 = s1[s1.find("=") + 1:s1.find("&")] s1 = s1.encode() #Length of the Msg msg_len = len(msg) * 8 #Don't know the Key Len; brute force different Lens #0 - 192 chars for x in range(0, 192): #Num Chars * 8 is bit len key_len = x * 8 #Req Padding for key + msg req_pad = padding(msg_len + key_len) #len of the pad req_pad_len = len(req_pad) * 8 #Block Count Given Keylen, msg_len, and pad len N = (key_len + msg_len + req_pad_len) #Create md5 hash of state s1 and operating on block len N h = md5(state=s1, count=N) #Update state with desired message h.update(admin) #Extract the Token token = h.hexdigest() #Make the completet Query url = (b'http://www.flickur.com/?api_tag=' + token.encode('utf-8') + b'&' + msg + req_pad + admin) print(url) #Make the Query #Use Byte encodings ret = make_query("one", "amiller68", url) if (ret != b'Incorrect hash'): return ret return flag
def len_ext_attack(url, command_to_add, user_password_length): """ :rtype : void """ # Parse the URL and get the current session token parsedUrl = urlparse.urlparse(url) parameters_list = urlparse.parse_qsl(parsedUrl.query) parameters = dict(parameters_list) # HERE # did not have the -1 before command_to_add = "&command" + str(len(parameters) - 1) + "=" + command_to_add if "token" not in parameters: # if there isn't a token in the parameters quit the program print "There is no token in the url parameters" assert False # remove the session token from the current parameters session_token = parameters["token"] del parameters["token"] length_of_message_with_password = len(urllib.urlencode(parameters)) + user_password_length bits = (length_of_message_with_password + len(padding(length_of_message_with_password * 8))) * 8 h = md5(state=session_token.decode("hex"), count=bits) h.update(command_to_add) # build the query query = "token=" + h.hexdigest() for i in range(1, len(parameters_list)): query += "&" + parameters_list[i][0] + "=" + parameters_list[i][1] query += urllib.quote(padding(length_of_message_with_password * 8)) query += command_to_add conn = httplib.HTTPConnection(parsedUrl.hostname, parsedUrl.port) conn.request("GET", parsedUrl.path + "?" + query) print conn.getresponse().read()
def decipher(query,command,outfile ): with open(query) as query: query=query.read().strip() with open(command) as command: command=command.read().strip() token=(query.split("&")[0]).split("=")[1] user="******"+(query.split("&")[1]).split("=")[1] token=md5(state=token.decode('hex'),count=512) token.update(command) print token.hexdigest() string="token="+token.hexdigest()+"&"+user+urllib.quote(padding(len(user)*8))+command with open(outfile,"w") as outfile: outfile.write(string)
def attack(query, cmd): end_token = query.find('&') token = query[:end_token].split('=')[1] params = query[end_token+1:] pad_bytes = padding((8 + len(params)) * 8) kms = md5(state=token.decode('hex'), count=512) # set start state to end of user string kms.update(cmd) hashed = kms.hexdigest() print(hashed) return "token=" + hashed + "&" + params + quote(pad_bytes) + cmd
def extend_query(query, command): divider_pos = query.find('&') token_query = query[:divider_pos] message_query = query[divider_pos + 1:] token = token_query.split('=')[1] data_length = PASSWORD_LENGTH + len(message_query) padding_text = padding(data_length * 8) md_hash = md5(state=token.decode('hex'), count=512) md_hash.update(command) new_token = md_hash.hexdigest() new_query = ''.join([message_query, quote(padding_text), command]) return (new_token, new_query)
def main(): if len(sys.argv) != 4: print 'Wrong usage.' sys.exit(1) with open(sys.argv[1]) as file: query = file.read().strip() with open(sys.argv[2]) as file: cmd3 = file.read().strip() query = query.split("=", 1)[1] [token, msg] = query.split("&", 1) bits = (8 + len(msg) + len(padding(8 * 8 + len(msg) * 8))) * 8 h = md5(state=token.decode('hex'), count=bits) h.update(cmd3) token = h.hexdigest() # token = md5(msg + urllib.quote(padding(len(msg)*8)) + cmd3).hexdigest() output = 'token=' + token + '&' + msg + urllib.quote( padding(8 * 8 + len(msg) * 8)) + cmd3 with open(sys.argv[3], 'w') as file: file.write(output)
def extend_query(query, command): divider_pos = query.find("&") token_query = query[:divider_pos] message_query = query[divider_pos + 1 :] token = token_query.split("=")[1] data_length = PASSWORD_LENGTH + len(message_query) padding_text = padding(data_length * 8) md_hash = md5(state=token.decode("hex"), count=512) md_hash.update(command) new_token = md_hash.hexdigest() new_query = "".join(["token=", new_token, "&", message_query, quote(padding_text), command]) return new_query
def attack(query, cmd): idx = query.find('&') tmp = query[:idx] token = tmp.split('=')[1] #print token cmds = query[idx + 1:] pad = padding((8 + len(cmds)) * 8) #print quote(pad) before = md5(state=token.decode('hex'), count=512) before.update(cmd) after = before.hexdigest() #print after return "token=" + after + "&" + cmds + quote(pad) + cmd
def main(): keylen = 8 pad = pymd5.padding((keylen + msglen) * 8) padlen = len(pad) #"Intruder message" new_message = query + pad + comm3 cnt = (keylen + msglen + padlen) * 8 h = pymd5.md5(state=token.decode("hex"), count=cnt) h.update(comm3) intruder_token = h.hexdigest() # "Intruder Message and Token" intra_msg = (new_message, intruder_token) print(intra_msg) fo = open("Solution33.txt", "w") fo.write(new_message) server_verify(intra_msg)
def main(): query = open(sys.argv[1], "r") command = open(sys.argv[2], "r") output = open(sys.argv[3], "w") x = query.readlines() token = x[0].split('&')[0].split("=")[1] user = x[0].split('&')[1] + '&' + x[0].split('&')[2] + '&' + x[0].split( '&')[3] #user.append() #print(user) command3 = command.readlines()[0] new_token = md5(state=token.decode("hex"), count=512) new_token.update(command3) pad = quote(padding(len(user) * 8 + 8 * 8)) command = "token=" + new_token.hexdigest() + '&' + user + pad + command3 output.write(command)
def problem1(cnetid): url = b'http://www.flickur.com/?api_tag=' resp = make_query('one', cnetid, '') tag = re.findall(b'api_tag=(\w+)&uname', resp)[0] param = b'&uname=' + cnetid.encode('utf-8') + b'&role=user' start = len(param) * 8 stop = (64 + 1024) * 8 + 1 # max len of secret||param for i in range(start, stop, 8): pad = padding(i) padded_param = param + pad # round to the next multiple of 512 since secret||padded_param is a mult of 512 counter = math.ceil(len(padded_param) * 8 / 512) * 512 # start at secret||padded_param h = md5(state=bytes.fromhex(tag.decode('utf-8')), count=counter) h.update('&role=admin') forged_tag = h.hexdigest() padded_param += b'&role=admin' attack = url + forged_tag.encode('utf-8') + padded_param res = make_query('one', cnetid, attack) if b'flag' in res: return res
# split the url into hostname and rest of the arguements # 'http://eecs388.org/project1/api' hostname = url.split('?')[0] # print hostname # # ['token=b301afea7dd96db3066e631741446ca1', '&user=admin&command1=ListFiles&command2=NoOp'] arguments = url.split('?')[1].split('&', 1) # print arguments # splits hashed value from 'token=b301afea7dd96db3066e631741446ca1' token = arguments[0].split('=')[1] # since the user uses 8-character password # add 8 to the length of the url query len_of_m = 8 + len(arguments[1]) bits = (len_of_m + len(padding(len_of_m*8)))*8 h = md5( state=token.decode("hex"), count=bits ) # suffix is the new command that's going to be appended in the original url query suffix = '&command3=DeleteAllFiles' h.update(suffix); new_token = h.hexdigest() new_url = hostname + '?token=' + new_token + '&' + arguments[1] + urllib.quote(padding(len_of_m*8)) + suffix # print new_url # the new url = # http://eecs388.org/project1/api?token=d127a022396f60239b3d08ecc0c4e3f4 # &user=admin&command1=ListFiles&command2=NoOp%80%00%00%00%00%98%01%00%00%00%00%00%00&command3=DeleteAllFiles # parse url
APPEND = "&command3=DeleteAllFiles" PWDLEN = 8 #define command line arguments url = sys.argv[1] # message = "user=admin&command1=ListFiles&command2=NoOp" append = "&command3=DeleteAllFiles" parsedUrl = urlparse.urlparse(url) query = parsedUrl.query #parse query for arguments queryDictionary = urlparse.parse_qs(query) oldToken = queryDictionary["token"][0] message = "user="******"user"][0] + "&command1=" + queryDictionary["command1"][0] + "&command2=" + queryDictionary["command2"][0] #calculate new token h = md5(state=oldToken.decode("hex"), count=512) h.update(APPEND) newToken = h.hexdigest() #form new query string newQuery = "token=" + newToken + '&' + message + urllib.quote(padding((len(message)+PWDLEN)*8)) + APPEND #make request to server conn = httplib.HTTPConnection(parsedUrl.hostname) conn.request("GET", parsedUrl.path + "?" + newQuery) print conn.getresponse().read()
from pymd5 import md5, padding import httplib, urlparse, sys, urllib m = "Use HMAC, not hashes" h = md5() h.update(m) print h.hexdigest() print len(m) print len(padding(len(m)*8)) h = md5(state="3ecc68efa1871751ea9b0b1a5b25004d".decode("hex"), count=512) x = "Good advice" h.update(x) print h.hexdigest() h = md5() h.update(m + padding(len(m)*8) + x) print h.hexdigest()
if test: dprint("TESTING!!!!!!!!!!!!!!!") dprint(f'{test_password=}') with open(query_file) as query_file, open( command3_file) as command3_file, open(output_file, 'w') as output_file: query_file = query_file.read().strip() command3_file = command3_file.read().strip() dprint(f'{query_file=}') dprint(f'{command3_file=}') old_hash = query_file.split('&')[0].split('=')[1] old_2nd_half = query_file[len(query_file.split('&')[0]) + 1:] old_count = (8 + len(old_2nd_half)) * 8 old_padding = pymd5.padding(old_count) if test: md5test = pymd5.md5() md5test.update(test_password + old_2nd_half) old_hash = md5test.hexdigest() true_padding = pymd5.padding(len(test_password + old_2nd_half) * 8) dprint(f'{true_padding=}') dprint(f'{old_hash=}') dprint(f'{old_2nd_half=}') dprint(f'{old_count=}') dprint(f'{old_padding=}') md5 = pymd5.md5(state=old_hash, count=old_count + len(old_padding) * 8) md5.update(command3_file) new_hash = md5.hexdigest() dprint(f'{new_hash=}')
self.prefix = url[:url.find('=') + 1] self.token = url[url.find('=') + 1:url.find('&')] # suffix starts at the first "command=" and goes to the end of the URL self.suffix = url[url.find('&') + 1:] if __name__ == "__main__": if len(sys.argv) < 2: print(f"usage: {sys.argv[0]} URL_TO_EXTEND [COMMAND_TO_ADD]", file=sys.stderr) sys.exit(-1) url = ParsedURL(sys.argv[1]) # get length of original message length = len(url.suffix) + 8 bits = (length + len(padding(length * 8))) * 8 # add new command h = md5(state=bytes.fromhex(url.token), count=bits) x = "&command=UnlockSafes" h.update(x) # calculate new token and suffix (with padding in the middle) token = h.hexdigest() suffix = url.suffix + quote(padding(length * 8)) + x # new url in format modified_url = "https://project1.eecs388.org/liuspenc/lengthextension/api?token=" + token + "&" + suffix print(modified_url)
#!/usr/bin/python2 from pymd5 import md5,padding from sys import argv for a in argv[1:]: f = open(a) data = f.read() f.close() f = open(a+".padded",'w') f.write(data); f.write(padding(len(data)*8))
from urlparse import urlparse, parse_qs from urllib import quote import httplib, sys ATTACK = "&command3=DeleteAllFiles" url = sys.argv[1] parsed_url = urlparse(url) params = parse_qs(parsed_url.query) token = params.get("token")[0] usr_part = parsed_url.query[39:] m_len = 8 + len(usr_part) padded_len = (m_len + len(padding(m_len * 8))) * 8 digest = md5(state=(token.decode("hex")), count=padded_len) digest.update(ATTACK) new_token = digest.hexdigest() # add the padding needed for this url for new token new_query = "token=" + new_token + "&" + usr_part + quote(padding(m_len * 8)) + ATTACK connection = httplib.HTTPConnection(parsed_url.hostname) my_request = parsed_url.path + "?" + new_query connection.request("GET", my_request) print connection.getresponse().read()
# message = "user=admin&command1=ListFiles&command2=NoOp" append = "&command3=DeleteAllFiles" parsedUrl = urlparse.urlparse(url) query = parsedUrl.query # parse query for arguments queryDictionary = urlparse.parse_qs(query) oldToken = queryDictionary["token"][0] message = ( "user="******"user"][0] + "&command1=" + queryDictionary["command1"][0] + "&command2=" + queryDictionary["command2"][0] ) # calculate new token h = md5(state=oldToken.decode("hex"), count=512) h.update(APPEND) newToken = h.hexdigest() # form new query string newQuery = "token=" + newToken + "&" + message + urllib.quote(padding((len(message) + PWDLEN) * 8)) + APPEND # make request to server conn = httplib.HTTPConnection(parsedUrl.hostname) conn.request("GET", parsedUrl.path + "?" + newQuery) print conn.getresponse().read()
from pymd5 import md5, padding from codecs import decode from urllib import parse import requests import sys url = sys.argv[1] actionNumber = str(url.count("&action") + 1) originalParams = "user="******"&user="******"&user="******"token=") startOfURL = splitedURL[0] + "token=" token = splitedURL[1] msglen = len(originalParams) + 8 bits = (msglen + len(padding(msglen * 8))) * 8 md5Hash = md5(state=decode(token, "hex"), count=bits) attack = "&action" + str(actionNumber) + "=unlock-all-safes" md5Hash.update(attack) newToken = md5Hash.hexdigest() hashPadding = parse.quote(padding(msglen * 8)) newURL = startOfURL + newToken + "&" + originalParams + hashPadding + attack req = requests.get(url=newURL) print(req.text)
import httplib, urlparse, sys, pymd5, urllib url = sys.argv[1] parsedUrl = urlparse.urlparse(url) queryDict = urlparse.parse_qs(parsedUrl.query) state = queryDict['token'][0] #State tokenKey = "token=" length_of_m = 8 + (len(parsedUrl.query) - len(tokenKey + "&") - len(state) ) # length of value orignally passed into md5 #print length_of_m padding = pymd5.padding(length_of_m * 8) count = (length_of_m + len(padding)) * 8 #Count h = pymd5.md5(state=state.decode("hex"), count=512) newCommand = "&command3=UnlockAllSafes" h.update(newCommand) # updates token to include command3 newToken = h.hexdigest() # replaces token value in list with new value #newToken newQuery = tokenKey + newToken + parsedUrl.query[ (len(tokenKey) + len(state)):] + urllib.quote(padding) + newCommand #newQuery conn = httplib.HTTPConnection(parsedUrl.hostname) conn.request("GET", parsedUrl.path + "?" + newQuery)
import httplib, urlparse, sys, urllib url = sys.argv[1] from pymd5 import md5, padding # split around equal and ampersand to get token token = url.split('=')[1].split('&')[0] # split ampersand and generate message params = url.split('&') # generate original message message = params[1] + "&" + params[2] + "&" + params[3] m_len = 8 + len(message) bits = (m_len + len(padding(m_len * 8))) * 8 h = md5(state=token.decode("hex"), count=bits) killamessage = "&command3=DeleteAllFiles" h.update(killamessage) killatoken = h.hexdigest() killaurl = url.split('=')[0] + "=" + killatoken + "&" + message + urllib.quote( padding(m_len * 8)) + killamessage print killaurl parsedUrl = urlparse.urlparse(killaurl) conn = httplib.HTTPConnection(parsedUrl.hostname) conn.request("GET", parsedUrl.path + "?" + parsedUrl.query) print conn.getresponse().read()
import sys from pymd5 import md5, padding from urllib import quote import re query_file = sys.argv[1] command3_file = sys.argv[2] output_file = sys.argv[3] with open(query_file) as f: query = f.read().strip() with open(command3_file) as f: command3 = f.read().strip() m = re.search(r'user=.*', query).group() # match user=...&commands length_of_m = 8 + len(m) # 8 is password length bits = (length_of_m + len(padding(length_of_m * 8))) * 8 token = re.search(r'(?<=token=)[0-9a-fA-F]+(?<!&)', query).group() # match the token h = md5(state = token.decode('hex'), count = bits) h.update(command3) new_token = h.hexdigest() with open(output_file, 'w') as f: f.write("token=" + new_token + "&" + m + quote(padding(length_of_m * 8)) + command3)
command = "DeleteAllFiles" parsed_url = urlparse.urlparse(url) url_parts = { key: value for (key, value) in [pair.split('=') for pair in parsed_url.query.split('&')] } next_cmd = max( [int(key[-1]) for key in url_parts.keys() if key[:-1] == 'command']) + 1 # note: +2 is for & preceding key and = between key=val, and -1 is for & missing from first key ("user") m = sum( [len(k) + len(url_parts[k]) + 2 for k in url_parts.keys() if k != 'token']) - 1 + 8 cmd3 = "&command" + str(next_cmd) + "=" + command paddedCmd3 = urllib.quote(padding(m * 8)) + cmd3 #update the token using the md5 module h = md5(state=url_parts["token"].decode("hex"), count=512) h.update(cmd3) new_token = h.hexdigest() #make a new url from the new token with the new command url = str.replace(url, url_parts["token"], new_token) + paddedCmd3 #code given to connect to server and send requests parsedUrl = urlparse.urlparse(url) conn = httplib.HTTPConnection(parsedUrl.hostname, parsedUrl.port) conn.request("GET", parsedUrl.path + "?" + parsedUrl.query) print conn.getresponse().read()
tokenbak = token query = "token=" + token + "&" + query ''' Read the new command ''' fi = open("3.3_command3.txt") comm3 = fi.readline().strip() fi.close() ''' Extract token (hash) and message from the query ''' token = query[query.index("=")+1:query.index("&")] msg = query[query.index("&")+1:] ''' Compute the padding of current message ''' msglen = len(msg) for keylen in range(0, 10): pad = pymd5.padding((keylen+msglen)*8) padhex = pad.encode("hex") ''' Setup the md5 hash function ''' padlen = len(pad) cnt = (keylen + msglen + padlen) * 8 h = pymd5.md5(state=token.decode("hex"), count=cnt) h.update(comm3) ''' Get the new token and create new query ''' newtoken = h.hexdigest() newquery = query.replace(token, newtoken) newquery += pad newquery += comm3 ''' Verify '''
url = sys.argv[1] parsedUrl = urlparse.urlparse(url) urlprefix = parsedUrl.scheme + "://" + parsedUrl.netloc + parsedUrl.path + '?' string = parsedUrl.query assert string[0:6] == "token=" for i in range(0, len(string)): if string[i] == '&': token = string[6:i] message = string[i + 1:] break secret = "password" attack = "&command3=UnlockAllSafes" # attack command pad = pymd5.padding(len(secret + message) * 8) h = pymd5.md5(attack, state=token.decode("hex"), count=512) token_attack = h.hexdigest() urlprefix = urlprefix + "token=" message = message + urllib.quote(pad) + attack # QUOTE is super important! url = urlprefix + token_attack + "&" + message parsedUrl = urlparse.urlparse(url) conn = httplib.HTTPSConnection(parsedUrl.hostname, parsedUrl.port) conn.request("GET", parsedUrl.path + "?" + parsedUrl.query) print conn.getresponse().read()
len_og_msg = 0 count_of_extra = 0 query.pop(0) for n in query: len_og_msg += len(n) count_of_extra += 1 len_og_msg += 8 + count_of_extra - 1 #Concatenate all queries for single command command = "" for n in query: command += n + "&" command = command[:-1] print(command) pad = quote(padding(len_og_msg * 8)) #Calculate hash with count bits of new message bits = (len_og_msg + len(padding(len_og_msg * 8))) * 8 h = md5(state=bytes.fromhex(token[1]), count=bits) h.update(hack_msg) #Re-Combine URL newUrl = '{scheme}://{netloc}{path}?token={token}&{command}{pad}{suffix}'.format( scheme=parsed.scheme, netloc=parsed.netloc, path=parsed.path, token=h.hexdigest(), command=command, pad=pad, suffix=hack_msg)
import sys from urllib import quote with open(sys.argv[1]) as query_file: query_text = query_file.read().strip() with open(sys.argv[2]) as command3_file: command3 = command3_file.read().strip() print command3 h_known = query_text[6:6+32] print h_known rest = query_text[6+32+1:] print rest len_text = 8 + len(rest) padding_text = padding(len_text*8) print padding_text bits = (len_text + len(padding_text))*8 #bit lenth of padded text h_ext = md5(state = h_known.decode("hex"), count = bits) h_ext.update(command3) print h_ext.hexdigest() new_query = query_text[0:6] + h_ext.hexdigest() + query_text[6+32:] + quote(padding_text) + command3 print new_query with open(sys.argv[3], "w+") as output: output.write(new_query)
from pymd5 import md5, padding import urllib #token=94d5acaecc0d6d45f6bdabe2948722d2&user=admin&command1=ListFiles&command2=NoOp m = "&command3=DeleteAllFiles" x = md5() h = md5(state="94d5acaecc0d6d45f6bdabe2948722d2".decode("hex"), count=512) h.update(m) h = h.hexdigest() url = "token=" + h + "&user=admin&command1=ListFiles&command2=NoOp" + urllib.quote( padding(52 * 8)) + m f = open("./sol_2.1.2.txt", "wb") f.write(url)
from pymd5 import md5, padding import httplib, urlparse, sys, urllib password_length = 8 appended_command = "&command3=DeleteAllFiles" url = sys.argv[1] # Get user & token querystring = url[url.find('?') + 1:] original_token = urlparse.parse_qs(querystring)['token'][0] original_message = url[url.find('user='******'?')[0] + '?' url += 'token=' + new_token + '&' url += original_message + appended_string # Your code to modify url goes here parsedUrl = urlparse.urlparse(url) conn = httplib.HTTPConnection(parsedUrl.hostname) conn.request("GET", parsedUrl.path + "?" + parsedUrl.query)