Bad Timing binary exploitation challenge


Musyoka Ian
7 min readSep 25, 2022

Hello guys back again with another walkthrough. This time am going to be showing how I tackled a binary called bad_timing. It was sent over by a friend who just asked me to analyze and exploit any bug I could find. My initial thought was that I was supposed to exploit a buffer overflow but after doing a bit of reverse engineering I discovered that the weakness the binary had was in a function that is initialized with some random value (called the seed), in other words it’s a PRNG attack on a binary. The vulnerability in the binary that we are going to analyze arises from the fact that the seed used is predictable meaning if we know the exact seed used we can predict the random number and solve the challenge. We will also end up creating a small c program used to generate the random number. Without much say let’s jump in.

First I downloaded the binary to my box and ran a file command

We notice that it’s a 64 bit binary and the fact that it’s not stripped makes it easy to reverse engineer, debug and even analyze with tools like gdb.

First I tried to see if there was a way I could solve the challenge dynamically by using tools like ltrace and gdb. According to my opinion it’s always easier to solve CTF challenges with dynamic analysis instead of going through each line of code. Unless it’s absolutely necessary I always begin with dynamic analysis. Dynamic analysis entails running the program though a debugger (gdb of course is my favorite ) and using breakpoint and passing input see how the program responds. The program am running in my current context is a binary I trust if you have any doubts on a binary you are analyzing it’s always recommended that you run it in an isolated sandboxed environment like a VM.

First i executed the binary without a debugger just to see what happens

Looking at the screenshot above the application asks me to enter some characters using stdin and compares it to some value in registers and if they match i should probably get correct instead of wrong.

Given the binary we are analyzing has debugging symbols present(not stripped) I just decide to run it in gdb debugger using the command

gdb ./bad_timing

In my instance I have gef installed since it makes the debugging process much simpler

First thing i added was a breakpoint in main. This will be the place where the program will pause before continuing

Then ran the program. When it reached the main function it stopped.

Next I disassembled main function of the program and the cmp call looked interesting given the fact that it comes after a scanf() function (our user input).

I decided to create a second breakpoint at that specific memory address

Then continued through the execution of the program.

Looking at the screenshot below we have hit the breakpoint again

Now am interested in the values stored in those registers because they might be the correct input that we can supply to solve the challenge

We can see the string QUUO from rbp-0x18 being moved to eax then eax being compared to rbp-0x14. But after several attempts of trying to get the value I noticed that the value always changes. Meaning I had to go back and reverse engineer the binary to see where the randomness was coming from. For static analysis I use cutter. Ghidra also works really well just that am a fan of cutter. I open cutter application on my kali box

And loaded the binary for analysis

Looking at the main function we can see a stack canary or stack cookie being initialized. This is just a protection that binaries have to prevent buffer overflows

After that we see some function that lets us believe that we are looking at the PRNG generator because of the srand()

Now we understand why we were getting different strings when we executed the binary and looked at the compare call. It because the values are generated at runtime and initialized by a specific seed. Our goal is to pass the if statement check and execute the win function

Looking at the win function we can see that all it does is call system and reads the flag from the file system.

Going back to the main function we have to pin point where the vulnerability is and find a way to exploit the vulnerability to read the flag. After reading about how PRNG works i discovered that the vulnerability exists in how the the seed value is initialized

seed = time(0);

Using this method to generate a seed makes it possible to predict the value of the random number that will be generated

I went online and googled

time(0) c++ prng exploit

Which lead me to a stack overflow page that explain the weakness of generating random numbers this way

Here is the link if you want to check out the full discussion link

But basically time(0) gives the time in seconds since the Unix epoch, which is a pretty good "unpredictable" seed (unpredictable in quotes means in some instances the number generated can be predicted). This means if i know the exact time (in epoch format) when binary was started I can predict the random number that is being generated.

So we need to start the binary at a specific time and record the epoch time which will be used to guess the random number. Linux has a way of generating the epoch time using the following command

date +'%s'

This lead me to create a small binary that will always predict the correct input required

All I have to replace is the epoch timestamp. If you look at the code I wrote and the one in main function it pretty identical because I always believe it’s easier to mimic an exploit in a language that it was written in.

Next step is to start the binary while recording the epoch time

The binary has been started and the epoch timestamp has also been recorded. Sweet. Let’s replace the epoch timestamp in out binary and compile the exploit

And execute the exploit

Looking at the screenshot below we get the random number generated is 50. Let’s try to use this in our challenge binary and see if it’s the correct one

Looking at the screenshot below we see that this worked perfectly !!

We’ve managed to guess the random number successfully and the binary is trying to read the flag but given that we haven’t created one the binary errors out. But we have completed the challenge successfully. Hope you enjoyed the walkthrough if so clap for me down below and follow me so that you won’t miss any upcoming walkthrough