- Author: supasuge | supasuge.com
- Category: Crypto
- Difficulty: Medium
“What is magic but mathematics that sleeps?
Wake it up and it becomes cryptanalysis.”
This repository contains a mini CTF-style challenge (src/chal.py) and two solvers (solution/solve.py, solution/solve2.py). The goal is to recover the secret number $\alpha$ that the Magical Oracle multiplies into every query and, with it, decrypt the flag.
Below is a compact but self-contained explanation of the attack in readable Markdown/LaTeX. If you prefer the tl;dr, jump to Usage.
1. Challenge in a nutshell
- A 256-bit prime $p$ is chosen.
- A random secret $\alpha \in \mathbb{Z}_p$ is fixed.
- For each user query the service:
- picks $t \xleftarrow{\$}\mathbb{Z}_p^*$,
- returns one misleading number
$$ z = \mathrm{MSB\_Oracle}(\alpha \,t \bmod p), $$
- allows at most
$$ d = 2\lceil\sqrt{n}\rceil + 3 $$
queries (here $d=35$). - The flag is encrypted with
$$ \text{key} = \mathrm{SHA256}(\,\alpha\,) $$
using AES-CBC and shown to the attacker.
The MSB oracle does not leak the exact most-significant bits; instead it returns a value close to the real product. Internally it draws many random candidates until
$$ |x - z| < \frac{p}{2^{k+1}}, \quad k = \lfloor \sqrt{n}\rfloor + n + 1. $$
Because $k\approx26$ is large, the error is tiny relative to $p$, yielding a Hidden Number Problem (HNP).
2. Modelling as HNP
Each query gives an unknown signed error $e_i$ with
$$ z_i \equiv \alpha\,t_i - e_i \pmod p, \quad |e_i| < \frac{p}{2^{k+1}}. $$
Choosing integer representatives in $(-p/2,p/2)$,
$$ \alpha\,t_i - z_i = e_i \quad(\text{as integers}). $$
So we have $d$ linear equations
$$ \begin{cases} t_1\,\alpha - z_1 = e_1,\\ \;\;\;\vdots\\ t_d\,\alpha - z_d = e_d, \end{cases} $$
with small $e_i$. We build the $(d+1)\times(d+1)$ lattice basis
$$ B = \begin{pmatrix} p & 0 & \cdots & 0 & 0\\ 0 & p & \cdots & 0 & 0\\ \vdots& &\ddots& &\vdots\\ 0 & 0 & \cdots & p & 0\\ t_1 & t_2 & \cdots & t_d & p \end{pmatrix}, $$
and set the target vector
$$ \mathbf y = (z_1,\;z_2,\;\dots,\;z_d,\;0). $$
Since $\mathbf y$ differs from a true lattice point by the error vector, solving the approximate Closest Vector Problem (CVP) against $\mathcal L=\langle B\rangle$ recovers $\alpha$ in the last coordinate.
3. Solving CVP quickly
- LLL-reduce the basis.
- Babai nearest-plane: project the target onto each Gram–Schmidt vector in reverse, round, subtract.
- Read off $\alpha$ from the last coordinate (then reduce $\bmod p$).
Since $36\times36$ LLL+Babai on integers is sub-millisecond, the whole attack is lightning-fast.
4. Implementation highlights
| File | Purpose |
|---|---|
src/chal.py |
the vulnerable oracle & flag encryptor |
solution/solve.py |
original Sage-based solver |
solution/solve2.py |
annotated & slightly cleaner variant |
🚀 Speed tricks
- Pipelined queries: send all
1\nrequests back-to-back to amortize RTT. - Integer lattice: multiply the fractional row by $p$ so LLL works entirely in $\mathbb{Z}$.
- Optional: swap in
fpylllfor a 5–10× speed-up.
5. Usage
# Prereqs (Debian/Ubuntu):
apt-get update && apt-get install -y sage python3-venv
python3 -m venv venv && . venv/bin/activate
pip install -r requirements.txt # Crypto, pwntools, sage-conf, etc.
# Local test — launches challenge and solver
python3 solution/solve2.py
# Remote
python3 solution/solve2.py chall.host 1338
````
**Expected output** (trimmed):
[+] Parameters: p=9…5903, n=256, k=26, d=35
[+] Recovered alpha = 4927…
= FLAG PLAINTEXT =
*Total runtime ≈ 3.6 s (90% spent in the oracle’s artificial 0.1 s delays).*
---
## 6. References
* Adi Shamir, **How to share a secret**, *Communications of the ACM* 1979.
* Oded Regev, lecture notes on lattices & Babai’s nearest-plane (NYU 2004).
* Boneh & Venkatesan, **Breaking RSA given a small fraction of the private key bits**, CRYPTO ’98.
Here’s a cleaned-up `README.md` that should render nicely on GitHub:
# 🧙♂️ Magical Oracle — Write-up
> _“What is magic but mathematics that **sleeps**?
> Wake it up and it becomes cryptanalysis.”_
This repository contains a mini CTF-style challenge (`src/chal.py`) and two solvers (`solution/solve.py`, `solution/solve2.py`). The goal is to recover the secret number $\alpha$ that the **Magical Oracle** multiplies into every query and, with it, decrypt the flag.
Below is a compact but self-contained explanation of the attack in readable Markdown/LaTeX. If you prefer the tl;dr, jump to **Usage**.
---
## 1. Challenge in a nutshell
1. A 256-bit prime $p$ is chosen.
2. A random secret $\alpha \in \mathbb{Z}_p$ is fixed.
3. For each user query the service:
- picks $t \xleftarrow{\$}\mathbb{Z}_p^*$,
- returns one misleading number
$$
z = \mathrm{MSB\_Oracle}(\alpha \,t \bmod p),
$$
- allows at most
$$
d = 2\lceil\sqrt{n}\rceil + 3
$$
queries (here $d=35$).
4. The flag is encrypted with
$$
\text{key} = \mathrm{SHA256}(\,\alpha\,)
$$
using AES-CBC and shown to the attacker.
The MSB oracle does **not** leak the exact most-significant bits; instead it returns a value *close* to the real product. Internally it draws many random candidates until
$$
|x - z| < \frac{p}{2^{k+1}},
\quad
k = \lfloor \sqrt{n}\rfloor + n + 1.
$$
Because $k\approx26$ is large, the error is *tiny* relative to $p$, yielding a Hidden Number Problem (HNP).
---
## 2. Modelling as HNP
Each query gives an unknown signed error $e_i$ with
$$
z_i \equiv \alpha\,t_i - e_i \pmod p,
\quad
|e_i| < \frac{p}{2^{k+1}}.
$$
Choosing integer representatives in $(-p/2,p/2)$,
$$
\alpha\,t_i - z_i = e_i \quad(\text{as integers}).
$$
So we have $d$ linear equations
$$
\begin{cases}
t_1\,\alpha - z_1 = e_1,\\
\;\;\;\vdots\\
t_d\,\alpha - z_d = e_d,
\end{cases}
$$
with small $e_i$. We build the $(d+1)\times(d+1)$ lattice basis
$$
B =
\begin{pmatrix}
p & 0 & \cdots & 0 & 0\\
0 & p & \cdots & 0 & 0\\
\vdots& &\ddots& &\vdots\\
0 & 0 & \cdots & p & 0\\
t_1 & t_2 & \cdots & t_d & p
\end{pmatrix},
$$
and set the target vector
$$
\mathbf y = (z_1,\;z_2,\;\dots,\;z_d,\;0).
$$
Since $\mathbf y$ differs from a true lattice point by the error vector, solving the approximate **Closest Vector Problem** (CVP) against $\mathcal L=\langle B\rangle$ recovers $\alpha$ in the last coordinate.
---
## 3. Solving CVP quickly
1. **LLL-reduce** the basis.
2. **Babai nearest-plane**: project the target onto each Gram–Schmidt vector in reverse, round, subtract.
3. Read off $\alpha$ from the last coordinate (then reduce $\bmod p$).
Since $36\times36$ LLL+Babai on integers is sub-millisecond, the whole attack is lightning-fast.
---
## 4. Implementation highlights
| File | Purpose |
| -------------------- | -------------------------------------- |
| `src/chal.py` | the vulnerable oracle & flag encryptor |
| `solution/solve.py` | original Sage-based solver |
| `solution/solve2.py` | annotated & slightly cleaner variant |
### Speed tricks
- **Pipelined queries**: send all `1\n` requests back-to-back to amortize RTT.
- **Integer lattice**: multiply the fractional row by $p$ so LLL works entirely in $\mathbb{Z}$.
- **Optional**: swap in `fpylll` for a 5–10× speed-up.
---
## 5. Usage
```bash
# Prereqs (Debian/Ubuntu):
apt-get update && apt-get install -y sage python3-venv
python3 -m venv venv && . venv/bin/activate
pip install -r requirements.txt # Crypto, pwntools, sage-conf, etc.
# Local test — launches challenge and solver
python3 solution/solve2.py
# Remote
python3 solution/solve2.py chall.host 1338
````
**Expected output** (trimmed):
[+] Parameters: p=9…5903, n=256, k=26, d=35
[+] Recovered alpha = 4927…
= FLAG PLAINTEXT =
flag{.....}
```
Total runtime ≈ 3.6 s (90% spent in the oracle’s artificial 0.1 s delays).
6. References
- Adi Shamir, How to share a secret, Communications of the ACM 1979.
- Oded Regev, lecture notes on lattices & Babai’s nearest-plane (NYU 2004).
- Boneh & Venkatesan, Breaking RSA given a small fraction of the private key bits, CRYPTO ’98.
- https://github.com/jvdsn/crypto-attacks