Misc - Not really random

495 points | 25 solves

Description

Do you really think random numbers generated by computers are random?

Downloads

Solution

We are given 2 files:

  1. rand.py

import random 
import time 
import hashlib

seed = round(time.time())

random.seed(seed, version=2)

while True:
    rand = random.random()
    has = hashlib.sha256(str(rand).encode()).hexdigest()
    flag = f"CTF{{{has}}}"
    if "7a2" in has:
        with open("./flag", "w") as f:
            f.write(flag)
            break
    else:
        print(f"Bad random value: {rand}")

2. log.txt

Bad random value: 0.33567959567961436
Bad random value: 0.8913897703358419
...
Bad random value: 0.5905894610211082
Bad random value: 0.09018146469820387
Flag created 🎉

The weakness in the randomization is in line 5 of the rand.py script. According to documentations,

When the seed is a floating point number, it would be very difficult to guess which seed results in the random value in log.txt. However in this case, because the seed is rounded to an integer, brute-forcing becomes viable.

First I converted the random values in log.txt into a python list using Sublime so that the script will be able to compare and know when the brute-forced seed is correct.

target = [0.33567959567961436, 0.8913897703358419, 0.3032054069265432, 0.6860829464688437, 0.2658087107328536, 0.8903005048882441, 0.914630909612433, 0.9688578899818961, 0.7925090397955323, 0.10136501216336935, 0.568451491382639, 0.16898065821921437, 0.5541712073794856, 0.029926361216790154, 0.18218590474521223, 0.49713845657579536, 0.7631162105077507, 0.7386939443532723, 0.5815609491717452, 0.5905894610211082, 0.09018146469820387]

Using seed = round(time.time()), I get the seed at the current time so that I know the last number to brute-force and the number was 1646540228 when I wrote the script. The starting seed should be a feasible number and in my case, I used 1646430228. If the number is too small the brute-force will take forever while if the number is too big, you risk missing the number (now to think about it I should probably have brute-forced it in the reverse direction.)

import random 
import time 
import hashlib
import tqdm

#seed = round(time.time())

for seed in tqdm.tqdm(range(1646430228, 1646540228)):
    random.seed(seed, version=2)

    target = [0.33567959567961436, 0.8913897703358419, 0.3032054069265432, 0.6860829464688437, 0.2658087107328536, 0.8903005048882441, 0.914630909612433, 0.9688578899818961, 0.7925090397955323, 0.10136501216336935, 0.568451491382639, 0.16898065821921437, 0.5541712073794856, 0.029926361216790154, 0.18218590474521223, 0.49713845657579536, 0.7631162105077507, 0.7386939443532723, 0.5815609491717452, 0.5905894610211082, 0.09018146469820387]
    br_array = []

    while True:
        rand = random.random()
        has = hashlib.sha256(str(rand).encode()).hexdigest()
        flag = f"CTF{{{has}}}"
        if "7a2" in has:
            with open("flag.txt", "w") as f:
                f.write(flag)
                break
        else:
            br_array.append(rand)

    if (br_array == target):
        print("Seed found: " + str(seed))
        print(flag)
        exit()

Flag: CTF{a13a806d175841731b24a01e9af240bc81750967542550a4b3bb77a29a9d291b}

Last updated