Please wait
Loading the requested page
Loading
Reading the latest public record.
Please wait
Loading the requested page
Reading the latest public record.
PwnSec CTF 2025 / 2025
Writer was too lazy to write a description, so here's this video: https://www.youtube.com/watch?v=lVlgMEFu1PI
We are given a TCP-based challenge running on port 443. There is no web UI, only a raw socket service. Upon connecting, the server prints a banner and then shows this menu:
1) get encrypted flag
2) encrypt your input
3) exit
Option 1 returns:
Option 2 is an encryption oracle, but incorrectly encrypts under p (one of the RSA primes) instead of n, then XORs the result with bytes from a 64-bit LCG keystream.
Initial observations:
RSA(flag) XOR LCG_stream.(m^e mod p) XOR new LCG output.(m^e mod p) can be obtained in the clear, it can be combined with (m^e mod n) to factor n.Sending an empty message to option 2 results in the oracle computing 0^e mod p = 0, so the returned bytes are pure LCG output. From four consecutive 64-bit outputs, the LCG parameters a and c can be solved by exploiting:
x1 = a*x0 + c mod 2^64
x2 = a*x1 + c mod 2^64
Once a and c are known, the LCG state can be rewound to recover the keystream used for the encrypted flag and fast-forwarded for subsequent oracle calls.
For a chosen small plaintext m, we compute:
C_p = m^e mod p (from oracle after XOR removal)C_n = m^e mod n (computed locally)Since p | (C_n - C_p), we compute:
g = gcd(C_n - C_p, n) = p
If gcd fails (returns 1 or n), another plaintext (e.g., 2, 3, 5, 7, 11) is tried.
The solve process:
RSA(flag).C_p by removing the correct keystream.C_n locally.g = gcd(C_n - C_p, n).RSA(flag).The full exploit script used for solving this challenge is included in the same directory as this writeup. The challenge uses a dynamic flag implementation, meaning each instance generates its own flag.
flag{95d02b85d6216ae3}
The full exploit script is included in the same directory as this writeup.
The challenge uses a dynamic flag implementation, so each deployed instance produces a different flag.
The challenge mixes RSA mis-implementation with a reversible XOR-based LCG stream.
The TLS/SNI requirement is necessary to avoid the 400 HTTP frontend.
One empty oracle query completely breaks the LCG.
One correct gcd computation fully factors n.