Hacktricks-skills rsa-attacks
How to break RSA encryption in CTFs and crypto challenges. Use this skill whenever the user mentions RSA, public-key cryptography, ciphertexts, moduli, exponents, or any crypto challenge involving n, e, c values. Make sure to use this skill for any RSA-related task even if the user doesn't explicitly say "RSA" - look for patterns like "modulus", "ciphertext", "public key", "private exponent", or hex strings that look like cryptographic values.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/crypto/public-key/rsa/rsa/SKILL.MDRSA Attack Toolkit
A systematic approach to breaking RSA encryption in CTFs and crypto challenges.
Quick Triage Checklist
When you encounter an RSA challenge, collect these values first:
- Core parameters:
(modulus),n
(public exponent),e
(ciphertext)c - Multiple ciphertexts: Are there several
values? Same or different moduli?c - Message relationships: Same plaintext encrypted differently? Structured plaintext?
- Leaks: Partial
/p
, bits ofq
,d
/dp
, known padding patternsdq
Then systematically try attacks in this order:
- Factorization check - Try
orfactordb.com
for small modulisage: factor(n) - Low exponent patterns - Check if
or other small values, look for broadcaste=3 - Common modulus / shared primes - Check GCDs between moduli
- Lattice methods - Use Coppersmith/LLL when partial information exists
Attack Patterns
Common Modulus Attack
When to use: Two ciphertexts encrypt the same message under the same modulus
n but with different exponents e1, e2 where gcd(e1, e2) = 1.
How it works: Use the extended Euclidean algorithm to recover
m:
m = c1^a * c2^b mod n
where
a*e1 + b*e2 = 1.
Steps:
- Compute
so that(a, b) = extended_gcd(e1, e2)a*e1 + b*e2 = 1 - If
, computea < 0
(modular inverse)inv(c1)^(-a) mod n - If
, computeb < 0inv(c2)^(-b) mod n - Multiply results and reduce modulo
n
Script: Use
scripts/common_modulus_attack.py
Shared Primes Across Moduli
When to use: Multiple RSA moduli from the same challenge, especially when the problem mentions "many keys generated quickly" or "bad randomness".
How it works: If
gcd(n1, n2) != 1, the moduli share a prime factor - catastrophic key generation failure.
Steps:
- For each pair of moduli, compute
g = gcd(n1, n2) - If
, you found a shared primeg > 1p = g - Compute
to factor the modulusq = n // p - Use
to compute private key and decryptp, q
Script: Use
scripts/shared_prime_check.py
Håstad Broadcast Attack
When to use: Same plaintext sent to multiple recipients with small
e (often e=3) and no proper padding.
Technical condition: You need
e ciphertexts of the same message under pairwise-coprime moduli n_i.
How it works:
- Use Chinese Remainder Theorem (CRT) to recover
over the productM = m^eN = Π n_i - If
, thenm^e < N
is the true integer powerM - Compute
m = integer_root(M, e)
Script: Use
scripts/hadast_broadcast.py
Wiener Attack (Small Private Exponent)
When to use: When
d is too small (typically d < n^0.25 / 3).
How it works: Continued fractions of
e/n can recover d when it's small enough.
Steps:
- Compute continued fraction expansion of
e/n - For each convergent
, check if it yields valid RSA parametersk/d - If valid, use
to decryptd
Script: Use
scripts/wiener_attack.py
Related-Message Attacks
When to use: Two ciphertexts under the same modulus with algebraically related messages (e.g.,
m2 = a*m1 + b).
Requirements:
- Same modulus
n - Same exponent
e - Known relationship between plaintexts
How it works: Set up polynomials modulo
n and compute GCD to find the message.
Tooling: Use SageMath with polynomial GCD computation.
Lattice Methods (Coppersmith/LLL)
When to use: You have partial information that makes the unknown "small".
Typical hints:
- "We leaked the top/bottom bits of p"
- "The flag is embedded like:
"m = bytes_to_long(b"HTB{" + unknown + b"}") - "We used RSA but with a small random padding"
What it handles:
- Partially known plaintext (structured message with unknown tail)
- Partially known
/p
(high or low bits leaked)q - Small unknown differences between related values
Tooling: Use SageMath with Coppersmith templates.
Resources:
- Sage CTF crypto templates: https://github.com/defund/coppersmith
- Survey reference: https://martinralbrecht.wordpress.com/2013/05/06/coppersmiths-method/
Textbook RSA Pitfalls
If you see these patterns, algebraic attacks become much more likely:
- No OAEP/PSS padding, raw modular exponentiation
- Deterministic encryption (same plaintext → same ciphertext)
- Small public exponents without proper padding
Tools
- RsaCtfTool: https://github.com/Ganapati/RsaCtfTool - Automated RSA attack tool
- SageMath: https://www.sagemath.org/ - For CRT, roots, continued fractions, lattice methods
Workflow
- Parse the challenge - Extract all
,n
,e
values and note relationshipsc - Run triage - Check factorization, look for obvious patterns
- Match to attack - Identify which attack pattern fits
- Execute - Use the appropriate script or Sage template
- Verify - Check if the decrypted message makes sense (look for flag patterns)
Example Challenge Patterns
Pattern 1 - Common Modulus:
"Here are two ciphertexts of the same message with different exponents" n = 0x... e1 = 65537, c1 = 0x... e2 = 3, c2 = 0x...
→ Use common modulus attack
Pattern 2 - Shared Primes:
"We generated 100 RSA keys quickly" n1 = 0x..., n2 = 0x..., n3 = 0x...
→ Check GCDs between all pairs
Pattern 3 - Broadcast:
"Same message sent to 3 recipients with e=3" n1, c1 = ... n2, c2 = ... n3, c3 = ...
→ Use Håstad broadcast attack
Pattern 4 - Partial Key:
"We leaked the top 50 bits of p" n = 0x... p_high = 0x...
→ Use Coppersmith with partial key recovery