views:

690

answers:

5

I am trying to do an example from the Smashing the Stack for Fun and Profit in C, but am kind of stuck at a point, following is the code (I have a 64-bit machine with Ubuntu 64-bit):

int main()
{
    int x;

    x = 0;
    func(1,2,3);
    x = 1;
    printf("x is : %d\n", x);
}

void func(int a, int b, int c)
{
    char buffer[1];
    int *ret;

    ret = buffer + 17;
    (*ret) += 7;
}

The above code works fine and on returning the x=1 line is not executed, but I can't understand the logic behind ret = buffer + 17;, shouldn't it be ret = buffer + 16; i.e, 8bytes for buffer and 8 for the saved base pointer on stack.

Secondly, my understanding is that char buffer[1] is taking 8 bytes (owing to 64-bit arch) and if I increase this buffer to say buffer[2], still the same code should work fine, BUT this is not happening and it starts giving seg fault.

Regards, Numan

+1  A: 

With a lot of this stack smashing stuff, your best friend is gdb. Since you're segfaulting already you're already writing memory you're not supposed to be (a good sign). A more effective way to do it right is to change the return address to somewhere else that's a valid address (e.g. to func's address or to some shellcode you've got). A great resource I'd recommend is the Shellcoder's Handbook, but since you're on a 64-bit architecture a lot of the examples need a bit of work to get going.

Chris Bunch
+6  A: 

Step through the disassembly in gdb (disassemble, stepi, nexti) and look at the registers at each step (info registers).

Here how you can step through disassembly:

gdb ./myprogram
break main
run
display/4i $eip
stepi
stepi
...
info registers
...

You should also know (you probably already do given that you got part of it working) that on many distros, the stack protector is enabled by default in gcc. You can manually disable it with -fno-stack-protector.

codelogic
+11  A: 

'char' on every architecture I've used is 8 bits wide irrespective of whether it's an 8 bit micro, a 16 bit micro, a 32 bit PC, or a 64 bit new PC. Int, on the other hand, tends to be the word size.

The order which the locals are put on the stack can be implementation specific. My guess is that your compiler is putting "int *ret" on the stack before "char buffer[1]". So, to get to the return address, we have to go through "char buffer[1]" (1 byte), "int *ret" (8 bytes), and the saved base pointer (8 bytes) for a total of 17 bytes.

Here's a description of the stack frame on x86 64-bit: http://www.mit.edu/~6.035/handouts-2007/x86-64-architecture-guide.html#stack_frame

Paul
Thanks for the reply. But this should mean that if i declare a char buffer[2], it would take 2 bytes and i should be able to overwrite return address by ret=buffer+18; i.e., 2 bytes for buffer + 8 bytes for *ret + 8bytes for saved base pointer. But this is still not working and it gives a seg fault.
Random trivia: on one embedded architecture that I've seen, char is 32 bits, because the processor can't refer to smaller chunks of memory. Also, on some architectures (such as Itanium), the return address is stored on a different stack to the parameters and locals.
Doug
@numanahsan - actually `char buffer[2];` would be an array and thus `buffer` be the size of a pointer, probably 4 not 2 bytes. It would contain the address of a 2 byte memory region.
tvanfosson
A: 

Aside from (or better yet, in addition to) running a debugger, you can also use the printf "%p" construct to print the addresses of your variables, e.g.:

printf("buf: %p\n", buffer); //&buffer[0] works too; &buffer works for an array
printf("ret: %p\n", &ret):
printf("a:   %p\n", &a);

Printing the addresses of various things can give great insight into how your compiler/implementation is arranging things in the background. And you can do it directly from C code, too!

aib
A: 

Consider taking a look at stealth's borrowed code chunk technique, if you're interested in x64 buffer overflow exploitation.

Mustapha Isyaku-Rabiu