views:

534

answers:

7

I tried the code provided by this question,but it doesn't work.

How to contrive an overflow to wrap my head around?

Update:

    .file   "hw.cpp"
    .section .rdata,"dr"
LC0:
    .ascii "Oh shit really bad~!\15\12\0"
    .text
    .align 2
.globl __Z3badv
    .def    __Z3badv;   .scl    2;  .type   32; .endef
__Z3badv:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    movl    $LC0, (%esp)
    call    _printf
    leave
    ret
    .section .rdata,"dr"
LC1:
    .ascii "WOW\0"
    .text
    .align 2
.globl __Z3foov
    .def    __Z3foov;   .scl    2;  .type   32; .endef
__Z3foov:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $4, %esp
    movl    LC1, %eax
    movl    %eax, -4(%ebp)
    movl    $__Z3badv, 4(%ebp)
    leave
    ret
    .def    ___main;    .scl    2;  .type   32; .endef
    .align 2
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    andl    $-16, %esp
    movl    $0, %eax
    addl    $15, %eax
    addl    $15, %eax
    shrl    $4, %eax
    sall    $4, %eax
    movl    %eax, -4(%ebp)
    movl    -4(%ebp), %eax
    call    __alloca
    call    ___main
    call    __Z3foov
    movl    $0, %eax
    leave
    ret
    .def    _printf;    .scl    2;  .type   32; .endef
+3  A: 

You can use the C example you posted. It works the same in C as C++.

The smallest readable answer I can think of:

int main() {
    return ""[1]; // Undefined behaviour (reading past '\0' in string)
}
strager
I tried that code,but doesn't work.BTW your code seems can't get compiled:invalid conversion from `char*' to `int'
Mask
@Mask, Remember that accessing unallocated memory, or memory outside the pointer it was meant for, is undefined behaviour. It could crash, do nothing, or set your computer on fire. I fixed the compiler error; my bad.
strager
`argv[argc]` is already 0. Nothing bad here.
UncleBens
@UncleBens: Did it happen to be 0 when you tested it, or is this actually standardized, defined behaviour?
Thomas
One past the end of array, i.e. arr[sizeof(arr)], is not guaranteed to be 0 but I've often seen such implementation. This partly stems from the fact that an implementation need to ensure a pointer to one element past the array is unique. Dereferencing that element is still undefined behaviour though.
KTC
The description of main function (3.6.1 / 2) says: "The value of argv[argc] shall be 0." It's not one past the end of the array.
UncleBens
@UncleBens, Hmm, didn't know. I'll change my example then.
strager
Smallest readable I can think of: `int main() { return ""[1]; }`
MSalters
@MSalters, Okay, you win. =]
strager
+2  A: 

Something like this?

int main()
{
    char arr[1];
    arr[1000000] = 'a';
}
UncleBens
+2  A: 

A simple buffer overflow would be something like this:

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

int main() {
   char a[4] = {0};
   char b[32] = {0};

   printf("before: b == \"%s\"\n", b);

   strcpy(a, "Putting too many characters in array a");

   printf("after:  b == \"%s\"\n", b);
}

A possible output:

before: b == ""
after:  b == " characters in array a"

The actual behavior of the program is undefined, so the buffer overflow might also cause different output, crashes or no observable effect at all.

sth
+3  A: 

It would help to compile the example in the other question to assembly so you can get a feel for how the stack is laid out for your given compiler and processor. The +8 in the example may not be the correct number for your environment. What you need to determine is where the return address is stored on the stack relative to the array stored on the stack.

By the way, the example worked for me. I compiled on Win XP with Cygwin, gcc version 4.3.4. When I say it "worked", I mean that it ran code in the bad() function, even though that function was never called by the code.

$ gcc -Wall -Wextra buffer-overflow.c && ./a.exe
Oh shit really bad~!
Segmentation fault (core dumped)

The code really isn't an example of a buffer overflow, it's an example of what bad things can happen when a buffer overflow is exploited.

I'm not great with x86 assembly, but here's my interpretation of how this exploit works.

$ gcc -S buffer-overflow.c && cat buffer-overflow.s
_foo:
        pushl   %ebp           ;2
        movl    %esp, %ebp     ;3
        subl    $16, %esp      ;4
        movl    LC1, %eax      ;5
        movl    %eax, -4(%ebp) ;6
        leal    -4(%ebp), %eax ;7
        leal    8(%eax), %edx  ;8
        movl    $_bad, %eax    ;9
        movl    %eax, (%edx)   ;10
        leave
        ret

_main:
    ...
        call    _foo            ;1
    ...

When main calls foo (1), the call instruction pushes onto the stack the address within main to return to once the call to foo completes. Pushing onto the stack involves decrementing ESP and storing a value there.

Once in foo, the old base pointer value is also pushed onto the stack (2). This will be restored when foo returns. The stack pointer is saved as the base pointer for this stack frame (3). The stack pointer is decremented by 16 (4), which creates space on this stack frame for local variables.

The address of literal "WOW\0" is copied into local variable overme on the stack (5,6) -- this seems strange to me, shouldn't it be copying the 4 characters into space allocated on the stack? Anyway, the place where WOW (or a pointer to it) is copied is 4 bytes below the current base pointer. So the stack contains this value, then the old base pointer, then the return address.

The address of overme is put into EAX (7) and an integer pointer is created 8 bytes beyond that address (8). The address of the bad function is put into EAX (9) and then that address is stored in memory pointed to by the integer pointer (10).

The stack looks like this:

     // 4 bytes on each row
ESP: (unused)
   : (unused)
   : (unused)
   : &"WOW\0"
   : old EBP from main
   : return PC, overwritten with &bad

When you compile with optimization, all the interesting stuff gets optimized away as "useless code" (which it is).

$ gcc -S -O2 buffer-overflow.c && cat buffer-overflow.s
_foo:
        pushl   %ebp
        movl    %esp, %ebp
        popl    %ebp
        ret
Dan
Why it doesn't wrk for my computer?
Mask
Edit your question to show what the example looks like when compiled to assembly and we can take a look. Only need to see what `foo` looks like.
Dan
@Mask: Because it all depends on compiler, architecture, stack layout, calling conventions and whatnot. Because such exploits exploint undefined behaviour, it cannot be expected to work as-is on all systems.
Thomas
@Dan ,I don't know how to show the assembly graph...I've pasted the `makefile` I'm using tho
Mask
If you're using gcc, then compile with the `-S` switch. If you're using some other compiler, ... read the documentation :)
Dan
Turn off optimization (get rid of the -O2) and it will work.
Dan
@Dan ,I just cooked a fresh dump,maybe you can find why it doesn't work here? :)
Mask
`movl $__Z3badv, 4(%ebp)` Strange... it's storing the address of `bad` 4 bytes past the base pointer. Did you edit the code? Gotta run, take a look at the article in Eric's answer, it's a good one.
Dan
Oh it works using `gcc -Wall -Wextra`,seems to be something wrong with my `makefile`...
Mask
+5  A: 

If you want to understand exactly what happens in a buffer overflow and how to exploit them i recommend the tutorial by Aleph One written for Phrack 49, Smashing the stack for fun and profit

Eric
+1 for linking to that article
jschmier
I can't make it work in windows XP,x86:(
Mask
See my answer to your follow-up question - http://stackoverflow.com/questions/2543725/how-to-write-a-buffer-overflow-exploit-in-gcc-windows-xp-x86/2548562#2548562
jschmier
Is there a detailed explanation for http://insecure.org/stf/smashstack.html ?I can't seem to understand the second half of that page,the **Shell Code** part...
Mask
A: 
#define _WIN32_WINNT 0x0400
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

void process_msg(const char *pSrc)
{
    char cBuff[5];
    strcpy(cBuff, pSrc);
}

void main()
{
    char szInput[] = "hello world!";
    process_msg(szInput);
}

Running this program at Visual Studio 2008 in Debug mode gives this message:

Run-Time Check Failure #2 - Stack around the variable 'cBuff' was corrupted.

The 'cBuff' char array is allocated on the stack in this example and it's of 5 bytes in size. Copying the given pointer's data (pSrc) to that char arrat (cBuff) overwrites the stack frame's data which will result in a possible exploit.

This technique is used by hackers - they send a specially crafted array of chars which will overwrite the pointer to the "return" address, on the stack, and change it to their desired location at the memory.

So, for example, they could point that "return" address to any system/program code that will open a port or establish a connection, and then they get to you PC, with the application's privileges (many times this means root/administrator).

Read more at http://en.wikipedia.org/wiki/Buffer_overflow .

Poni
A: 

In addition to the excellent article pointed out by Eric, you might also check out the following reading materials:

The following article focuses more on heap overflows:

This was copied from my answer here.

jschmier
Can you elaborate a little about the shell code part?I understand how to change the ret address,but can't seem to understand how the shell code exploit works in all the tutos...
Mask
Definition of shellcode - http://en.wikipedia.org/wiki/Shellcode
jschmier
In these tutorials, the return address is modified to point to the shellcode or a `NOP` slide leading to the shellcode. The shellcode is the code to be executed and is commonly written in machine code. It is specific to the target OS/CPU combination and carefully crafted so it doesn't contain any `NULL` characters. It often starts with a `JMP` to another point in the shellcode followed by a `CALL` to call the start of the payload.
jschmier
So in order to exploit successfully,the key step is to modify the return address to point to the shellcode,which is quite hard if the program is not open source,is that right?
Mask
Discovering and exploiting a security hole is no easy task, nor should it be. Understanding the basics of these exploits is important for writing code to defend against them. You might be interested in *The Shellcoder's Handbook* - http://www.amazon.com/Shellcoders-Handbook-Discovering-Exploiting-Security/dp/047008023X/ref=dp_ob_title_bk
jschmier