Crypto categories in CTFs intimidate more newcomers than any other. The barrier isn’t math — it’s pattern recognition. Almost every CTF crypto challenge is a known weakness applied to slightly different parameters.
The First Pass — Identify the Family
When a challenge drops, classify it in under 30 seconds:
| Signal | Likely category |
|---|---|
| Output contains only A-Z and length divisible by 5 | Classical (Caesar, Vigenère, transposition) |
Strings of = padding | Base64 / Base32 / encoding |
c = pow(m, e, n) in source | Textbook RSA |
| Hex strings of length 32 / 64 / 128 | MD5 / SHA-256 / SHA-512 |
AES.new(key, AES.MODE_ECB) | AES ECB block patterns |
xor(plaintext, repeated_key) | XOR-based |
Output looks like noise, source uses os.urandom | Stream cipher or PRNG analysis |
90% of CTF crypto challenges fall into half a dozen categories. Familiarity with each saves hours.
Classical Ciphers
Use dCode or CyberChef automatic decoders first. Custom tooling only when nothing matches.
- Caesar / ROT-N: brute force all 26 keys.
- Vigenère: index of coincidence to find key length, then Kasiski/frequency analysis.
- Transposition: pattern-spot column counts (text length factors).
Textbook RSA — The Pattern Bank
n = 2477... # public modulus
e = 65537
c = 1827... # ciphertext
Run through the checklist:
- Small
n(<1024 bits) → factor with FactorDB,factor, orcado-nfs. - Small
e(e=3) and short message → cube root recovery:m = c ** (1/3). e = 1→ ciphertext is plaintext.pandqclose together → Fermat’s factorization (isqrt(n)+kloop).- Common modulus, two different
e→ use the extended Euclidean algorithm to combine ciphertexts. - Same plaintext encrypted under multiple moduli with small
e→ Håstad’s broadcast attack via CRT. - Partial private key leakage → Coppersmith’s method (SageMath has it built-in).
# Fermat — close p,q
from sympy import isqrt
a = isqrt(n) + 1
while True:
b2 = a*a - n
b = isqrt(b2)
if b*b == b2: break
a += 1
p, q = a-b, a+b
AES Mode Misuse
AES is unbreakable; AES mode usage rarely is.
- ECB — the legendary penguin. Identical plaintext blocks → identical ciphertext blocks. Detect with
len(set(blocks)) < len(blocks). - CBC bit-flipping — XOR the previous ciphertext block to flip bits in the next plaintext block (the canonical “change admin=0 to admin=1” trick).
- CBC padding oracle — when the server tells you whether padding is valid, recover plaintext byte-by-byte. Tooling:
padbuster. - CTR nonce reuse — XOR two ciphertexts under the same nonce → XOR of the plaintexts. Crib-drag to recover.
- GCM nonce reuse — same as CTR, plus you can forge tags.
XOR
# Repeating-key XOR — single-character key
def score(b):
return sum(c in b' etaoinshrdlu' for c in b)
ct = bytes.fromhex(hex_input)
for k in range(256):
pt = bytes(c ^ k for c in ct)
if score(pt) > 50:
print(k, pt)
For longer keys: known-plaintext attacks if you know any portion of the original (e.g., a fixed file header).
Hash & Signature Schemes
- Length-extension (MD5, SHA-1, SHA-256) — when
H(secret || message)is used as a MAC and you know the message + hash, append to it.hashpumpautomates. - Hash collisions — MD5 colliders are commodity. Real challenges use chosen-prefix collisions (e.g.,
hashclash). - ECDSA nonce reuse — two signatures using the same
kreveal the private key. The Sony PS3 break, in CTF form.
Random Number Predictability
- Python’s
randomis a Mersenne Twister. Given 624 consecutive 32-bit outputs, you can reconstruct the entire state and predict all future outputs. - LCGs are trivial to recover from a few outputs.
# Recover Mersenne Twister state
from randcrack import RandCrack
rc = RandCrack()
for v in outputs[:624]:
rc.submit(v)
predicted = rc.predict_getrandbits(32)
Lattice Problems
When the challenge involves “I added a small error to…” or modular constraints, lattice reduction is often the answer. LLL via SageMath solves a surprising fraction of crypto challenges in one line. Worth knowing exists even if you never write the matrix yourself.
A Solver’s Toolkit
- SageMath — the swiss army knife. RSA, ECC, lattices, Galois fields.
- CyberChef — for encoding/decoding chains.
- OpenSSL CLI —
openssl rsautl,openssl enc. - pwntools — networking + automation around oracle servers.
- gmpy2 / sympy — Python big-integer math.
References
- CryptoHack — best learning path
- CTF Field Guide — Cryptography
- Cryptopals — the canonical exercise set
