(English) UTCTF 2026 - Cryptography [Fortune Teller | Oblivious Error | Smooth Criminal]
My write-up for the Verilicious medium crypto challenge, where I analyzed information leaks in PKCS#1 v1.5 padding, translated the samples into a Hidden Number Problem (HNP) instance, and leveraged that to successfully recover the flag m
Fortune Teller
This challenge shows us the working of a Linear Congruential Generator (LCG) and exactly why it isnβt secure for cryptography. It is one of the oldest and most widely used algorithms for generating pseudorandom numbers.
File lcg.txt:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
We're using a Linear Congruential Generator (LCG) defined as:
x_(n+1) = (a * x_n + c) % m
where m = 4294967296 (2^32), and a and c are secret.
We intercepted the first 4 outputs of the generator:
output_1 = 4176616824
output_2 = 2681459949
output_3 = 1541137174
output_4 = 3272915523
The flag was encrypted by XORing it with output_5 (used as a 4-byte repeating key).
ciphertext (hex) = 3cff226828ec3f743bb820352aff1b7021b81b623cff31767ad428672ef6
Solution
Before solving this problem, one needs only a basic understanding of group theory, particularly multiplicative inverses. In modular arithmetic modulo $m$, the inverse of an integer $p$ is an integer $q$ such that $pq \equiv 1 \pmod m$. With this concept, the analysis reduces to modular manipulations that allow recovery of $a$ and $c$.
The LCG algorithm operates based on a single calculation:
\[X_{n+1} = (a \cdot X_n + c)\ (\mathrm{mod}\ m)\]Now that we have $a$, recovering $c$ is trivial.
\[c \equiv x_2 - a \cdot x_1 \pmod m\]You might have noticed that we needed only 3 outputs to recover $a$ and $c$.
Exploitation script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
m = 4294967296
x = [4176616824, 2681459949, 1541137174, 3272915523]
ct = bytes.fromhex("3cff226828ec3f743bb820352aff1b7021b81b623cff31767ad428672ef6") #ciphertext = ct
d1 = (x[1] - x[0]) % m
d2 = (x[2] - x[1]) % m
a = (d2 *pow(d1,-1,m)) % m
c = (x[1] - a * x[0]) % m
x5 = (a * x[3] + c) % m
print(xor(ct, x5.to_bytes(4, 'big')))
Flag
1
utflag{pr3d1ct_th3_futur3_lcg}
Oblivious Error
Smooth Criminal
This challenge is based on the Discrete Logarithm Problem (DLP). To approach it, the key idea is to determine the exponent $a$ from the relation
\[g^a \equiv h \quad (\mathrm{mod}\ p).\]Thus, the main task is to transform the given data into this form and then apply an appropriate method to solve for $a$.
File dlp.txt:
1
2
3
4
5
6
7
8
9
The flag has been encoded as a secret exponent x, where:
h = g^x mod p
Your job: find x. Convert it from integer to bytes to get the flag.
p = 1363402168895933073124331075716158793413739602475544713040662303260999503992311247861095036060712607168809958344896622485452229880797791800555191761456659256252204001928525518751268009081850267001
g = 223
h = 1009660566883490917987475170194560289062628664411983200474597006489640893063715494610197294704009188265361176318190659133132869144519884282668828418392494875096149757008157476595873791868761173517
Solution
