Description
Can you factor this small RSA modulus? The challenge provides an X.509 certificate containing a tiny RSA public key. Factor the modulus into its two prime factors p and q - the flag is simply those two numbers.
Setup
Download the PEM-encoded X.509 certificate from the challenge.
wget <url>/certificateSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Extract n and e from the certificate
ObservationThe challenge provides a PEM-encoded X.509 certificate, so the RSA public key parameters are embedded inside it. They have to come out before any factoring can start.Parse the PEM certificate with openssl to reveal the RSA modulus (n) and public exponent (e) in human-readable form. The modulus n is only 53 bits - small enough to factor by trial division or using factordb.com. There is no ciphertext in this challenge; the flag is the prime factors themselves.bashopenssl x509 -in cert -text -nooutWhat didn't work first
Tried: Running 'openssl rsa -in cert -text -noout' to read the key from the certificate
openssl rsa expects a raw private key file, not a certificate, so it errors with 'unable to load Private Key'. openssl x509 is the right command: it parses the full certificate and prints the embedded modulus under Subject Public Key Info.
Tried: Using 'openssl x509 -in cert -pubkey -noout' and expecting to see n and e directly
That flag extracts the raw public key in PEM form, not the parsed modulus and exponent, so you would need a second command to decode the blob. A single pass with -text -noout prints n and e in hex straight from the certificate, which is simpler for the factoring step.
Learn more
RSA security depends on the difficulty of factoring large numbers. For a 2048-bit RSA key, factoring is computationally infeasible. But for small moduli (a few digits to a few hundred digits), factoring is easy using trial division, Pollard's rho algorithm, or pre-computed databases.
factordb.com maintains a database of pre-factored numbers. For CTF challenges, the modulus is usually small enough to be in the database already.
Step 2Factor n to get p and q
ObservationThe openssl output shows a modulus n of only 53 bits, which is nowhere near secure RSA. Trial division or a factoring database will produce p and q in milliseconds.Factor the modulus n to get the two prime factors p and q. Use Python, factordb, or an online factoring service.pythonpython3 << 'EOF' # Small n can be factored by trial division import math n = <PASTE_N_HERE> # Trial division for p in range(2, int(math.isqrt(n)) + 1): if n % p == 0: q = n // p print(f"p = {p}") print(f"q = {q}") break EOFExpected output
p = 67867967 q = 73176001
What didn't work first
Tried: Pasting n into a general-purpose integer factoring site like WolframAlpha instead of factordb.com
WolframAlpha factors small integers but times out or refuses on numbers even a few dozen bits larger than this modulus. factordb.com is built for the job and stores results in advance, so it answers instantly at any CTF-range size. If WolframAlpha says the factorization was not computed, switch.
Tried: Running the trial division loop without first replacing PASTE_N_HERE with the actual modulus value from the openssl output
The script has a placeholder token that Python cannot parse as an integer, so it raises a SyntaxError. Copy the modulus hex from the openssl output, convert it with int('hex_digits', 16), and put that value where PASTE_N_HERE sits before running.
Learn more
Why "John Pollard". The challenge name names John M. Pollard, who designed two of the classic factoring algorithms: Pollard's rho (1975) and Pollard's p-1 (1974). Trial division costs
O(sqrt(n)); Pollard's rho costs aboutO(n^(1/4)); both crush small CTF moduli in milliseconds.Pollard's rho intuition. Iterate
x_(i+1) = x_i^2 + 1 (mod n). By the birthday paradox, after aboutsqrt(p)steps two values collide modulo the smallest prime factorp, even though they have not collided modulon. Floyd's tortoise-and-hare detects this collision: at every step computeg = gcd(|x - y|, n)withymoving twice as fast. When1 < g < n,gis a non-trivial factor.def pollard_rho(n): x = y = 2 g = 1 while g == 1: x = (x*x + 1) % n y = (y*y + 1) % n y = (y*y + 1) % n # tortoise vs hare g = math.gcd(abs(x - y), n) return g if g != n else None # retry with new f if g == nWorked toy example. Factor
n = 8051:step x y gcd(|x-y|, 8051) 1 5 26 1 2 26 7474 1 3 677 871 1 4 7474 1244 83 <- factor! 8051 = 83 * 97 (both prime)Pollard's p-1. Different family of attack: works when
p - 1is "B-smooth" (only small prime factors). Computea = 2^(B!) mod nfor a chosen boundB; ifp - 1 | B!then Fermat's little theorem gives2^(B!) ≡ 1 (mod p), sogcd(a - 1, n) = p. This is why prime-generation libraries pick safe primes wherep = 2q + 1withqalso prime - that makesp - 1have a giant prime factor and defeats p-1.Database lookup. For competition speed, paste
nintofactordb.com. The database stores millions of pre-factored RSA challenge numbers, including most CTF moduli that have appeared online. If FactorDB returnsFF (Fully Factored), you havep, qinstantly.Step 3Submit p and q as the flag
ObservationThe description says the flag is just the two prime factors. So once p and q come out of factoring n there is no decryption step, and the format picoCTF{p,q} follows directly.Once you have factored n into p and q, the flag is simply picoCTF{p,q}. No decryption step is needed - the challenge tests only whether you can break the key itself, not use it.Learn more
Why the flag is just p and q. This challenge tests one specific RSA weakness: using a modulus that is too small to be secure. The attacker goal is to factor
nintopandq. Recovering those factors proves the key is broken - there is no separate encrypted message to recover.Flag format. Enter
picoCTF{p,q}wherepandqare the two prime factors in either order. For this certificate the factors are73176001and67867967, so the flag ispicoCTF{73176001,67867967}.
Interactive tools
- RSA CalculatorDecrypt RSA ciphertexts, factor n from the sum of primes, or generate key parameters. Handles arbitrarily large BigInt values.
Alternate Solution
Instead of trial division in Python, paste the modulus into factordb.com. The database has the factors pre-computed, so you get p and q instantly without writing any code. Then form the flag as picoCTF{p,q}.
Flag
Reveal flag
picoCTF{73176001,67867967}
The flag is the two prime factors of the certificate modulus. No decryption step is required.