def find_prefix_length(encryptor, block_size=16): test_input = b'A' * block_size * 2 for i in range(block_size): encrypted_block = encryptor(test_input) duplicate_block = block.findDuplicateBlock(encrypted_block, block_size) if duplicate_block: duplicate_index = block.blockSplit( encrypted_block, block_size).index(duplicate_block) prefix_length = (duplicate_index * block_size) - i test_input = b'B' + test_input return prefix_length
import utils import strcon import itertools import block block_length = 16 texts = [ strcon.hexToBytes(t) for t in utils.import_file("Inputs/8.txt", split=True) ] for text in texts: blocks = block.blockSplit(text, block_length) for combo in itertools.combinations(blocks, 2): if combo[0] == combo[1]: print('Detected duplicate! Text was {0}, block was {1}'.format( strcon.bytesToHex(text), strcon.bytesToHex(combo[0]))) break
#Strategy: 1) Find the encrypted block for "user" + padding_bytes # 2) Feed input of different lengths until that block is found # 3) Find the encrypted block for "admin" + padding_bytes # 4) Replace the user block with the admin block def find_encrypted(plaintext_block, block_size=16): crafted_input = b'A' * (block_size - len("email=")) + (plaintext_block * 2) return block.findDuplicateBlock(encrypted_profile(crafted_input), block_size) #step 1 user_email = block.pkcsPadding(b"user", block_size) user_block = find_encrypted(user_email) #step 2 for i in range(block_size): email = b'A' * i if user_block in block.blockSplit(encrypted_profile(email), block_size): attack_length = i break #step 3 admin_email = block.pkcsPadding(b"admin", block_size) admin_block = find_encrypted(admin_email) #step 4 attacked_profile = encrypted_profile(b'A' * attack_length) attacked_profile_blocks = block.blockSplit(attacked_profile, block_size) modified_profile = b''.join(attacked_profile_blocks[:-1] + [admin_block]) #reveal print(profile_decryptor(modified_profile, key))
return False assert (has_valid_padding(encryption_oracle()[0])) #Strategy: 1) Compile (prev_block || block) strings from the ciphertext and IV # 2) For each string repeat steps 3-6: # 3) Use bitflipping on prev_block to edit the final byte of block # 4) Eventually the padding oracle will return True # 5) Perform xor(\x01, edit) to get the plaintext byte # 6) Edit the final byte to \x02, and cycle through edits for the # penultimate byte until we get valid padding etc. #Step 1 ciphertext, IV = encryption_oracle() blocks = [IV] + block.blockSplit(ciphertext, block_size) consec_blocks_list = [blocks[i:i + 2] for i in range(len(blocks) - 1)] # Step 2 def decrypt_block(consec_blocks, reverse_search=False): """Given a list [prev_block, block], decrypts block""" prev_block, block = consec_blocks prev_block_edit = bytearray(prev_block) plaintext = bytes() for i in range(1, len(block) + 1): start_val = prev_block_edit[-i] search_range = range(255, -1, -1) if reverse_search else range(256) for b in search_range: prev_block_edit[-i] = b if has_valid_padding(bytes(prev_block_edit + block)):
#Step 1 def calculate_filler_length(encryptor): """Finds the length of input such that the last block is all padding""" filler = bytes() basic_length = current_length = len(encryptor(filler)) while basic_length == current_length: filler += b'A' current_length = len(encryptor(filler)) return len(filler) filler_length = calculate_filler_length(encryption_oracle) #Step 2 ciphertext = encryption_oracle(b'A' * filler_length) #Step 3 ciphertext_blocks = block.blockSplit(ciphertext, block_size) padding_block = bytes(block_size * [block_size]) admin_string = b";admin=true;" admin_block = admin_string + (b'A' * (block_size - len(admin_string))) evil_block = xor.xorBytes(xor.xorBytes(ciphertext_blocks[-2], padding_block), admin_block) modified_ciphertext = b''.join(ciphertext_blocks[:-2] + [evil_block] + [ciphertext_blocks[-1]]) #Step 4 if detect_admin(modified_ciphertext): print("You are now the admin. Muahahahaha") print(decryptor(modified_ciphertext))