This problem was called seed-sPRiNG and involved guessing random numbers computed by the server each time the binary
is executed.
The challenge value was 350 points and it was solved by 570 teams only.
You can download the original linux executable here.
The Program
This time no source code was given. Because of this, we fired up IDA Pro to reverse engineer the binary file provided. This part was easy as Hex-Rays managed to give some pseudocode. I edited the important variables with meaningful names in the code below:
The program iterates 30 times asking to the user for an ANDed rand() number in each iteration.
Given that the number is ANDed with 0xF, the probability for getting the right number on one attempt is 1/16. During each one of these 30 iterations, the program requests you to guess a new random number and you cannot fail once. In a way, you must be very lucky to guess the right number 30 times in a row, and if you can manage to do
that you should drop everything you are doing inmediatly and run very fast to your nearest Lotto agency.
If you fail to guess the number, then the program exits. Otherwise it continues execution and calls get_flag() which
prints the flag.
The Problem About glibc rand()
The glibc implementation of rand() gives a deterministic list of random numbers depending on the initial
state of the Pseudo Random Number Generator or PRNG which can be configured by passing a integer value to the seed() function.
In this program, the seed value is defined like this:
seed = time(0);
time() when NULL is passed as a parameter, returns the number of seconds since the Epoch. For this, the
seed parameter is an integer which is a timestamp corresponding to the time when the program was executed.
In order to get the list of integers generated by rand() we must sync up our seed with the seed
of the remote server.
Here is a C implementation that returns glibc random numbers with the current timestamp plus a parameter
that allows to adjust it secondswise:
After compiling this program, we have access to the glibc PRNG values for a given timestamp,
and we can use this program to be called by the following python script:
For obtaining the difference in seconds between your host machine and the server, you need to compare the
server time with your own time and calculate the difference.
After obtaining this, you pass the difference as a parameter to solver.py:
And we got our flag: picoCTF{pseudo_random_number_generator_not_so_random_1e980471db65a9f446af481d75490127}