Export-grade
Export-grade
Platform: CUSTOM | Category: Crypto | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: cipher_suite_downgrade, mitm_negotiation_rewrite, pohlig_hellman, small_dlp
Summary
Walkthrough of the CUSTOM Crypto Export-grade. Task: MITM a DH cipher-suite negotiation (socket.cryptohack.org 13379) where Alice offers groups from DH1536 down to DH64, then passively observe. Solution: rewrite the negotiation so Bob accepts the
Description
"Alice and Bob are using legacy codebases and need to negotiate parameters they both support. You've man-in-the-middled this negotiation step, and can passively observe thereafter. How are you going to ruin their day this time?" Connect at
socket.cryptohack.org 13379.
Alice and Bob first negotiate a DH group from a supported list, then perform the key exchange and send the AES-CBC encrypted flag (key = sha1(str(shared)).digest()[:16]). We sit in the middle for the negotiation and can rewrite messages, then can only observe.
Recon / Analysis
Alice advertises a list of cipher suites / groups, strongest first:
supported = ["DH1536", "DH1024", "DH512", "DH256", "DH128", "DH64"]
This is the classic Logjam-style export-grade downgrade. Because we control the negotiation, we rewrite Bob's view so that the agreed group is the weakest one, DH64 — a Diffie-Hellman group with a 64-bit prime modulus. A 64-bit discrete log is trivially solvable (Pohlig-Hellman / BSGS / sympy.discrete_log in well under a second), so once we passively capture the public values we recover the private exponent and the shared secret.
Solution
- MITM the negotiation: intercept Alice's offered list and reply to Bob so that the chosen group is forced to
DH64. After agreement, switch to passive observation. - Capture the agreed
p(64-bit),g, Alice'sA = g^a mod p, and Bob'sB = g^b mod p. - Solve the small DLP:
a = dlog_g(A) mod pwithsympy.discrete_log(Pohlig-Hellman under the hood). - Shared secret & decrypt:
shared = B^a mod p, then AES-CBC.
python read-only • copy allowedimport json from hashlib import sha1 from sympy.ntheory.residue_ntheory import discrete_log from Crypto.Cipher import AES from Crypto.Util.Padding import unpad # After forcing DH64 in the negotiation and observing the exchange: # p, g, A, B (p is a 64-bit prime), iv, encrypted_flag a = discrete_log(p, A, g) # 64-bit DLP -> instant (Pohlig-Hellman) shared = pow(B, a, p) # = g^(a*b) mod p key = sha1(str(shared).encode()).digest()[:16] pt = AES.new(key, AES.MODE_CBC, bytes.fromhex(iv)).decrypt(bytes.fromhex(encrypted_flag)) print(unpad(pt, 16).decode())
crypto{REDACTED}
Takeaways
- Downgrade attacks are devastating when the negotiation step is unauthenticated: a MITM forces the weakest mutually-supported group, regardless of how strong the parties' real preferences are. This is exactly the real-world Logjam attack against export-grade DH.
- A 64-bit DH prime gives a 64-bit discrete log, solvable instantly with
sympy.discrete_log/ Pohlig-Hellman; froma = dlog_g(A)recovershared = B^a mod p. - Defense: authenticate the negotiation (sign the transcript) and refuse weak/export-grade groups entirely.
- Recognize it by: an MITM-able cipher-suite/group negotiation that includes a tiny group (
DH64,DH128) in the supported list, followed by a normal DH exchange.
Key Takeaways / Lessons
- Mastering cipher_suite_downgrade, mitm_negotiation_rewrite, pohlig_hellman, small_dlp was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-06-22 • CUSTOM • Export-grade • Difficulty: Medium