分享
 
 
 

Read the article "WindowsNT Buffer Overflow's From Start to Finish"

王朝system·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

WindowsNT Buffer Overflow's From Start to Finish

I've read most of the articles on BO's(Buffer Overflows) on the net. I have found that

they either for *NIX systems, or they are not detailed enough. The author's usually take

some known vulnerable software and show you step by step how to exploit it. I am going

to take a different approach. I am going to write an app that has a buffer overflow when

reading data from a file. Then I will write an app that will create the file, that when

read, will cause the exploit. I will also include an opcode finding tool.

Tools Needed:

Visual C++ 6.0

Windows NT

*The code and addresses I use are for Windows NT Workstation

4.0 SP6 .First lets write the app that will contain the buffer

overflow. We also want the app to be able to read in some

type of file so we can actually exploit this from some type

of script. So in Visual C++ create a new console application,

select "An Application that supports MFC" and click Finish.

This does not necessarily have to be a MFC app, but I

prefer to use some of the MFC classes. Obviously, I am a

windows programmer. So let's add some exploitable code

here. This is what it will look like:

CWinApp theApp;

using namespace std;

void overflow(char* buff);

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

cerr << _T("Fatal Error: MFC initialization failed") << endl;

nRetCode = 1;

}

else

{

char buff[10];

overflow(buff);

}

return nRetCode;

}

void overflow(char* buff)

{

CFile file;

CFileException er;

if(!file.Open(_T("overflow.txt"),CFile::modeRead,&er))

{

er.ReportError();

return;

}

int x = file.GetLength();

file.Read(buff,x);

}

Let's analyze the code a bit now and find where the problem actually is. Since this

is an MFC console app, the "main" routine may look a little

different, but it works the same. Let's skip to the else

section inside main. You see the first line, char buff[10].

We have allocated a local variable, buff which is an array

of 10 chars. We all know local variables are allocated on

the stack right? So now we call the function overflow and

pass it our buff. Now lets look inside the overflow function.

First we instantiate a CFile object, then a CFileException

object. Now we will attempt to open a file named "overflow.

txt" from the current directory, with read access. If we

open the file successfully we will get the files length,

then we will read the entire contents of the file into our

buff. Do you see the problem here? buff is only 10 chars.

What happens if the file we read is 100? BUFFER OVERFLOW.

But, the big problem is that we are overflowing a buffer

which exists on the stack. When we can write to the stack

we can do some strange things. As you will soon see. So now

lets create a text file called overflow.txt and place it into

the project directory of the first application.

Let's step to the side for a second, a little explanation

of WindowsNT memory architecture is in order here. In NT every

process (executable) is given 4GB (0xFFFFFFFF) of virtual memory

when it is started. Some of this memory is actually shared among

all processes, like kernel and device driver areas. But those

areas are mapped to each processes virtual address space.

No process actually gets 4GB of phyiscal memory, only the

memory necessary is actually allocated from physical. So

every process has full 4GB of virtual memory, which ranges

from 0x00000000 to 0xFFFFFFFF. These areas are divided.

0x00000000 to 0x0000FFFF is reserved for NULL pointer assignments.

Attempting to access memory in this area will cause an access

violation. 0x00010000 to 0x7FFEFFFF is the processes user space.

This is where the exe image is loaded (starting at 0x00400000)

and DLL's are loaded. If code (a DLL or EXE) is loaded at a certain

address in this range it can be executed. Accessing an address which

does not have code loaded in it will cause an access violation.

0x7FFF0000 to 0x7FFFFFFF is reserved bad pointer assignments and you

will get an access violation with any attempt to access it. 0x80000000

to 0xFFFFFFFF is for operating system use only. Things like Device

Drivers and other Kernel level code is stored here. Attempting to

access this area from a user level application (ring 3) will cause

an access violation.

Now back to the overflow.txt file. We are going to keep

putting characters into our text file until we see the

dialog popup informing us of an application error and what

memory we attempted to access. Which character you chose to

fill this text file with is important, as you will see in

minute. Let's start by filling the text file with a's.

Lower case a's. We know the buffer will hold ten so lets

start with 11(make sure your application being built in

debug mode or your results will be different). 11 doesn't

work so we keep increasing it. 18 finally causes a crash.

This crash isn't anything special yet. We've just totally

screwed up the stack and it shows. Lets add six more a's,

for a total of 24. Run the program and watch the dialog

popup explaining to us that instruction at 0x61616161 had

referenced memory at 0x61616161. You do know that the hex

value for the ascii character a is 0x61 right? If you have

Visual C++ installed you will be able to hit cancel now,

and it will debug the application. Once visual studio is

open, open you registers window. To do that go to the view

menu, then debug window, and select registers. If you don't

know anything about assembly, you should, get a book and

READ IT. We see that EAX has been taken, and so has EBP and

EIP. The most important thing is EIP. By being able to fill

in the EIP with whatever we want we are able to jump to any

code in memory. And what makes this even easier is that our

ESP is not destroyed. It seems to point near the area on

the stack that we control. We need to test this to find out.

Now let's get into this. Set a breakpoint on the last bracket

of the main routine, we only care about what happens here.

Now start the debugger and it will make it to this breakpoint

with no errors. Now we need to switch into disassembly view.

If you have the standard keyboard setup for Visual C++ press

alt+8, if not go to the view menu, debug windows, and select

disassembly Also open your memory and registers windows if

you haven't already. You should see something similiar to

this:

004011DB 5F pop edi

004011DC 5E pop esi

004011DD 5B pop ebx

004011DE 83 C4 50 add esp,50h

004011E1 3B EC cmp ebp,esp

004011E3 E8 28 04 00 00 call _chkesp (00401610)

004011E8 8B E5 mov esp,ebp

004011EA 5D pop ebp

004011EB C3 ret

So what is that junk? It's assembly code. You do know

assembly right? Even if you don't, I'll try to make this

easy to understand. Starting at the top we have pop edi.

The pop instruction will remove one item from the top of

the stack and place it into whatever register. In this case

edi. Also important here is the ESP. The ESP is the 32 bit

stack pointer. A pop will mov(e) the top element from the

stack, in this case a DWORD (4 bytes), put it in whatever

register, and increment the stack pointer by 4 (because of

the 4 bytes). So before making another step, look at ESP.

In the memory window enter ESP. You will now see exactly

where esp is pointing to and what is there. Look at the four

bytes pointed to by ESP and watch edi. Now step over this

instruction and notice that edi is now filled with

whatever esp pointed to, and esp has been incremented by

four. Now the next two instructions are the same, but

different registers, step over them and see that they work

the same way. The next three lines are not very important

to us. To understand them you will need to follow the

assembly from the beginning of the routine, and we aren't

doing that. Just step over them, they do nothing special.

Now onto the line, mov esp,ebp. You read this line, right

to left. This will mov(e) whatever is in EBP into ESP.

This also does nothing special for us. Now onto pop ebp.

Here is where this gets interesting. Remember what a pop

does, it removes the top element from the stack. Now lets

take a look at where we our ESP is pointing to, cause

whatever four bytes are there are about to go into EBP.

So again type esp into your memory window. We have a bunch

of 0x61's there (hex value of 'a'). So 0x61616161 is about

to be popped into ebp. Step over the instruction and verify

that it does. Sure enough, that is what happens. But that doesn't

really get us anywhere. Now the next line, ret. Ret is the assembly

return instruction. But there is more to it than just returning. How

does it know where to return to? By the address that is supposed to

be sitting on the stack right now. The return would be the equivalent

of pop eip (which you can't do). It takes the four bytes that ESP points

to and moves them into EIP. And EIP is our 32 bit instruction pointer.

This mean, whatever address EIP points to, is the next instruction to get

executed. So once again, type esp into the memory window and see what we

are about to put into EIP. Well what do you know, another four bytes of

0x61. So step over the ret instruction and watch what happens. EIP will

become 0x61616161 and you will be about to execute the instruction at

0x61616161. Which in my case is nothing ???, invalid memory. So step over

again and you get an access violation. Now look at ESP. It correctly points

to the next area on the stack. For some reason, if you run the program

independant of the debugger and let it crash so you get the ok\cancel dialog,

and then press cancel. When you land on 0x61616161 your ESP will be wrong.

I'm not sure why that is, but it works as expected when you step through

it line by line like we just did. So now we got the program to execute, or

attempt to execute code at 0x61616161, which means we can take over the EIP.

So lets see if we can overflow the stack some more, so that when we get to

0x61616161 our ESP points to the rest of our overflow. So lets add another

4 a's to our text file and debug again. We now have 28 a's in our text file.

So we view the disassembly again, make sure to have your memory window and

register windows open. Step through and over the ret instruction. You are

now at 0x61616161 again. Now type esp into the memory window and look what

is there. Just as we suspected, there are 4 0x61's there. Now we are in business.

Let me go back to a point I made earlier. We used a's (0x61) to fill our text

file to determine if there was an overflow. So since EIP became 0x61616161 we

attempted to access instructions at that address. In my case there was invalid

memory there so it was an access violation. But what if there had been code there?

Maybe a DLL loaded or something. Well, it would have executed that code and probably

done something totally different. The same thing could have happened if we would have

used, A's instead of a's. A's hex value is 0x41. So we would have jumped to 0x41414141

instead of 0x61616161. There could be code there and it would have executed it. So keep

those things in mind.

So we can control the EIP, the ESP points to the rest of the stack, and we can

fill the stack with whatever we like. So now what? Would it be nice if we could

could just jump to ESP and start executing? Well we can, hopefully. Jmp ESP is

in fact a legal instruction. This instruction would mov(e) whatever is in ESP

into EIP and begin executing instructions there. So we need to somehow call jmp

esp. Hmm, how can we do that? Well, lets think. We do have control of EIP, so we

can jump to where ever we want in our process space. If we can fill EIP with the

address of a jmp esp instruction somewhere in memory we are in business. So how

do we find out if there is a jmp esp instruction somewhere in our process space?

It's easier than you think. The first thing we need to do is figure out what the

opcodes for jmp esp are. The opcodes are the machine instructions that programs

are compiled into so they can be executed. So let's create a new app in Visual

C++. Again a console app, and again with MFC. Enter the following code:

CWinApp theApp;

using namespace std;

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

cerr << _T("Fatal Error: MFC initialization failed") << endl;

nRetCode = 1;

}

else

{

return 0;

__asm jmp esp

}

return nRetCode;

}

Now set a breakpoint on the return 0; statement, because the inline assembly line

will not get executed. Start the debugger and let it run to the breakpoint. Now

open up the disassembly debug window. Right click on the window to turn on source

annotation and code bytes. Now look at the line which contains jmp esp. To the

left of jmp esp and to the right of its address, you will see its code bytes

or opcodes. The opcodes for jmp esp are FF E4. So now that we know that, how

do we find that in oour process space? Let's add a bit more code to this app.

Change it to the following:

CWinApp theApp;

using namespace std;

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

cerr << _T("Fatal Error: MFC initialization failed") << endl;

nRetCode = 1;

}

else

{

#if 0

return 0;

__asm jmp esp

#else

bool we_loaded_it = false;

HINSTANCE h;

TCHAR dllname[] = _T("Kernel32");

h = GetModuleHandle(dllname);

if(h == NULL)

{

h = LoadLibrary(dllname);

if(h == NULL)

{

cout<<"ERROR LOADING DLL: "<

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有