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 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 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