There’s not really much I can say about this challenge… The bytes speak for themselves. Good luck!!!

nc 4008


Let’s look at the file information first.

It is a dynamically linked ELF 64-bit executable. Now, let’s look at its protections before we actually start.

The stack is not executable.

Let’s decompile its main function to understand the executable.

It actually allows us to select the file descriptor parameter for the following read function call. We can simply send 0 as the file descriptor to make it read input from stdin.

Since it reads up to 0x1860 bytes and the buffer is located at bp-9h, there is a buffer overflow issue where we can overwrite the return address after 17 bytes of padding.

In order to be able to call execve(“/bin/sh”, NULL, NULL), we need to set rdi to the address of a “/bin/sh” string and clear both rsi and rdx registers. Luckily, the binary already contains the “/bin/sh” string so that we don’t need to inject it.

As you can see above, the manifesto string in rodata ends with “/bin//sh” which is perfect for us.

Let’s use ROPgadget to locate the address of “/bin//sh”.

Now, we know its address.

Let’s set a breakpoint on the return instruction in main to see the registers’ values.

Now, we are ready to search for gadgets in the file.

Unfortunately, I could only find one useful gadget to modify rdx:

Since r14 and r15 are already zero, this gadget actually clears rdx and rsi for us. If we look at the register values, we see that rdi is already zero. Thus, we can use r13 to set a 32-bit address to rdi. We will use it to assign “/bin//sh” string’s address to rdi. Also, notice that rbx was already zero which means we can call arbitrary functions by controlling r12.

I have found the following gadget to modify r12 and r13:

However, we need a pointer of an address to assign to r12. I found the following string in the binary to overcome this issue:

This string is actually used by get_int function which calls __isoc99_scanf to read an integer. We can simply use this to write an address to somewhere in the .data section or in the .bss section.

As you can see above, the address 0x602000 is writable. We need to set rdi to format string and set rsi to our buffer. We can use the following gadgets for this purpose:

The only thing left is to find a way to set rax to 59. However, I couldn’t find any gadget for this purpose, but we know that get_int reads an integer from stdin and returns it. Therefore, we can call it to modify rax.

Here is the exploit:

Let’s run it and get the flag.

The flag is flag{sr0p_is_fir3.||—————————–();<>{}[]–0081734012870871238471632974132074}