1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
| from utils import *
from random import randint
from Crypto import Random
from Crypto.Cipher.AES import block_size, key_size
from base64 import b64decode
strings = [
"MDAwMDAwTm93IHRoYXQgdGhlIHBhcnR5IGlzIGp1bXBpbmc=",
"MDAwMDAxV2l0aCB0aGUgYmFzcyBraWNrZWQgaW4gYW5kIHRoZSBWZWdhJ3MgYXJlIHB1bXBpbic=",
"MDAwMDAyUXVpY2sgdG8gdGhlIHBvaW50LCB0byB0aGUgcG9pbnQsIG5vIGZha2luZw==",
"MDAwMDAzQ29va2luZyBNQydzIGxpa2UgYSBwb3VuZCBvZiBiYWNvbg==",
"MDAwMDA0QnVybmluZyAnZW0sIGlmIHlvdSBhaW4ndCBxdWljayBhbmQgbmltYmxl",
"MDAwMDA1SSBnbyBjcmF6eSB3aGVuIEkgaGVhciBhIGN5bWJhbA==",
"MDAwMDA2QW5kIGEgaGlnaCBoYXQgd2l0aCBhIHNvdXBlZCB1cCB0ZW1wbw==",
"MDAwMDA3SSdtIG9uIGEgcm9sbCwgaXQncyB0aW1lIHRvIGdvIHNvbG8=",
"MDAwMDA4b2xsaW4nIGluIG15IGZpdmUgcG9pbnQgb2g=",
"MDAwMDA5aXRoIG15IHJhZy10b3AgZG93biBzbyBteSBoYWlyIGNhbiBibG93",
]
class Oracle:
def __init__(self, possible_inputs):
self.iv = Random.new().read(block_size)
self._key = Random.new().read(key_size[0])
self._possible_inputs = possible_inputs
def get_encrypted_message(self):
chosen_input = self._possible_inputs[randint(0, len(self._possible_inputs) - 1)].encode()
return aes_cbc_encrypt(chosen_input, self._key, self.iv)
def decrypt_and_check_padding(self, ciphertext, iv):
plaintext = aes_cbc_decrypt(ciphertext, self._key, iv, False)
return is_pkcs7_padded(plaintext)
def create_forced_previous_block(iv, guessed_byte, padding_len, found_plaintext):
index_of_forced_char = len(iv) - padding_len
forced_character = iv[index_of_forced_char] ^ guessed_byte ^ padding_len
output = iv[:index_of_forced_char] + bytes([forced_character])
m = 0
for k in range(block_size - padding_len + 1, block_size):
forced_character = iv[k] ^ found_plaintext[m] ^ padding_len
output += bytes([forced_character])
m += 1
return output
def attack_padding_oracle(ciphertext, oracle):
plaintext = b''
ciphertext_blocks = [oracle.iv] + [ciphertext[i:i + block_size] for i in range(0, len(ciphertext), block_size)]
for c in range(1, len(ciphertext_blocks)):
plaintext_block = b''
for i in range(block_size - 1, -1, -1):
padding_len = len(plaintext_block) + 1
possible_last_bytes = []
for j in range(256):
forced_iv = create_forced_previous_block(ciphertext_blocks[c - 1], j, padding_len, plaintext_block)
if oracle.decrypt_and_check_padding(ciphertext_blocks[c], forced_iv) is True:
possible_last_bytes += bytes([j])
if len(possible_last_bytes) != 1:
for byte in possible_last_bytes:
for j in range(256):
forced_iv = create_forced_previous_block(ciphertext_blocks[c - 1], j, padding_len + 1,
bytes([byte]) + plaintext_block)
if oracle.decrypt_and_check_padding(ciphertext_blocks[c], forced_iv) is True:
possible_last_bytes = [byte]
break
plaintext_block = bytes([possible_last_bytes[0]]) + plaintext_block
plaintext += plaintext_block
return pkcs7_unpad(plaintext)
def main():
for string in strings:
oracle = Oracle([string])
result = attack_padding_oracle(oracle.get_encrypted_message(), oracle)
print(b64decode(result.decode()))
if __name__ == '__main__':
main()
|