79 lines
3.0 KiB
Python
79 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
# exploit.py
|
|
# Try date variants and Unit options for the provided OPERATION REPORT template,
|
|
# derive key prefix from c1 and decrypt c2. Look for CTF{...}.
|
|
|
|
import binascii
|
|
import re
|
|
|
|
# Ciphertexts (exact hex strings provided earlier in this conversation)
|
|
C1_HEX = "7a4ca3bb8c3a8b4e2f5b399a1ff9b911691c07ed68e0636c0ca1d10c4786c3ad1880e2675a2c9e260072080afdfc80e93141556487fbf8099c54b971b8f6a5ed62954984d943761f6591888032782a8c1a63826a398200ddebf50ac02dbf6287ef744b1b767e95581f9baa8771626496392757be7df4eb9e633630bcb0b4"
|
|
C2_HEX = "7653a8af842a874f35322a936ffbae16301921dc078d0a097bd8a646048785ac5fd5c53a462b975971704b3de8c7beaf0c5b0463acaaeb228000b01286e1eafd739159d1dd0a770721958483515061f2296f897871c6329d8d9310dc32af27abfb314a1f19"
|
|
|
|
c1 = binascii.unhexlify(C1_HEX)
|
|
c2 = binascii.unhexlify(C2_HEX)
|
|
|
|
# Template and choices
|
|
date_variants = ["14-11-25", "14-11-2025"] # try both dd-mm-yy and dd-mm-yyyy
|
|
units = ["Alpha", "Beta", "Delta"]
|
|
|
|
def make_p1(date_str: str, unit: str) -> bytes:
|
|
"""Construct plaintext candidate for message 1 using the template exactly."""
|
|
s = (
|
|
"OPERATION REPORT\n"
|
|
f"Date: {date_str}\n"
|
|
f"Unit: {unit}\n"
|
|
"Subject: Routine status update\n"
|
|
"Details: All systems operational.\n"
|
|
"End of report.\n"
|
|
)
|
|
return s.encode("utf-8")
|
|
|
|
def derive_key_prefix_from_p1(c1_bytes: bytes, p1_bytes: bytes) -> bytes:
|
|
"""Derive the key prefix by XORing c1 and the candidate p1 bytes where p1 exists."""
|
|
L = min(len(c1_bytes), len(p1_bytes))
|
|
return bytes([c1_bytes[i] ^ p1_bytes[i] for i in range(L)])
|
|
|
|
def decrypt_with_key_prefix(c2_bytes: bytes, key_prefix: bytes) -> str:
|
|
"""Decrypt the prefix of c2 using the derived key prefix, leave rest unknown as '?'."""
|
|
out_chars = []
|
|
for i in range(len(c2_bytes)):
|
|
if i < len(key_prefix):
|
|
out_chars.append(chr(c2_bytes[i] ^ key_prefix[i]))
|
|
else:
|
|
out_chars.append("?")
|
|
return "".join(out_chars)
|
|
|
|
flag_re = re.compile(r"WITCTF\{[A-Za-z0-9_!@#\$%\^&*\-:.?+=/\\]+\}")
|
|
|
|
found = False
|
|
results = []
|
|
|
|
for date_str in date_variants:
|
|
for unit in units:
|
|
p1 = make_p1(date_str, unit)
|
|
# if p1 longer than c1, we can still derive prefix (we will take min inside function)
|
|
key_pref = derive_key_prefix_from_p1(c1, p1)
|
|
dec = decrypt_with_key_prefix(c2, key_pref)
|
|
# Search for FLAG
|
|
m = flag_re.search(dec)
|
|
info = {
|
|
"date": date_str,
|
|
"unit": unit,
|
|
"derived_key_len": len(key_pref),
|
|
"decrypted_preview": dec[:300]
|
|
}
|
|
results.append(info)
|
|
print("-" * 72)
|
|
print(f"Trying Date='{date_str}' Unit='{unit}' (derived key bytes: {len(key_pref)})")
|
|
print("Decrypted preview (unknowns shown as '?'):\n")
|
|
print(dec[:300])
|
|
if m:
|
|
print("\n>>> FLAG FOUND:", m.group(0))
|
|
found = True
|
|
|
|
if not found:
|
|
print("\nNo flag found with the tried date/unit combinations.")
|
|
else:
|
|
print("\nFinished.")
|