2026-07-12 20:22:15 +01:00

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.")