Securinets Friendly CTF 2026 / Misc WRITEUP
UNIX
Two codes are already on the screen. Predict the next one, Professor Probability. Go on. The machine could use a laugh.
Walkthrough
Player-facing content
The player receives only the remote endpoint. There are no downloadable files, technical clues, or hints. The service prints two six-digit verification codes and accepts one prediction for the next code.
The public description is intentionally sarcastic:
Two codes are already on the screen. Predict the next one, Professor Probability.
>
Go on. The machine could use a laugh.
Construction
Each connection creates an independent Python random.Random instance seeded with int(time.time()). It draws exactly three values using randint(100000, 999999), discloses the first two, and checks the player's input against the third.
The seed has one-second granularity. A solver records its local time when it connects and tests nearby timestamps. For each candidate it reproduces the first two calls. Matching both visible codes identifies the seed with overwhelming confidence, after which the third call predicts the required answer.
The weakness is the predictable seed, not a statistical defect in the displayed six-digit values. Two outputs are exposed so the correct nearby timestamp can be identified without ambiguity.
Intended solution
- Connect and record the two displayed codes.
- Enumerate Unix timestamps near the connection time.
- For each timestamp, create
random.Random(timestamp). - Reproduce two
randint(100000, 999999)calls. - When both values match, generate the third value and submit it.
The included organizer solver uses a ten-minute window to tolerate clock skew and manual delays.
Reference solver
The reference solver supplied with the writeup:
#!/usr/bin/env python3
import random
import re
import socket
import sys
import time
host = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
port = int(sys.argv[2]) if len(sys.argv) > 2 else 20046
connection_time = int(time.time())
connection = socket.create_connection((host, port), timeout=10)
banner = b""
while b"> " not in banner:
chunk = connection.recv(4096)
if not chunk:
raise SystemExit("The service disconnected before sending its codes.")
banner += chunk
visible_codes = re.findall(rb"(?m)^(\d{6})\r?$", banner)
if len(visible_codes) != 2:
raise SystemExit("Could not find the two verification codes.")
first_code = int(visible_codes[0])
second_code = int(visible_codes[1])
current_time = int(time.time())
prediction = None
recovered_seed = None
for seed in range(connection_time - 600, current_time + 6):
rng = random.Random(seed)
if rng.randint(100000, 999999) != first_code:
continue
if rng.randint(100000, 999999) != second_code:
continue
recovered_seed = seed
prediction = rng.randint(100000, 999999)
break
if prediction is None:
raise SystemExit("No matching seed was found.")
print(f"seed: {recovered_seed}")
print(f"next code: {prediction:06d}")
connection.sendall(f"{prediction:06d}\n".encode())
response = b""
while True:
chunk = connection.recv(4096)
if not chunk:
break
response += chunk
connection.close()
print(response.decode(), end="")Flag
Securinets{y0u_c4nt_h1d3_th3_s33d_fr0m_t1m3}