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.

1 comment:

  1. Thx for the nice article. Can u throw some light on how to get the actual return address of my code which I intend to actually run, by replacing the return value in stack frame? One part is calculating how much data to add to the buffer input to overwrite. But the important part is to know what address does my malicious code sits at.. right? How to get that? Thx in advance

    ReplyDelete