Points: 400 Solves: 29 Category: Exploitation Description:
Very interesting and fun challenge, it’s build on the concept of a shadow stack.
A quick look at the functionality, we see it’s pretty simple.
We get to input a name and a message 3 times. Let’s see what we can find underneath the hood :)
This is weird, right ? We are in
main but there’s a function
call that calls
_main ? Well whatever, let’s first see how
_main looks like. Maybe we can just find the vulnerability there and move on.
_main doesn’t have much going on either. It prints the welcome message via
printf and calls
message. So, let’s go see the
So, this is where everything is happening… We get to loop 3 times and input 3 messages with control of the length of the message and optionally change the name. If you haven’t spot the vulnerability by now, it’s the signed check for
msg_len > 0x20. We can supply negative length here and overflow the whole stack frame with anything we want. Because we get to do this 3 times we can easily overwrite the null-byte of the canary on the first loop. This will cause
printf at the end of the loop to leak the canary. On the second loop we can restore the canary and overwrite the saved return pointer and we even get 1 loop to spare, easy 400 pts.
Yes, but not really… You see the call
eax = ret(0x0) before the end of the function ? This is where the original saved return address will be restored from the
"shadow stack" and our return pointer will be overwritten. To see how this works, let’s reverse the
Call, Push, Ret, mprotect ?
From the previous functions we saw that
call gets called with the first argument a potential function to be executed followed by the typical arguments of that function and the assembly shows us just that. So the
push function is called twice with arguments the saved return pointer and saved base pointer of
call. Next, the function pointer is loaded in EAX to be jumped to as we can see in the last instruction. But whats that
ret_stub before that ? And what seems to be, it’s replacing the function pointer from arg 0 ? Yes, but no :P, the
LEAVE instruction will basically do
MOV ESP, EBP ; POP EBP which will restore the stack frame, meaning ESP will point to the return pointer. BUT… there’s
add esp, 4 after the
leave, this is where ESP will no longer point to the saved return pointer but it will point to the first argument which is now a pointer to the
push function is also very interesting… Here we see the
stack_buf global variable as a pointer to the
shadow stack. First the memory’s permissions are changed to
rw then the argument (which if you remember from the
call function is always saved return pointer and saved base pointer) is processed through the
enc_dec function which just XORs it with a futex stored at
gs:0x18 and then moved to the
shadow stack. After that the memory’s permissions are changed back to 0.
ret function is absolutely the same as the
push function, it just instead of storing data it pops data from the
shadow stack restores the saved ebp and jumps to the poped saved return pointer.
Pretty cool implementation right ? So how are we going to pwn it ?
Before jumping directly to the exploit, let’s first see what we can control. We leaked the canary, a saved base pointer providing us with relative offsets to anything on the stack, we control the counter for the for loop and the counter_limit, we also control the
getnline function. So this means we can write anywhere anything.
I didn’t show u the function pointers passed to
call but they are basically pointers from the GOT with FULL RELRO, so GOT overwrite is not an option. However, if we think for a second, the saved return pointer is replaced with the
ret function BEFORE we jump to a function in libc. And when the libc function we called to returns it will pop this value from the stack ! So what if we pre-calculate the address of the saved return pointer for
getnline ? This means read will be overwriting it’s own saved return address and returning to whatever address we place there.
Here is the full exploit code