Saturday, April 11, 2009

Change return address on stack through buffer overflow (Windows version)

Here is the windows version of the same program.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void shankar()
{
printf("\n\nAey,\nWhat's up doc :) \n\n");
exit(10) ;
}

void vijay(char *input)
{
char buffer[14];
strcpy(buffer,input);
}

int main()
{
//print some useful information for the hack
printf("main=%p\n",main);
printf("vijay=%p\n",vijay);
printf("shankar=%p\n",shankar);
vijay("ABCDEFGHIJKLMNOPQRVS\xdc\x10\x41\x00");
return 0;
}

This program was compiled on windows using Visual Studios 2008


This program works same as the linux version, there is however a difference; the C compiler on windows places some extra data on the stack just after the return address (notice the length of the garbage string is 2 bytes more in this case as compared to the linux version); it does it so that it can verify after the function return that the return address is not tampered.

To make this program work, turn off "Buffer security check" using /GS- option from the command line or through the program properties in visual studios, else you might not get upto the return address and even if you managed to find the return address on the stack and change it, you will not able to execute it because the system will come to know that the return address is tampered and it will stop the execution of the program.



You need to change the return address in the string that is passesd to vijay() function else the program will segfault. The manner in which the return address is written remain the same for both linux and windows.

Hope you all find this a bit useful ;)

Thursday, April 9, 2009

Change return address on stack through buffer overflow (Linux)

Ok, i know that i am late; and i should have written this way long before; but anyways, better late than never :)

As said in the previous post, i am going too tell something about changing the return address on the stack through buffer overflow. Please keep in mind that it is not very fancy; its just for the beginners; i am still learning ;)

So, the code goes as:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void bar()
{
printf("\n\nAey,\nWhat's up doc :) \n\n");
exit(10) ;
}

int foo(char *input)
{
char buffer[14];
strcpy(buffer,input);
}

int main()

{
//print some useful information
printf("main=%p\n",main);
printf("foo=%p\n",foo);
printf("bar=%p\n",bar);

foo("ABCDEFGHIJKLMNOPQR\x24\x84\x04\x08");
return 0;

}


This code is written on a linux machine, the same will not work on windows machines. It turns out that C compiler on windows places some more information on the stack after the stack frame pointer.


Code explanation:
Here, we have three function; the good old main() our entry point to the application; then we have the foo() function and the bar() function.

In the main() we are just printing the addresses of the functions in the memory; and then there is a call to the foo() function. Please note that the bar() function is never called; it is not in the control flow of the program. My aim was to somehow replace the address on the stack so that the bar() function is called automatically, when the foo() function returns.

The core of the logic ( if you say so :) ) is in the foo() function. Note the strcpy() operation; we are copying more data in the less space; hence it results in a buffer overflow. This overflowed data is then spilt over other information on the stack including the return address on the stack.

At this point when foo() function is executing, the stack looks something like this:


HIGH ADDRESS LOW ADDRESS
-------------------------------------------------------------------------------------------
input | return address (4 bytes) | sfp (4 bytes) | buffer (14 bytes) |
-------------------------------------------------------------------------------------------
Stack grows this way ------->


From the figure above we can easily see that the return address is at an offset of 18 bytes from the buffer; 14 bytes for the buffer and 4 bytes for the stack frame pointer. So if we copy more then 14 bytes in buffer we will overwrite the stack frame pointer and if we copy more than 18 bytes into the buffer we can easily overwrite the return address on the stack, and there is on one who will stop you from doing this :)

The next question is how to write the return address?
As this code is written on intel machine which is a "little endian" machine; you write the little end of the address first and then the higher end of the address. Say for example, if the address is 0x08048454 the string representation of the same will be \x54\x84\x04\x08. We start with the little end of the address.

If you compile this code on your machine, the address of the bar() function will be different on your system, so just change the return address in the string that is passed to the foo() function as told above and you are ready to go.

Please note that Linux now provides what is called Address Space Randomization. This means that each time your application is loaded into the memory, it is loaded at some random address. This will change the address of the functions every time they are executed. This in turn will render this address changing on the stack useless. To overcome this turn off Address Space Randomization in Linux as follows:

$ echo 0 > /proc/sys/kernel/randomize_va_space

This will make sure that the functions are loaded at the same virtual address every time.