keyboard_arrow_up

title: Seed
date: Nov 09, 2021
tags: Writeups DamCTF Reverse


Seed

342 solves / 249 points

Having a non-weak seed when generating "random" numbers is super important! Can you figure out what is wrong with this PRNG implementation?

seed.py is the Python script used to generate the flag for this challenge. log.txt is the output from the script when the flag was generated.

What is the flag?

Author: m0x



For this challenge, we had to brute force a Pseudo Random Number Generator (PRGN) hashing algorithm used to generate a flag that must match a specific pattern with the following script:

#!/usr/bin/env python3
import sys
import time
import random
import hashlib

def seed():
    return round(time.time())

def hash(text):
    return hashlib.sha256(str(text).encode()).hexdigest()

def main():
    while True:
        s = seed()
        random.seed(s, version=2)

        x = random.random()
        flag = hash(x)

        if 'b9ff3ebf' in flag:
            with open("./flag", "w") as f:
                f.write(f"dam{{{flag}}}")
            f.close()
            break

        print(f"Incorrect: {x}")
    print("Good job <3")

if __name__ == "__main__":
    sys.exit(main())


Before attacking, we need to know how to exploit PRGN. After seeding a random generator, it will always generate random number in the same order. For example:

import random

random.seed(99999, version=2)
for i in range(3):
    print(random.random())

First output:
0.12049047611259744
0.3092850036925837
0.9529198903583602

Second output:
0.12049047611259744
0.3092850036925837
0.9529198903583602

As you can see, both issues are the same.


If we come back to the script, we can see that seed function is initialized using timestamps. So, trying all timestamp of 2021 for example, using the same algorithm must give us the flag!

Script:

import random
import hashlib
import time

# 2021 year timestamp
timestamp = 1609459200

# Loop tour equal to second number in a year
for i in range(32140800):
    timestamp += 1
    random.seed(timestamp, version=2)

    x = random.random()
    flag = hashlib.sha256(str(x).encode()).hexdigest()

    if 'b9ff3ebf' in flag:
        print(f"Timestamp: {timestamp}")
        print(f"dam{{{flag}}}")
        break


And we got it! ??

Timestamp: 1634187287
Flag: dam{f6f73f022249b67e0ff840c8635d95812bbb5437170464863eda8ba2b9ff3ebf}


Fun fact: By making a mistake in my script, I found a timestamp that matches flag condition 👀

Timestamp: 149919217148325
Flag: dam{d73fd97d6a496b146eed6b4efa237176193a324767f6669cb9ff3ebf86045ed1}