Welcome back to another PWN CTF, this time we will be looking on how to solve the exploitation challenge from the Hackerolympiad Thomas More & NVISO.
link to the binary: https://github.com/ctfs/write-ups-2017/tree/master/belgian-hackerolympiad-2017/exploitation/luigi
First, let's try to execute it in order to get the big picture of the program workflow
before executing the program, we need the binary to be executable by using chmod utility
~# chmod +x challenge
uh-oh! it seems we missing something that leads to a segmentation fault, we need to gain more understand to find out what we need to supply along the binary so it won't crash at the next execution. We can use Ghidra to help us with this task. It helps us to analyze the binary in detail manner by providing the pseudocode of the program
After ghidra finish load the binary, go to the main function and take a look at the disassembler window that contains the main function source code. One of the functions that catch my eyes is the read_flag function and when we try to go to the function we can see it needs to load flag.txt file
from this simple check, we can conclude that we need to create a fake flag.txt in our directory so the program will run as the way it supposed to be.
Once the fake flag.txt is created. Try to execute it again and as you can see it's not crash
next, we need to fuzz the program to trigger a buffer overflow, we can do this supplying a really long string of pattern.
But after a couple of trial and error by supplying a longer string in every iteration it seems the result is not what we expected. Let's go back again to ghidra to study the main function one more time.
The first section of the code is responsible to take the input from the user and each one of our input will be passed to read_string() function. The function itself requires two parameters first is the local variable that will hold our input and the second will be the limit on how long the string will be stored into the stack.
the second section of the code is responsible to get the flag.txt content and stored into the local variable.
the third section is responsible to compare the input for username if its match with string admin and input for the password is matched with string get from the "flag.txt"
In terms of memory management the program doing all of it correctly so that's why we don't get buffer overflow vulnerability.
after a couple of minutes of debugging the binary and examine the stack in every function call I found out that we were looking at the wrong place, it turns out we can get the content of the flag by exploiting the printf that located at the end of the main function.
Let me explain why
we will put three breakpoints into this address, each of the addresses is responsible to call read_string and read_flag that will process our input respectively.
by putting a breakpoint into there address we can examine how the program stores our input and processed it in real-time.
The first input we supply for the username is just "AAAA", we hit the breakpoint and when we examine the stack we can see that our input is stored at 0x7fffffffd950
The second input we supply for the password is just "BBBBBBB", we hit the breakpoint again and as you can see it start storing the string at 0x7fffffffd910
and at the last breakpoint, the flag is stored at address 0x7fffffffd990 so it is adjacent to the first input.
as you remember from our last analysis from the source code if the username is not matched with the string admin it will notify that the string we just input is wrong.
The program will take the value stored in 0x7fffffffd950 (which contains contain the username input) and output the content through print function.
So what is the problem here?
as you know printf will stop printing the value if its hit "\x00" at the memory and since the username input and the flag location is adjacent all we need to do is to fill enough memory (which is 0x40) until it reaches 0x7fffffffd950, like this
since we provide the wrong value to the program, the printf function will just spit out everything from 0x7fffffffd950 until it's found "\x00" and because the "\x00" is not available before the flag, this will eventually continue to dump the value of the flag
That's all folks, hope you enjoy it :)
Comments
Post a Comment