For this challenge we’re told an application is running on a server and given a binary that outputs the following:
Checking for buffer overflow…
On break/step, peda gives us detailed colored output of registers, the block of code, and the stack. We can see that it segfaults on
mov ebp, DWORD PTR [ecx], and that peda says
ECX: 0x41484441 ("ADHA"), or ECX contains part of our buffer at this line.
We now know buff needs to be a pointer to valid memory, and it is loaded into EBP. We chose a random zeroed spot in the .data segment, found by scrolling through IDA. We’ll use this address,
0x80EE46C, wherever we need this kind of pointer. It’s simple to hex edit this address into our buffer and run it through gdb again. Here’s the abbreviated output:
It crashed at a new spot! This is good, as we know our last buffer patch fixed the first crash. From this we can say that buff needs to be a pointer to writable memory minus 4. We stick
0x80EE468 into the buffer at this position, and run the program.
From the line above, we can see that ECX needs to be an index of an array pointed to be EDX. Some math tells us EDX is 0x1114d9d9 – (0×42417541 * 4), which is 0x80f04d5. We can use PEDA to inspect this pointer:
So, we know EDX is controlled by buff, and ECX just modifies EDX. We want to find what ECX’s offset is, which should be the pattern “AuAB.” Using
pattern offset, PEDA tells us this is not found. At this point I opened the binary in IDA and reversed how it loaded “AuAB” into ECX. There’s a pointer above where our current crash is, and the references to that pointer show that the value of the first character was incremented by one. Doing a pattern offset on “BuAB” tells us buff-1 is the value loaded into ECX.
Let’s return to the equation we were looking at:
[edx+ecx*4]. We can store 1 into ecx via buff to zero out the right term, and we can set EDX to whatever we like via buff, for this example we’ll use our standard write address
0x80EE468. After this last update to the buffer file, gdb will tell us the program received SIGILL(illegal instruction) at
0x80EE470! This means our last update took over EIP(the instruction pointer) and caused it to execute the code at wherever buff was telling it to.
We now control EIP. The above command, “pattern search,” tells us where and how much of our input is stored in memory. Let’s tell EIP to go to that location, and we can replace the data at that location with shellcode(being careful not to overwrite any of our magic buffer positions). To do this, we set buff to
0x80f0340. We modified this shellcode to connect back to our IP, and stuck it in the buffer at the beginning. On our host, we run netcat on the port specified in the shellcode listening for a connection.
nc -l -p 45295 -vv
Running the program with our buffer one last time reveals that buff is written to EBP, and causes it to segfault when a
ret tries to use the garbage value stored there. EBP is the base pointer to the stack frame, so let’s make it our standard accessible memory pointer. We set buff to
0x80EE468 and run the program again. Looking back at our host, we see a connection!
All that’s left is to send this to the server they said is running the binary. We do a simple
nc host -p port < inputbuffer, and we see a connection back on our host. Doing a cat on the file “key” gives us the flag.