WARMING UP on STACK - Part II
Last time we worked on the first three levels of the WARMING UP on STACK section of gera's exploit challenge, today we'll clear the remaining two. Both will be covered as a single solution since they only differ in the output message after succeeding. As we mentioned, the path to the solution is a little bit different than the other levels. Last time all we had to do is overflow our buffer until we reached the cookie value. This time rather than changing a local variable's value, we will change the execution flow of our program. For this to be possible, we need a refresher on what role the stack plays in the proper flow of a program. From a C language point of view each time we call a function a couple of mandatory proceedings happen within the stack. First, when the assembly instruction call is executed, the current value of the eip register gets pushed into the stack (which grows towards lower memory addresses) so that when the function finishes we can get back to where we were executing instructions. Next, we save the current ebp register value in the stack and set the current esp value as ebp to have a consistent placeholder value from where to retrieve local variables and function parameters. To summarize, this is what a x86 assembly stack frame setup would look like: Random program calls function X():
... ...With a little math we can see the ret value (shown in green), is 16 bytes ahead of the cookie, so; 92 + cookie(4bytes) + 16 = 112bytes. Let's try that much and see what happens: As you can see from the Core Dump (use "$ulimit -c unlimited" if you're not getting dumps) we smashed the return value with 0x41414141 which is the hex value of the A character's we used. Therefore, all we need now is to write 108+the ret value we want in the buffer. If we read the disassemble we can use the value of the path is taken had the if comparison be true, 0x08048438. I want to stress at this point that hardcoding this kind of addresses is just possible because we are using a unpatched version of linux without ASLR and other protection measures. Keeping in my the endianness and using a similar command line setup of the previous sessions, we can bypass the cookie comparison again: A smart reader might have noticed that althought we get the win and loose messages confirming our success, we get a segmentation fault each time. This happens because althought our ret overwriting succeeded, we also smashed the ebp value which gets pop'd when the functions ends. This corrupted value is needed by the callee and other functions and these fail if the value doesn't have a proper meaning, which after filling with A's doesn't. I tried to find a workaround and tested several values from values in various execution situations but a the pushes and pops of the values from the printf parameters seems to screw up my calculations. Hope anybody got a more elegant solution than mine and posts it as a comment or anywhere else, but for the purpose I think this is enough. This article finishes the WARMING UP on STACK section, in the future I will try to continue with the rest of the sections but I don't promise anything at this point :-) Thanks for reading if you got up to this point!
call to function X ----------------------> call X
this is where execution will return after X() does his job -----------------> ...
and after the call we land in X: first, save current EBP --------------> push ebp then, update EBP ---------------------> mov esp, ebp
...This figures might change depending on architecture and syntax, but I think the general idea should be clear for now :-). Now moving on, the saved ebp and retvalues (the saved eip value, called ret from now on) are stored on the stack AFTER our buffer. At this point the path seems a little more obvious, why not overrun the stack and change our ret value so instead of returning to the callee (the program that called it), return to the "you win!" path inside the if statement? First we need to figure out how much we need to overwrite to get to the ret value. If we recall from the previous levels, at the time we used 92bytes plus the value we wanted the cookie to have. If we take a look at the stack layout from the previous sessions and the theory we just reviewed, the ret value should be right after the saved ebp that we have already identified: