Challenge Setup
A typical RSA challenge gives you some combination of the following:n— the public modulus (product of two primespandq)e— the public exponent (commonly65537, but sometimes3or another small value)c— the ciphertext (an integer:c = m^e mod n)- A
.pempublic key file - Sometimes: multiple
(n, e, c)triples or the encryption script
m (the plaintext message, usually a flag) by finding the private exponent d or by exploiting a structural weakness that lets you bypass the need for d entirely.
Always start by inspecting the numbers. Print the bit length of
n, check whether e is unusually small, and look for any values that appear in more than one set of parameters. These observations take thirty seconds and will immediately rule out most attacks — or confirm the right one.Attack Workflow
1
Inspect the Parameters
Load the key material and check the basics. A 512-bit or smaller modulus is almost certainly factorable. An exponent of
3 opens the door to cube-root attacks. Identical n values across different ciphertexts suggest a common modulus attack.2
Try Factoring the Modulus
Before running any sophisticated attack, check whether Once you have
n is already known to be factored. Submit it to factordb.com — many CTF moduli use pre-generated weak primes that have been catalogued there. If factordb doesn’t have it, try sympy or SageMath for small moduli.p and q, computing the flag is straightforward:3
Choose and Execute an Attack
If the modulus doesn’t factor easily, identify which structural attack applies based on the parameters you have. The tabs below cover each major attack class in detail.
4
Decode the Flag
The recovered plaintext
m is an integer. Convert it to bytes and look for your flag format (e.g., CTF{...}).Attack Types
- Small Exponent (e=3)
- Wiener's Attack
- Common Modulus
- Broadcast Attack
When If the cube root isn’t exact,
e = 3 and the message m is small enough that m^3 < n, the modular reduction never activates — which means c = m^3 exactly, with no modular arithmetic involved. You recover m by taking the integer cube root of c.m^3 wrapped around n. Try the following: for k in a small range, check whether gmpy2.iroot(c + k * n, 3) is exact. This works when padding is minimal.