323 words
2 minutes
CodeVinci CTF 2026 - lottery - Cryptography Writeup

Category: Cryptography Flag: CodeVinci{https://arxiv.org/abs/2307.12430_player_b7a01e0bffd28575}

Challenge Description#

I swear that LLMs are not yet LUDOPATICI enough to solve this challenge

Analysis#

The remote service immediately told us this was a strict combinatorial input checker: V=19, ticket size K=3, pair coverage target T=2, and at most 58 tickets. That means the goal is to submit triples over 0..18 so every pair appears at least once.

nc lottery.codevinci.it 9975
--- LOTTERY ---
V=19, K=3, T=2
Max tickets: 58
Enter your tickets as a JSON list.

Checking the provided local script showed an intentional trap: local success prints a deterministic placeholder flag with not_real_flag_..., so a locally accepted solution is necessary but not sufficient for the real flag.

rg -n "not_real_flag" lottery.py
16:    return f"CodeVinci{{not_real_flag_{h}}}"

That was a pretty classic troll moment because the first valid local output looks like a real flag but is guaranteed fake.

tableflip

The clean way to solve it is to build a Steiner Triple System on 19 points, which should use 57 triples and perfectly cover all pairs. A cyclic construction works with base blocks (0,1,4), (0,2,9), (0,5,11), then developing each block by adding t mod 19 for t=0..18. This is elegant because 3 base blocks generate exactly 3*19 = 57 tickets and naturally satisfy the pair-coverage constraint.

wink

Submitting that JSON list to the remote endpoint returns a valid solution and the real CodeVinci{...} flag.

python solve.py | nc lottery.codevinci.it 9975
--- LOTTERY ---
V=19, K=3, T=2
Max tickets: 58
Enter your tickets as a JSON list.
Valid solution.
FLAG: CodeVinci{https://arxiv.org/abs/2307.12430_player_b7a01e0bffd28575}

Solution#

# solve.py
import json

V = 19
bases = [(0, 1, 4), (0, 2, 9), (0, 5, 11)]

tickets = []
for a, b, c in bases:
    for t in range(V):
        tickets.append(sorted([(a + t) % V, (b + t) % V, (c + t) % V]))

# Canonicalize and deduplicate
tickets = sorted({tuple(x) for x in tickets})

print(json.dumps([list(x) for x in tickets]))
python solve.py | nc lottery.codevinci.it 9975
--- LOTTERY ---
V=19, K=3, T=2
Max tickets: 58
Enter your tickets as a JSON list.
Valid solution.
FLAG: CodeVinci{https://arxiv.org/abs/2307.12430_player_b7a01e0bffd28575}
CodeVinci CTF 2026 - lottery - Cryptography Writeup
https://blog.rei.my.id/posts/80/codevinci-ctf-2026-lottery-cryptography-writeup/
Author
Reidho Satria
Published at
2026-03-10
License
CC BY-NC-SA 4.0