Description
RSA pop quiz! Answer questions about RSA computations. Connect to the server with nc.
Setup
Connect to the challenge server.
nc <HOST> <PORT_FROM_INSTANCE>Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Understand the quiz format
ObservationThe name and description both say RSA pop quiz, so the server will run multiple rounds of RSA parameter computations. Knowing the five core identities (n, phi, d, encryption, decryption) up front is what makes opening the connection worthwhile.The server asks a series of RSA computation questions. Each question gives you some parameters and asks you to compute a missing value. Questions may include: compute n from p and q, compute d from p, q, e, decrypt c given all key parameters.Learn more
The five RSA identities you must internalize.
n = p * q- the public modulus, product of two distinct large primes.φ(n) = (p-1)*(q-1)- Euler's totient, counts integers in[1, n-1]coprime ton.d = e^(-1) mod φ(n)- private exponent, exists becausegcd(e, φ(n)) = 1; computed by extended Euclidean.c = m^e mod n- encryption.m = c^d mod n- decryption.
Why decryption inverts encryption. By construction
e*d = 1 + k*φ(n)for some integerk. Thenc^d = m^(e*d) = m^(1 + k*φ(n)) = m * (m^φ(n))^k ≡ m * 1^k ≡ m (mod n)by Euler's theorem. The1^ksimplification is what makes it work - it is the entire reason RSA is a scheme rather than just a one-way function.Worked example with tiny numbers. Take
p = 11, q = 13:n = 143, φ = 10*12 = 120, pick e = 7 extgcd(7, 120): 1 = 120 - 17*7 => d = -17 mod 120 = 103 Encrypt m = 42: c = 42^7 mod 143 = 81 Decrypt c = 81: m = 81^103 mod 143 = 42 ✓Variant: Carmichael instead of Euler. Some implementations use
λ(n) = lcm(p-1, q-1)instead ofφ(n). Both work for choosingd, andλgives a slightly smaller (sometimes faster)d. The quiz may accept either, but always teste*d ≡ 1 (mod φ(n))first - that is the canonical relation.Step 2Write a pwntools solver
ObservationThe quiz is timed and runs many rounds. Solving each question by hand is far too slow, so automate the interaction with pwntools and dispatch to the right RSA formula per question type.Automate the quiz with pwntools. Read each question, parse the parameters, compute the answer using sympy or gmpy2, and send it back.pythonpython3 << 'EOF' from pwn import * from sympy import mod_inverse, isprime import re r = remote('<HOST>', <PORT_FROM_INSTANCE>) def solve_rsa(params): p = params.get('p') q = params.get('q') e = params.get('e') c = params.get('c') n = params.get('n') if p and q and not n: return ('n', p * q) if p and q and e and not c: phi = (p-1)*(q-1) d = mod_inverse(e, phi) return ('d', d) if n and e and c and p and q: phi = (p-1)*(q-1) d = mod_inverse(e, phi) m = pow(c, d, n) return ('plaintext', m) return None # Main loop: read question, parse params, compute answer, send r.interactive() EOFWhat didn't work first
Tried: Computing d as pow(e, -1, n) instead of pow(e, -1, phi) and sending that as the private exponent.
The modular inverse has to be taken with respect to phi(n) = (p-1)*(q-1), not n. pow(e, -1, n) returns a different number entirely, one that does not satisfy the e*d relation mod phi, so decryption produces garbage. Use pow(e, -1, (p-1)*(q-1)) or sympy.mod_inverse(e, phi).
Tried: Using gmpy2.invert(e, phi) but forgetting to import gmpy2 and falling back to a hand-rolled extended-gcd that returns a negative value without reducing mod phi.
A naive extended-gcd returns a Bezout coefficient that can be negative, -17 instead of 103 for phi=120, and the server rejects a negative integer. Reduce it: d = d % phi brings any negative result back into the canonical [0, phi-1] range.
Learn more
Extended Euclidean walked by hand. To find
dwithe*d ≡ 1 (mod φ), run forward Euclid then back-substitute. Example withe = 7, φ = 40:Forward: 40 = 5*7 + 5 7 = 1*5 + 2 5 = 2*2 + 1 2 = 2*1 + 0 -> gcd = 1 Back-substitute: 1 = 5 - 2*2 = 5 - 2*(7 - 5) = 3*5 - 2*7 = 3*(40 - 5*7) - 2*7 = 3*40 - 17*7 So -17*7 ≡ 1 (mod 40) d = -17 mod 40 = 23 Verify: 7*23 = 161 = 4*40 + 1 ✓That is exactly what
pow(e, -1, φ)(Python 3.8+) andsympy.mod_inverse(e, φ)compute internally. Both run inO(log min(e, φ)).Square-and-multiply for
pow(c, d, n). Walk the bits ofdfrom MSB to LSB:def modpow(base, exp, mod): result = 1 base = base % mod while exp > 0: if exp & 1: # if low bit of exp is 1 result = (result * base) % mod base = (base * base) % mod # square exp >>= 1 return resultFor 2048-bit
dthat is at most4096multiplies (one square plus optionally one multiply per bit), each on numbers reduced to undern. Without this,c**dwould be a literal number with10^600+ digits and could never fit in any computer's memory.Step 3Answer all questions and get the flag
ObservationInteractive quiz servers on picoCTF hand over the flag only after every round is answered correctly. So once the solver handles all the question types, the flag arrives as the final response.After correctly answering all RSA questions, the server prints the flag.Learn more
This challenge tests understanding of RSA's mathematical structure. Real-world RSA implementations also deal with padding (OAEP, PKCS#1), key serialization (PEM/DER), and constant-time implementation to prevent timing attacks.
Interactive tools
- RSA CalculatorDecrypt RSA ciphertexts, factor n from the sum of primes, or generate key parameters. Handles arbitrarily large BigInt values.
Alternate Solution
Use the RSA Calculator on this site to work through each quiz question manually - enter the given parameters (p, q, e, n, c) and it computes phi, d, and decrypted plaintext so you can verify your automation script produces the correct answers.
Flag
Reveal flag
picoCTF{wA8_th4t$_ill3aGal..ode_...}
Automate RSA computations (n=p*q, d=modinv(e,phi), m=pow(c,d,n)) to answer all quiz questions and receive the flag.