Secure Random (Безопасный рандом)
Secure Random (Безопасный рандом)
Platform: HackerLab | Category: Forensics | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-01-05 | Status: Solved Techniques: timestamp_bruteforce, prng_seed_recovery, xor_decryption
Summary
Files: secure_random.zip
Secure Random (Безопасный рандом) — HackerLab
Description
Расшифруй, если конечно сможешь =D (Decrypt it, if you can =D)
Files: secure_random.zip
Analysis
Step 1: Extracting Files
The ZIP archive contained a nested archive with two files inside:
data.enc(25 bytes) — encrypted datacypher.py— encryption script
Step 2: Analyzing the Encryption Script
python read-only • copy allowedimport random import time random.seed(int(time.time())) FLAG = b"CODEBY{?????????????????}" random = random.randbytes(len(FLAG)) enc = bytes(i ^ j for i, j in zip(FLAG, random)) with open("data.enc", "wb") as f: f.write(enc)
Step 3: Identified Vulnerability
Critical flaw: The script uses random.seed(int(time.time())) — the PRNG seed is based on the Unix timestamp at the moment of encryption.
This means:
- The seed is fully predictable if the approximate encryption time is known
- Knowing the seed, we can reproduce the same sequence of pseudo-random bytes
- XOR is reversible:
plaintext = ciphertext XOR random_bytes
Step 4: Obtaining the Timestamp
From the ZIP archive metadata: the file was created on June 30, 2022 at 21:40:10.
Considering possible timezone differences, we need to bruteforce timestamps in a ±12 hour range from this time.
Solution
python read-only • copy allowed#!/usr/bin/env python3 """ HackerLab - Secure Random (Безопасный рандом) Timestamp-based PRNG seed bruteforce """ import random from datetime import datetime import calendar # Read encrypted data with open("data.enc", "rb") as f: enc = f.read() print(f"[*] Encrypted data length: {len(enc)} bytes") print(f"[*] Encrypted data (hex): {enc.hex()}") # Base time from ZIP metadata base_time = datetime(2022, 6, 30, 21, 40, 10) base_ts = int(calendar.timegm(base_time.timetuple())) print(f"[*] Base timestamp: {base_ts}") print(f"[*] Bruteforcing timestamps +-12 hours...") # Bruteforce timestamps in +-12 hour range (43200 seconds) for offset in range(-43200, 43200): ts = base_ts + offset # Initialize PRNG with the same seed random.seed(ts) # Generate the same "random" bytes rand_bytes = random.randbytes(len(enc)) # XOR to decrypt decrypted = bytes(i ^ j for i, j in zip(enc, rand_bytes)) # Check flag format if decrypted.startswith(b"CODEBY{") and decrypted.endswith(b"}"): try: flag = decrypted.decode('ascii') print(f"\n[+] SUCCESS!") print(f"[+] Timestamp: {ts}") print(f"[+] DateTime: {datetime.utcfromtimestamp(ts)} UTC") print(f"[+] Offset from base: {offset} seconds") print(f"[+] FLAG: {flag}") break except UnicodeDecodeError: pass print("\n[*] Done")
Execution Result
[*] Encrypted data length: 25 bytes
[*] Base timestamp: 1656625210
[*] Bruteforcing timestamps +-12 hours...
[+] SUCCESS!
[+] Timestamp: 1656589211
[+] DateTime: 2022-06-30 11:40:11 UTC
[+] Offset from base: -35999 seconds
[+] FLAG: CODEBY{REDACTED}
[*] Done
Interesting Fact
The flag REDACTED ("back to the future") is a hint to the solution: you need to "go back in time" to find the correct timestamp seed!
Defense Against Such Attacks
- Use cryptographically secure PRNGs:
secretsmodule in Python or/dev/urandom - Never use predictable seeds: time, PID, etc.
- Use proven encryption algorithms: AES, ChaCha20 instead of simple XOR
python read-only • copy allowed# Correct approach: import secrets random_bytes = secrets.token_bytes(len(data))
References
- Python random module documentation
- Mersenne Twister PRNG
- CWE-330: Use of Insufficiently Random Values