#!/usr/bin/python3 -u # requirements: PyCryptodome import base64 import subprocess from Crypto.Util.strxor import strxor from Crypto.Util.Padding import pad ### variables to set PLAINTEXT = b"id=12345678;name=myname;is_admin=false;mail=mymail@mail.com" CIPHERTEXT = base64.b64decode("RlDfIOgTrnUsIZJE802+wNr0jll/3ZiM4BGHH7xMO8TF0QBkebuuychCaeDBhUP2kOJnerZm3kQoe3h9Sv12oA==") BLOCK_SIZE = 16 # AES PADDING_TYPE = "pkcs7" OLD_STR = b"false" # string to flip NEW_STR = b"true;" # string that will replace OLD_STR xxd_cmd = ["xxd", "-g1", "-c", str(BLOCK_SIZE)] print("\n[+] Infos:") print("OLD_STR = %s" % OLD_STR) print("NEW_STR = %s" % NEW_STR) print("\n[+] Plaintext (%d bytes):" % len(PLAINTEXT)) subprocess.run(xxd_cmd, input=PLAINTEXT) if len(PLAINTEXT) != len(CIPHERTEXT): PLAINTEXT = pad(PLAINTEXT, block_size=BLOCK_SIZE, style=PADDING_TYPE) print("\n[+] Plaintext [Padded with %s] (%d bytes):" % (PADDING_TYPE, len(PLAINTEXT))) subprocess.run(xxd_cmd, input=PLAINTEXT) print("\n[+] Ciphertext (%d bytes):" % len(CIPHERTEXT)) subprocess.run(xxd_cmd, input=CIPHERTEXT) assert len(PLAINTEXT) == len(CIPHERTEXT) assert len(CIPHERTEXT) % BLOCK_SIZE == 0 assert OLD_STR in PLAINTEXT assert len(OLD_STR) == len(NEW_STR) blocks = [PLAINTEXT[i:i + BLOCK_SIZE] for i in range(0, len(PLAINTEXT), BLOCK_SIZE)] block_offset = 0 in_block = -1 for block_id, block in enumerate(blocks): if OLD_STR in block: in_block = block_id block_offset = block.find(OLD_STR) break if in_block == -1: raise Exception("String to flip must be contained in one single block") elif in_block == 0: raise Exception("String to flip cannot be part of the first block") # pos = same block offset ,in previous block pos = (in_block - 1) * BLOCK_SIZE + block_offset end_pos = pos + len(OLD_STR) # here the magic happens... result = CIPHERTEXT[:pos] result+= strxor( strxor(OLD_STR,NEW_STR), CIPHERTEXT[pos:end_pos] ) result+= CIPHERTEXT[end_pos:] print("\033[32m\n[+] Flipped ciphertext:") subprocess.run(xxd_cmd, input=result) print("\n[+] Flipped ciphertext [BASE64]:") print(base64.b64encode(result).decode() + "\033[0m")