bug fixes for paddingoracle attack
This commit is contained in:
parent
6365e737df
commit
b9c5a5bf3e
3 changed files with 32 additions and 14 deletions
12
crack.py
12
crack.py
|
|
@ -1,7 +1,11 @@
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from imp.constants import PRINTABLE
|
from imp.constants import PRINTABLE
|
||||||
from imp.attacks.paddingoracle import paddingoracle
|
from imp.attacks import paddingoracle
|
||||||
|
|
||||||
|
from Crypto.Util.Padding import pad
|
||||||
|
|
||||||
|
import string
|
||||||
|
|
||||||
NIBBLESET = [n.to_bytes() for n in range(256)]
|
NIBBLESET = [n.to_bytes() for n in range(256)]
|
||||||
|
|
||||||
|
|
@ -9,8 +13,8 @@ HOST = 'https://aes.cryptohack.org'
|
||||||
ENDPOINT = '/ecb_oracle/encrypt/{0}/'
|
ENDPOINT = '/ecb_oracle/encrypt/{0}/'
|
||||||
URI = HOST + ENDPOINT
|
URI = HOST + ENDPOINT
|
||||||
|
|
||||||
# CHARSET = [c.encode() for c in string.printable]
|
CHARSET = [c.encode() for c in string.printable]
|
||||||
CHARSET = NIBBLESET # OVERRIDE
|
# CHARSET = NIBBLESET # OVERRIDE
|
||||||
|
|
||||||
FLAG_LEN = 26 # flag length, calculated by hand
|
FLAG_LEN = 26 # flag length, calculated by hand
|
||||||
SPACER = b'\x0f' # arbitrary spacing character
|
SPACER = b'\x0f' # arbitrary spacing character
|
||||||
|
|
@ -30,7 +34,7 @@ def encrypt(b: bytes) -> bytes:
|
||||||
return bytes.fromhex(resp['ciphertext'])
|
return bytes.fromhex(resp['ciphertext'])
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
paddingoracle(encrypt, NIBBLESET, 64, batch_size=16, debug=True)
|
paddingoracle.crack(encrypt, pad, CHARSET, 64, batch_size=2, debug=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,18 @@ def crack_secret_len(cipher: Callable[[str], str],
|
||||||
i += 1
|
i += 1
|
||||||
return secret_len
|
return secret_len
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
NOTE: pad_if_perfect exists for PKCS#7 which will add a full block
|
||||||
|
NOTE: of padding if the input is perfectly alligned to the blocks already.
|
||||||
|
'''
|
||||||
def crack(cipher: Callable[[str], str],
|
def crack(cipher: Callable[[str], str],
|
||||||
padfn: Callable[[bytes, int], bytes],
|
padfn: Callable[[bytes, int], bytes],
|
||||||
charset: list,
|
charset: list,
|
||||||
block_size: int,
|
block_size: int,
|
||||||
max_secret_iters: int = inf,
|
max_secret_iters: int = inf,
|
||||||
batch_size: int = 1,
|
batch_size: int = 1,
|
||||||
|
pad_if_perfect: bool = True,
|
||||||
debug: bool = False) -> str | None:
|
debug: bool = False) -> str | None:
|
||||||
if len(charset) % batch_size:
|
if len(charset) % batch_size:
|
||||||
raise ValueError(f'batch_size={batch_size} does not divide len(charset)={len(charset)}')
|
raise ValueError(f'batch_size={batch_size} does not divide len(charset)={len(charset)}')
|
||||||
|
|
@ -51,10 +57,12 @@ def crack(cipher: Callable[[str], str],
|
||||||
# the "current tail" is the characters in the same block as the target
|
# the "current tail" is the characters in the same block as the target
|
||||||
full_tail_bytes = len(known) + 1
|
full_tail_bytes = len(known) + 1
|
||||||
tail_bytes = clamp_max(full_tail_bytes, block_size - 1)
|
tail_bytes = clamp_max(full_tail_bytes, block_size - 1)
|
||||||
# generate ALL possible tails
|
# generate ALL possible tails (avoid padding if no padding required)
|
||||||
tails = [padfn(c+known[:tail_bytes], 16) for c in charset]
|
tails = [c + known[:tail_bytes] for c in charset]
|
||||||
|
if len(tails[0]) != block_size:
|
||||||
|
tails = [padfn(tail, 16) for tail in tails]
|
||||||
# calculate the "push" applied to the secret
|
# calculate the "push" applied to the secret
|
||||||
push_size = default_push + tail_bytes
|
push_size = (default_push + full_tail_bytes) % block_size
|
||||||
|
|
||||||
matched = False
|
matched = False
|
||||||
NUM_BATCHES = len(tails) // batch_size
|
NUM_BATCHES = len(tails) // batch_size
|
||||||
|
|
@ -66,24 +74,28 @@ def crack(cipher: Callable[[str], str],
|
||||||
|
|
||||||
# encrypt batch and split the ciphertext into blocks
|
# encrypt batch and split the ciphertext into blocks
|
||||||
ciphertext = cipher(batch)
|
ciphertext = cipher(batch)
|
||||||
index = i*block_size
|
|
||||||
num_blocks = len(ciphertext)//block_size
|
num_blocks = len(ciphertext)//block_size
|
||||||
blocks = [ciphertext[index:index+block_size] for i in range(num_blocks)]
|
blocks = [ciphertext[i*block_size : (i+1)*block_size] for i in range(num_blocks)]
|
||||||
|
|
||||||
oracle_pos = round_to_blocks(full_tail_bytes, block_size)
|
oracle_pos = round_to_blocks(full_tail_bytes, block_size)
|
||||||
print(oracle_pos)
|
if pad_if_perfect and (push_size + secret_len) % block_size == 0:
|
||||||
|
oracle_pos += 1
|
||||||
|
|
||||||
for j, cipher_block in enumerate(blocks[:batch_size]):
|
for j, cipher_block in enumerate(blocks[:batch_size]):
|
||||||
if cipher_block == blocks[-oracle_pos]:
|
if cipher_block == blocks[-oracle_pos]:
|
||||||
char = charset[i*batch_size + j]
|
char = charset[i*batch_size + j]
|
||||||
known = char + known
|
known = char + known
|
||||||
matched = True
|
|
||||||
if debug:
|
if debug:
|
||||||
print(f'[*] Found Tail: {known}')
|
print(f'[*] Found Tail: {known}')
|
||||||
input()
|
matched = True
|
||||||
|
break
|
||||||
|
if matched:
|
||||||
|
break
|
||||||
if not matched:
|
if not matched:
|
||||||
break
|
break
|
||||||
elif len(known) == secret_len:
|
elif len(known) == secret_len:
|
||||||
|
if debug:
|
||||||
|
print('[+] SUCCESS')
|
||||||
return known
|
return known
|
||||||
# if we reached the end (no return)
|
# if we reached the end (no return)
|
||||||
# then the attack failed
|
# then the attack failed
|
||||||
|
|
|
||||||
6
test.py
6
test.py
|
|
@ -11,13 +11,15 @@ KEY = b'you wont get me!'
|
||||||
FLAG = b'imbaud{omg_you_catched_me}'
|
FLAG = b'imbaud{omg_you_catched_me}'
|
||||||
CIPHER = AES.new(KEY, AES.MODE_ECB)
|
CIPHER = AES.new(KEY, AES.MODE_ECB)
|
||||||
|
|
||||||
def encrypt(b: bytes) -> bytes:
|
def encrypt(b: bytes, debug=False) -> bytes:
|
||||||
padded = pad(b + FLAG, 16)
|
padded = pad(b + FLAG, 16)
|
||||||
|
if debug:
|
||||||
|
print(padded)
|
||||||
# print(padded)
|
# print(padded)
|
||||||
return CIPHER.encrypt(padded)
|
return CIPHER.encrypt(padded)
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
paddingoracle.crack(encrypt, pad, CHARSET, 16, batch_size=1, debug=True)
|
paddingoracle.crack(encrypt, pad, CHARSET, 16, batch_size=50, debug=True)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue