26

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

Ethan Heilman
  • 16,347
  • 11
  • 61
  • 88
user60103
  • 321
  • 4
  • 6
  • 2
    Seriously, you're asking *here* for help in creating a buffer-overrun exploit??? – Lawrence Dol Jan 29 '09 at 08:19
  • 4
    Learning how machines work doesn't necessarily imply you want to perform harmful exploits. – falstro Jan 29 '09 at 08:21
  • 3
    @Monkey : understanding exploits is necessary to protect against them, and the best way to understand is by *writing* an exploit for targeting your *own* software, which is completely legitimate. – Kent Fredric Jan 29 '09 at 08:22
  • 2
    Monkey, Protip: the only way to defend against an attacker is to know how his attack works. – Serafina Brocious Jan 29 '09 at 08:23
  • 9
    Why anyone would vote to close this is beyond me. There is nothing wrong with learning about buffer overflows, exploits, etc. How do you think one would learn to avoid common security mistakes without knowing how they work? – mmcdole Jan 29 '09 at 08:42
  • Not only that, but as a coding exercise it is insanely fun! There are plenty of white-hat crackers. – mmcdole Jan 29 '09 at 08:44
  • +1 good question and an interesting link! – Paul Dixon Jan 29 '09 at 08:56
  • 1
    How does knowing how to exploit a buffer overflow help you write code that doesn't overflow buffers?? However, if you want to get stuf fixed, then you might want to be prepared to have your bluff called (or more likely just be given the run around because people that right sucky code generally aren't keen to fix it). – Tom Hawtin - tackline Apr 08 '10 at 11:18
  • 2
    If you are trying to follow the original paper by Alepth One, quite a lot has changed since its publication. You can read the following excellent blog post to know in detail what all has changed - http://paulmakowski.wordpress.com/2011/01/25/smashing-the-stack-in-2011/ – Raminder Aug 17 '11 at 17:52

5 Answers5

13

'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 buffer1". So, to get to the return address, we have to go through "char buffer1" (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://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-035-computer-language-engineering-spring-2010/projects/x86-64

vonbrand
  • 11,412
  • 8
  • 32
  • 52
Paul
  • 1,483
  • 8
  • 8
  • 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. – user60103 Jan 29 '09 at 10:29
  • 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 Jan 29 '09 at 13:45
  • 1
    @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 Apr 08 '10 at 11:35
9

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.

Shog9
  • 156,901
  • 35
  • 231
  • 235
codelogic
  • 71,764
  • 9
  • 59
  • 54
3

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
  • 87,773
  • 37
  • 126
  • 127
0

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

0

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
  • 45,516
  • 10
  • 73
  • 79