How lucky are you?
Target: 167.99.143.206 65031
Bin: https://dctf.def.camp/dctf-18-quals-81249812/lucky

Let’s look at the file first.

It is an 64-bit ELF shared object which is dynamically linked and stripped.

In order to see how it works, let’s run it.

After asking our name, it expects us to guess the 100 random generated number. Only then, it will give us the flag.

Let’s decompile and analyze its main function.

It first reads a seed value from /dev/urandom and generates a random number. It stores this random number in v35. After that, it reads the user input using std::getline(std::cin, &v27). Since it is a std::string, it first calls c_str() function to get a C string pointer and stores that pointer in v10. Finally, it calls strcpy(&dest, v10) to copy our string to dest. The good thing is that there were no length checks during these operations which means we can overwrite other variables using buffer overflow.

Let’s continue our analysis.

After reading our input and copying it to dest, it calls srand(v35). So, the first random generated number was actually a seed value for further uses. Finally, it generates 100 random numbers using rand() and expect us to guess them correctly.

As we can see, the distance from dest to v35 is 700 bytes which means after 700 characters, the next 4 characters will overwrite the value in v35 which is the seed. Since we can set the seed value as we like, we can guess the numbers that will be generated.

Let’s create a C program that prints 100 random numbers using 0xDEADBEEF as seed value.

Let’s compile and run it to get our expected numbers.

Now, we can create our exploit.

Let’s run it and receive our flag.

Here is our flag DCTF{8adadb46b599a58344559e009bc167da7f0e65e64167c27d3192e8b6df073eaa}.