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; .t开发者_运维技巧ype 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
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
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)
}
Something like this?
int main()
{
char arr[1];
arr[1000000] = '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.
#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 .
In addition to the excellent article pointed out by Eric, you might also check out the following reading materials:
Writing buffer overflow exploits - a tutorial for beginners
A step-by-step on the buffer overflow vulnerablity
The following article focuses more on heap overflows:
- w00w00 on Heap Overflows
This was copied from my answer here.
The term buffer overflow precisely means accessing past the end of the buffer (sloppily needing to include the idea of buffer underflow, too). But there's a whole class of "memory safety problems" having to do with buffer overflows, pointers, arrays, allocation and deallocation, all of which can produce crashes and/or exploit opportunities in code. See this C example of another memory safety problem (and our way to detect it).
精彩评论