imp/ctf-solutions/flipping_cookie.py

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()