Skip to content

Commit

Permalink
[digger] optimize sploit
Browse files Browse the repository at this point in the history
  • Loading branch information
keltecc committed Feb 9, 2024
1 parent 6fcf293 commit 6a65ac7
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 32 deletions.
74 changes: 48 additions & 26 deletions sploits/digger/slide.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import tables


PAIRS_COUNT = (2 ** 16)
# PAIRS_COUNT = (2 ** 17)
PAIRS_COUNT = (2 ** 14)
PAIRS_TRIES = 8

Pair = Tuple[des.Bytes, des.Bytes]
Oracle = Callable[[List[des.Bytes]], List[des.Bytes]]
Expand Down Expand Up @@ -157,46 +157,68 @@ def slide_attack(oracle: Oracle) -> des.Bits:
plaintexts1 = []
plaintexts2 = []

ciphertexts1 = []
ciphertexts2 = []

const_part = b'A' * 4

for i in range(PAIRS_COUNT):
plaintext1 = urandom(4) + const_part
plaintext1 = permutate_bytes(plaintext1, tables.FINAL_PERMUTATION)
plaintexts1.append(plaintext1)
for k in range(PAIRS_TRIES):
print(f'trying {PAIRS_COUNT} blocks more')

plaintext2 = const_part + urandom(4)
plaintext2 = permutate_bytes(plaintext2, tables.FINAL_PERMUTATION)
plaintexts2.append(plaintext2)
plaintexts1_part = []
plaintexts2_part = []

ciphertexts1 = oracle(plaintexts1)
ciphertexts2 = oracle(plaintexts2)
for i in range(PAIRS_COUNT):
plaintext1 = urandom(4) + const_part
plaintext1 = permutate_bytes(plaintext1, tables.FINAL_PERMUTATION)
plaintexts1_part.append(plaintext1)

ciphertexts1 = [
permutate_bytes(ciphertext, tables.INITIAL_PERMUTATION)
for ciphertext in ciphertexts1
]
plaintext2 = const_part + urandom(4)
plaintext2 = permutate_bytes(plaintext2, tables.FINAL_PERMUTATION)
plaintexts2_part.append(plaintext2)

ciphertexts2 = [
permutate_bytes(ciphertext, tables.INITIAL_PERMUTATION)
for ciphertext in ciphertexts2
]
ciphertexts1_part = oracle(plaintexts1_part)
ciphertexts2_part = oracle(plaintexts2_part)

plaintexts2 = [
permutate_bytes(plaintext, tables.INITIAL_PERMUTATION)
for plaintext in plaintexts2
]
ciphertexts1_part = [
permutate_bytes(ciphertext, tables.INITIAL_PERMUTATION)
for ciphertext in ciphertexts1_part
]

ciphertexts2_part = [
permutate_bytes(ciphertext, tables.INITIAL_PERMUTATION)
for ciphertext in ciphertexts2_part
]

plaintexts2_part = [
permutate_bytes(plaintext, tables.INITIAL_PERMUTATION)
for plaintext in plaintexts2_part
]

pairs1 = list(zip(plaintexts1, ciphertexts1))
pairs2 = list(zip(plaintexts2, ciphertexts2))
plaintexts1 += plaintexts1_part
plaintexts2 += plaintexts2_part

return find_round_key(pairs1, pairs2)
ciphertexts1 += ciphertexts1_part
ciphertexts2 += ciphertexts2_part

pairs1 = list(zip(plaintexts1, ciphertexts1))
pairs2 = list(zip(plaintexts2, ciphertexts2))

round_key = find_round_key(pairs1, pairs2)

if round_key is not None:
print(f'found round_key: {round_key}')

return round_key


def recover_possible_keys(vuln_oracle: Oracle, plaintext: des.Bytes, ciphertext: des.Bytes) -> List[bytes]:
round_key = slide_attack(vuln_oracle)
assert round_key is not None, 'slide attack failed'

master_key = bruteforce_master_key(round_key, plaintext, ciphertext)
print(f'master_key: {master_key}')

indices = [i for i in range(len(master_key)) if master_key[i] < 0]

keys = []
Expand Down
31 changes: 25 additions & 6 deletions sploits/digger/sploit.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,51 @@ def attack(client: api.API, username: bytes) -> bytes:
client.encrypt(b'AABB', username)
time.sleep(0.5)

test_ciphertext = client.encrypt(plaintext, username)
assert test_ciphertext != ciphertext, 'cipher is not vulnerable'
response = client.encrypt(plaintext, username)

if response.startswith(b'error'):
return response

assert response != ciphertext, 'cipher is not vulnerable'

oracle_calls = 0
oracle_data = 0

oracle_part_size = 8 * 1024

def vuln_oracle(blocks: List[des.Bytes]) -> List[des.Bytes]:
result = []
nonlocal oracle_calls, oracle_data, oracle_part_size

part_size = 8 * 1024
result = []

for i in range(0, len(blocks), part_size):
part = blocks[i : i + part_size]
for i in range(0, len(blocks), oracle_part_size):
part = blocks[i : i + oracle_part_size]

plaintext = b''.join(part)
ciphertext = client.encrypt(plaintext, username)
new_blocks = [ciphertext[i : i + 8] for i in range(0, len(ciphertext), 8)]

result += new_blocks

print(f'encrypted {i + oracle_part_size} / {len(blocks)}')

oracle_calls += 1
oracle_data += len(plaintext) + len(ciphertext)

return result

keys = slide.recover_possible_keys(vuln_oracle, plaintext, ciphertext)
# print(keys)

print(f'oracle calls: {oracle_calls} by {oracle_part_size / 1024} KB')
print(f'oracle data: {oracle_data / 1024} KB, {oracle_data / 1024 / 1024} MB')

for key in keys:
secret = client.login(username, key)

if not secret.startswith(b'error'):
print(f'found key: {key}')

return secret


Expand Down

0 comments on commit 6a65ac7

Please sign in to comment.