SnykCon CTF 2021 — Random Flag Generator

OTR
4 min readOct 12, 2021

--

Observations

This challenge gives us two files: generate.py and log.txt. Here is the code for generate.py

generate.py source code

And here is the output of log.txt.

log.txt output

By looking at the code, we can see that the flag is generated by creating a random sha256 hash, then checked if it contains the string “5bc” and finally written out to the flag file. However, if the hash does not contain the string “5bc”, the code repeats itself in an infinite loop generating hashes until it finally generates one with “5bc” in it.

For the failed cases where hashes do not have “5bc”, a log message is written out to log.txt (as we saw above). This log message contains the values of the random numbers used in the code, which is represented as a double (i.e. 0.3719072557403058)

Additionally, the name of the challenge suggests that this should be a crypto challenge, particularly attacking the random number generation.

Vulnerability

After looking at the code and the hint in the name of the challenge I decided to look at how the hashes were being generated since the hash is what’s used as the flag.

What immediately popped out to me was the use of time.time() as the seed for the random number generator. This is not a secure method of generating a seed, especially if the randomness needs to be cryptographically secure (CSPRNG).

Tl;dr — Random number generators work with an internal state that allows them to generate a new random number on every invocation. The very first number that starts this state is called a seed. Having a predictable seed means you know the internal state of the random number generator — meaning you can then determine all of the future outputs of the random number generator.

For more information on secure randomness please visit this article from OWASP

Because the code uses an insecure seed, we as an attacker can predict the output of the random number generator! Once we know the seed for the random number generator, we can therefore generate the hash used for the flag!

Note: What makes this particularly easy for us as attackers is that we also have the output of the failed random numbers used to generate the sha256 hash. Without this log file, this challenge would have been almost impossible to solve. You’ll see why in a second why the log file is important.

Attack

Now that we know the vulnerability, it’s time to attack the hash generation algorithm and retrieve the flag!

If we look at the log.txt file, we’ll notice there are several log lines. This tells us that the code must have run several iterations before finding a hash that contains “5bc”. Knowing this, we can assume that the first log entry contains the initial random number 0.3719072557403058.

With this information, if we can guess the seed, we can compare the first call to random.random() to see if it’s equal to the first log line 0.3719072557403058. If they are equal, then we know we have guessed the correct seed. But how do we guess the seed?

To guess the seed we can look at time.time(). This function returns the current epoch time, which is then used as the seed. Since epoch time is incremental, all we need to do is start with the current time, then subtract one.

So the logic goes like this:

  • Get current time in epoch and use it as the seed for random.
  • Generate a random number and check to see if it’s equal to 0.3719072557403058.
  • If the numbers do not match, repeat the loop but subtract 1 from the epoch time and use it as the seed for random.
  • Generate a random number again and check to see if it’s equal to 0.3719072557403058.

This process repeats until a match is found. You can see this in the code I wrote to solve this challenge below.

solve.py source code
solve.py source code

After finding the correct seed 1624176198 we can see the outputs are the same. Knowing the seed, we can use it to set the internal state of therandom object then proceed to follow the hash generating algorithm to derive the flag!

Output of solve.py
Output of solve.py

Flag: SNYK{53811586115bc8d9aed9fe1a84e9f2caeb71dea19fd63f68bad2a1a1d7196d46}

--

--

OTR

Offensive security engineer who streams CTFs on https://www.twitch.tv/its_otr and speaks on https://twitter.com/its_otr. I sometimes do bug bounties.