缓冲区溢出攻击的原理与实践

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

课程设计任务书

计通学院网络工程专业

一、缓冲区溢出概念

1、缓冲区溢出:指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量溢出的数据覆盖在合法数据上,理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符,但是绝大多数程序都会假设数据长度总是与所分配的储存空间相匹配,这就为缓冲区溢出埋下隐患.操作系统所使用的缓冲区又被称为"堆栈". 在各个操作进程之间,指令会被临时储存在"堆栈"当中,"堆栈"也会出现缓冲区溢出。

2、缓冲区最常见的攻击手段是通过制造缓冲区溢出使程序运行一个用户shell,在通过shell执行其他命令. 若该程序输入root且有suid权限的话,攻击者就获得了一个有root权限的shell,此时就可以对系统进行随意操作了.下面我来介绍一下如何控制程序跳转到攻击代码

①打开记录(Activation Records)

在程序中,每一个函数调用发生,在堆栈中会留下一个Activation Records,它包括函数结束时返回的地址,攻击者通过溢出这些自动变量,使地址指向攻击程序代码. 通过改变程序的返回地址,当调用结束时,程序就跳到攻击者设定的地址,而不是原地址.这类溢出被称为 stacks mashing attack.

②函数指针(Function Pointers)

void(*foo)(1)定义一个返回函数指针的变量foo, Function Pointers可用来定位任何地址空间. 所以只需在任何空间内的Function Pointers附近找到一个能溢出的缓冲区,然后溢出它来改变Function Pointers. 在某时刻,当程序通过Function Pointers调用函数时,程序的流程就按黑客的意图实现了(典型的溢出程序有:Linux下的Superprobe程序).

③长跳转缓冲区(Longjmpbuffers)

在C语言中,包含了一个简单的检验/恢复系统,称为setjmp/longjmp.即在检验点设定setjmp(buffer),用longjmp(buffer)恢复. 但若攻击者能够进入缓冲区空间,则longjmp(buffer)实际上跳转到攻击者的程序代码. 像Function Pointers, longjmp缓冲区能指向任何地方,所以攻击者要做的就是找到一个可供溢出的buffer即可.

最常见的是在一个字符串中综合了代码植入和打开记录. 攻击者定位或提供溢出的自动变量,然后向程序传一个超大字符串,在引发buffer溢出改变打开记录时植入程序代码,由此达到入侵系统的目的.

二、缓冲区溢出实例实现原理

1、堆栈的组成:

图2.1

堆栈由数据存储区、EBP (栈底指针)、EIP (指令寄存器,指向下一条指令的地址)

2、漏洞利用程序详细分析: 图2.2 编写一个漏洞利用程序,给它赋超过本身长度的值,使其溢出,但是我们要找到这个漏洞,我们需用shellcode 进行填充,填充一定数量的值,使我们能够清晰的找到漏洞(EIP ),如果EIP 指向的下一个地址不存在,那么它就出错,警告你哪里的指令引用的地址内存不能为“read ”,那么那个地址就是EIP 所在的

位子,由于每一个地址空间都是4个字节,所以EBP 和EIP 都占4个字节,所以在出错的地址前4个地址就是EBP 的地址。 为了利用漏洞,我们就必须利用EIP 的这个空间,将这个地址用JMP ESP 来赋值,这样EIP —>JMP ESP

,这样程序执行到了EIP 的地址空间时,就会跳转去执行JMP ESP ,这样就会执行另一个shellcode 的代码,这样我们就利用了缓冲区的漏洞。

图2.3

Dcba Hgf Ebp 原EIP …. Dcba Hgf Lkji Ponm …. 正常时的

堆栈情况 内存低址 0x61626364 0x61626364 EBP 的值 内存高址 原EIP 的值 内存高址 溢出后的 堆栈情况 内存低址 0x61626364 0x61626364 0x696a6b6c 内存高址 0x6d6e6f70 内存高址

三、缓冲区溢出实例实现过程

步骤1:

编写一个漏洞分析代码<程序一>

#include "stdio.h"

#include "string.h"

#include "windows.h"

char name[]=

" \x41\x41\x41\x41" //name[0]-name[3]

" \x41\x41\x41\x41" //name[4]-name[7]

"\x6a\x6b\x6c\x6d" //EBP

"\x6e\x6f\x71\x72" //EIP

"\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]);

return 0;

}

调试结果如下图:

图3.1

以上是运行结构,图中所示地址(0x6f6e6d6c)是代码中的部分,所以这里是EIP,所以程序就显而易见了

步骤2、

我找到了漏洞所在的地址,但是我们还需找到本机的JMP ESP的地址,每一台机子的JMP

ESP都不一样,所以,我用了一个小程序找它的地址,这个程序是在网上找的,具体什么意思也没有仔细分析。

程序如下:<程序二>

#include

#include

#include

int main()

{

int nRetCode=0;

bool we_load_it=false; //定义一个bool类型的,赋值false

HINSTANCE h;

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

h=GetModuleHandle(dllname); //动态链接库的地址

if(h==NULL)

{h=LoadLibrary(dllname);

if(h==NULL)

{cout<<"ERROR LOADING DLL:"<

return 1;

}

we_load_it=true;

}

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"<

catch(...) //捕获地址

{

cout<<"END OF"<

done=true;

}

}

if(we_load_it)

FreeLibrary(h);

return nRetCode;

}

这样运行后,找到了本机JMP ESP的地址:0x7c93fcd8

所以将EIP的地址改成JMP ESP的地址,那样就能通过这个地址,跳转,执行你想要的shellcode。

步骤3、

相关文档
最新文档