372 words
2 minutes
BITSCTF 2026 - Super DES - Cryptography Writeup
Category: Cryptography
Flag: BITSCTF{5up3r_d35_1z_n07_53cur3}
Challenge Description
Given server.py. Remote: nc 20.193.149.152 1340. Description: “I heard triple des is deprecated, so I made my own.”
The server generates random k1 at startup, then lets us choose k2 and k3:
def triple_des_ultra_secure_v1(pt, k2, k3): return E_k1(E_k2(E_k3(pad(pt))))
def triple_des_ultra_secure_v2(pt, k2, k3): return D_k1(E_k2(E_k3(pad(pt))))(k2 == k3 is blocked, but k2 != k3 is allowed.)
Analysis
DES has semi-weak key pairs such that for specific distinct key pairs. One valid pair:
-
k2 = 01FE01FE01FE01FE -
k3 = FE01FE01FE01FE01
So in ultra_secure_v1:
Solution
Use semi-weak pair to collapse encryption to . Then for arbitrary k2, k3, if we pick plaintext so that , querying ultra_secure_v2 gives .
The practical caveat: we must brute-force random (k2,k3) until has valid PKCS#7 structure.
File used: solve_super_des.py
# !/usr/bin/env python3from pwn import remotefrom Crypto.Cipher import DESfrom Crypto.Util.Padding import unpadfrom Crypto.Random import get_random_bytes
HOST, PORT = "20.193.149.152", 1340
def adjust_key(key8: bytes) -> bytes: out = bytearray() for b in key8: b7 = b & 0xFE ones = bin(b7).count("1") out.append(b7 | (ones % 2 == 0)) return bytes(out)
def wait_k2_prompt(io): io.recvuntil(b"enter k2 hex bytes >")
def query(io, k2: bytes, k3: bytes, option: int, mode: int, pt_hex: str | None = None) -> bytes: wait_k2_prompt(io) io.sendline(k2.hex().encode()) io.recvuntil(b"enter k3 hex bytes >") io.sendline(k3.hex().encode())
io.recvuntil(b"enter option >") io.sendline(str(option).encode())
io.recvuntil(b"enter option >") io.sendline(str(mode).encode())
if mode == 2: io.recvuntil(b"enter hex bytes >") io.sendline(pt_hex.encode())
line = io.recvline_contains(b"ciphertext") return bytes.fromhex(line.decode().split(":", 1)[1].strip())
def main(): io = remote(HOST, PORT)
# Step 1: semi-weak pair so E_k2(E_k3(x)) = x k2w = bytes.fromhex("01FE01FE01FE01FE") k3w = bytes.fromhex("FE01FE01FE01FE01")
# Cflag = E_k1(pad(flag)) cflag = query(io, k2w, k3w, option=2, mode=1) print(f"[+] Cflag ({len(cflag)} bytes): {cflag.hex()}")
# Step 2: find k2,k3 where D_k3(D_k2(cflag)) is valid PKCS#7 attempts = 0 while True: attempts += 1 k2 = adjust_key(get_random_bytes(8)) k3 = adjust_key(get_random_bytes(8)) if k2 == k3: continue
pre = DES.new(k3, DES.MODE_ECB).decrypt(DES.new(k2, DES.MODE_ECB).decrypt(cflag)) try: chosen_pt = unpad(pre, 8) except ValueError: continue
print(f"[+] Found valid candidate after {attempts} attempts")
# Step 3: v2 returns pad(flag) out = query(io, k2, k3, option=3, mode=2, pt_hex=chosen_pt.hex()) flag = unpad(out, 8) print(f"[+] Flag bytes: {flag}") print(f"[+] Flag: {flag.decode()}") break
io.close()
if __name__ == "__main__": main()Run:
python3 solve_super_des.pyOutput:
[+] Cflag (40 bytes): 72922fe6db8bbc21825f1f3a5a9d336e82ef77555946655ed1529579670aab074df19b7d7a35e007[+] Found valid candidate after 6 attempts[+] Flag bytes: b'BITSCTF{5up3r_d35_1z_n07_53cur3}'[+] Flag: BITSCTF{5up3r_d35_1z_n07_53cur3} BITSCTF 2026 - Super DES - Cryptography Writeup
https://fuwari.vercel.app/posts/40/bitsctf-2026-super-des-cryptography-writeup/