55 lines
1.6 KiB
Python
55 lines
1.6 KiB
Python
'''
|
|
Solution to https://cryptohack.org/courses/symmetric/flipping_cookie/
|
|
'''
|
|
|
|
import requests
|
|
from datetime import datetime, timedelta
|
|
|
|
URL = 'https://aes.cryptohack.org/flipping_cookie'
|
|
|
|
# NOTE: assumes A and B are equal length
|
|
def xor_bytes(A: bytes, B: bytes) -> bytes:
|
|
return b''.join([(a ^ b).to_bytes() for (a, b) in zip(A, B)])
|
|
def xor_str(A: str, B: str) -> str:
|
|
return ''.join([chr(ord(a) ^ ord(b)) for (a, b) in zip(A, B)])
|
|
|
|
def gen_expiry() -> str:
|
|
return (datetime.today() + timedelta(days=1)).strftime("%s")
|
|
|
|
def get_cookie() -> tuple[bytes, bytes]:
|
|
resp = requests.get(f'{URL}/get_cookie/')
|
|
cookie = resp.json()['cookie']
|
|
iv = bytes.fromhex(cookie[:32])
|
|
ciphertext = bytes.fromhex(cookie[32:])
|
|
return iv, ciphertext
|
|
|
|
|
|
def main() -> None:
|
|
# cookie flipping preprocessing step
|
|
admin_len = len('admin=')
|
|
expiry_len = len(';expiry=') + len(gen_expiry())
|
|
admin_mask = '\x00' * admin_len
|
|
expiry_mask = '\x00' * expiry_len
|
|
# we aim to replace "admin=False;" with "admin=True;;"
|
|
# NOTE: double semicolon ("True;;") is intentional
|
|
# NOTE: and the server won't ever realise it happened!
|
|
deletion = admin_mask + 'False' + expiry_mask
|
|
insertion = admin_mask + 'True;' + expiry_mask
|
|
# determine the value that replaces deletion with insertion
|
|
cookie_flip = xor_str(deletion, insertion)
|
|
|
|
# get our new cookie and apply the cookie flip!
|
|
iv, ciphertext = get_cookie()
|
|
flipped_iv = xor_bytes(cookie_flip.encode(), iv)
|
|
|
|
print('Flipped Cookie:')
|
|
print('IV:', flipped_iv.hex())
|
|
print('Body:', ciphertext.hex())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|