← Back to Writeups
CUSTOMMediumForensics

Secure Random (Безопасный рандом)

XESXOR9/2/20263 min read
#forensics#custom#medium#timestamp_bruteforce#prng_seed_recovery#xor_decryption

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 data
  • cypher.py — encryption script

Step 2: Analyzing the Encryption Script

python
import 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:

  1. The seed is fully predictable if the approximate encryption time is known
  2. Knowing the seed, we can reproduce the same sequence of pseudo-random bytes
  3. 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
#!/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

  1. Use cryptographically secure PRNGs: secrets module in Python or /dev/urandom
  2. Never use predictable seeds: time, PID, etc.
  3. Use proven encryption algorithms: AES, ChaCha20 instead of simple XOR ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
python
# Correct approach:
import secrets
random_bytes = secrets.token_bytes(len(data))

References