Created
March 2, 2021 08:09
-
-
Save nil0x42/8bb48b337d64971fb296b8b9b6e89a0d to your computer and use it in GitHub Desktop.
Simple, easy to understand implementation of Bit-Flipping attack on CBC mode
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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;[email protected]" | |
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") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment