Guess a random number to win the flag lottery. The server generates the winning number using a seeded PRNG.
Vulnerability
The server seeds the random number generator with the current Unix timestamp, which is predictable. Additionally, Python 2 and Python 3 have different PRNG implementations and string conversion behaviors.
Solution
The server code is vulnerable because:
- Predictable seed: Unix timestamp is public knowledge
- Time window: Even if time is slightly off, we can try nearby timestamps
- Version differences: Python 2’s
str()truncates floats, making predictions consistent
Use Python 2 to generate predictions for timestamps around the server’s current time:
import subprocessimport timefrom pwn import *
host = "13721472f3c35e88.247ctf.com"port = 50316context.log_level = "error"
# Try timestamps within a ±10 second windowfor offset in range(0, 10): r = remote(host, port) prompt = r.recvline()
target_time = int(time.time()) + offset
# Generate number using Python 2 seeding cmd = ["python2", "get_legacy_random.py", str(target_time)] payload = subprocess.check_output(cmd).decode().strip()
print(f"[*] Predicting for time {target_time} (offset +{offset}s): {payload}")
r.sendline(payload.encode()) response = r.recvall().decode()
if "247" in response: print(f"[SUCCESS] {response.strip()}") r.interactive() break else: print(f"[-] Failed: {response.strip()}") r.close()Helper script (get_legacy_random.py), specifically for Python 2 syntax; it is not Python 3 source. The server-side generator and Python 2 runtime are unavailable, so neither prediction equality nor the timing window has been reproduced:
import randomimport sys
target_time = int(sys.argv[1])secret = random.Random()secret.seed(target_time)print str(secret.random())Key Insight
PRNGs seeded with time are not cryptographically secure. Use secrets or os.urandom() for security-sensitive randomness. Additionally, always be aware of version-specific differences in language implementations when predicting values.
The returned flag belongs to the launched service instance; no cross-instance invariance is established. Record the generation/retrieval method and use the current instance response instead of a fixed-answer spoiler.