Google CTF 2024 (I): Blinders
This is yet another edition of Google CTF, where I wrote some crypto challenges with my colleagues. I contributed on three challenges this time, namely, Blinders, ZKPOK and IDEA. There are respectively 56, 3 and 4 solves (out of 267 teams scoring non-zero flags) during the contest period.
Blinders is one of the challenges I coauthored, which introduces a protocol for private set membership.
Challenge Summary⌗
If you are really efficient at guessing which number is missing from {0, 1, …, 255}, I am more than happy to share you the flag!
nc blinders.2024.ctfcompetition.com 1337
Attachments: blinders.zip
This challenge introduces a private set membership protocol called Blinders, which the server has the set $S$. The client wants to privately check whether a given $\text{id}$ is a member of the set $S$.
In the challenge, $S = \{1, 2, …, 256\} \setminus \{x\}$ for a random value $x \in \{1, 2, …, 256\}$. The goal is to find $x$ given two calls to the private set membership protocol… 16 times.
Solution⌗
Two bugs of Blinders⌗
We will cover the two bugs of Blinders that could be chained together in our case.
Since the $\text{eid}_i$’s are not shuffled, we have
$$\text{eid}_i = \begin{cases} \text{H}(i) \cdot k & \text{if} \ i < x, \\ \text{H}(i + 1) \cdot k & \text{otherwise}. \end{cases}$$
🐛 The subset bug. The client can query, not necessarily effectively, if a chosen set $T$ (of $m$ entries) is a subset of $S$.
The client can send $\text{eid} := \sum_{t \in T} \text{H}(t)$ to the server. Then $T \subseteq S$ iff there exists $i_1, i_2, …, i_{m}$ such that $\text{eid}_{i_1} + \text{eid}_{i_2} + … + \text{eid}_{i_m} = \text{deid}$.
Assume that we want to check if $\{2, 3\} \subseteq S$. We can send $\text{eid} := \text{H}(2) + \text{H}(3)$ to the server. The server then responds us with $(\text{eid}_1, \text{eid}_2, …, \text{eid}_n, \text{deid})$. We then can search for $i, j \in \{1, 2, …, 256\}$ such that $\text{eid}_i + \text{eid}_j = \text{deid}$. If such $(i, j)$ exists, we can claim that $\{2, 3\} \subseteq S$.
Recover $x$ with only two calls⌗
We can send $\text{eid} := \text{H}(2) + \text{H}(4) + … + \text{H}(256)$ and $\text{eid}' := \text{H}(1) + \text{H}(3) + … + \text{H}(255)$ to the server. Let $(\text{eid}_1, \text{eid}_2, …, \text{eid}_{255}, \text{deid})$ and $(\text{eid}'_1, \text{eid}'_2, …, \text{eid}'_{255}, \text{deid}')$ be the corresponding responses from the server.
- If $x$ is odd, we have $(\text{eid}_2 + \text{eid}_4 + … + \text{eid}_{x-1}) + (\text{eid}_x + \text{eid}_{x+2} + … + \text{eid}_{255}) = \text{deid}$.
- If $x$ is even, we have $(\text{eid}'_1 + \text{eid}'_3 + … + \text{eid}'_{x-1}) + (\text{eid}'_x + \text{eid}'_{x+2} + … + \text{eid}'_{254}) = \text{deid}'$.
For instance, we can determine if $x = 15$ by checking whether
$$(\text{eid}_2 + \text{eid}_4 + … +\text{eid}_{14}) + (\text{eid}_{15} + \text{eid}_{17} + … + \text{eid}_{255}) = \text{deid}.$$
We can likewise learn if $x = 24$ with
$$(\text{eid}'_1 + \text{eid}'_3 + … + \text{eid}'_{23}) + (\text{eid}'_{24} + \text{eid}'_{26} + … + \text{eid}'_{254}) = \text{deid}'.$$
Therefore we can recover $x$ with two oracle calls. Repeating the progress 16 times, we have the flag: CTF{pr1v4t3_s3t_m3mb3rsh1p_qu3r135_m3d4_m0r3_p0w3rfu1}
.