371 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 = 01FE01FE01FE01FEk3 = 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 python3
from pwn import remote
from Crypto.Cipher import DES
from Crypto.Util.Padding import unpad
from 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://blog.rei.my.id/posts/40/bitsctf-2026-super-des-cryptography-writeup/