-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchallenge_13.py
64 lines (45 loc) · 1.69 KB
/
challenge_13.py
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
from Crypto.Cipher import AES
from os import urandom
from challenge_09 import pkcs7, strip_pkcs7
KEY_SIZE = 32
_key = urandom(KEY_SIZE)
def profile_parse(profile: bytes) -> dict[bytes, bytes]:
kv_pairs = profile.split(b"&")
parsed = {
key: value for key, value in [pair.split(b"=") for pair in kv_pairs]
}
return parsed
def profile_build(t: tuple[tuple[bytes, bytes], ...]) -> bytes:
result = b'&'.join(key + b'=' + val for key, val in t)
return result
def profile_for(email: bytes) -> bytes:
# note: I'm opting not to do any email validation beyond rejecting profile
# metacharacters here (so like, no RFC 5322 stuff)
email = email.translate(None, b'&=') # remove & and = characters
result = profile_build((
(b'email', email),
(b'uid', b'10'),
(b'role', b'user')
))
return result
def enc_profile(email: bytes) -> bytes:
cipher = AES.new(_key, AES.MODE_ECB)
profile = profile_for(email)
return cipher.encrypt(pkcs7(profile))
def dec_profile(encrypted: bytes) -> bytes:
cipher = AES.new(_key, AES.MODE_ECB)
plaintext = strip_pkcs7(cipher.decrypt(encrypted))
return plaintext
def do_evil() -> bytes:
# generate a ciphertext for an admin profile
user_1 = b'foooo@bar.com'
user_2 = user_1[:10] + pkcs7(b'admin') + user_1[10:] # include parts of user_1 so it looks at least a _little_ like an email
print(f"{user_1=}\n{user_2=}")
ct_1 = enc_profile(user_1)
ct_2 = enc_profile(user_2)
return ct_1[:32] + ct_2[16:32]
if __name__ == "__main__":
evil = do_evil()
print("Malicious ciphertext:", evil)
print("Decryption:", dec_profile(evil))
profile = dec_profile(evil)