缓冲区溢出攻击详细讲解

上传人:hs****ma 文档编号:499077884 上传时间:2023-07-24 格式:DOCX 页数:13 大小:133.08KB
返回 下载 相关 举报
缓冲区溢出攻击详细讲解_第1页
第1页 / 共13页
缓冲区溢出攻击详细讲解_第2页
第2页 / 共13页
缓冲区溢出攻击详细讲解_第3页
第3页 / 共13页
缓冲区溢出攻击详细讲解_第4页
第4页 / 共13页
缓冲区溢出攻击详细讲解_第5页
第5页 / 共13页
点击查看更多>>
资源描述

《缓冲区溢出攻击详细讲解》由会员分享,可在线阅读,更多相关《缓冲区溢出攻击详细讲解(13页珍藏版)》请在金锄头文库上搜索。

1、缓冲区溢出攻击详细讲解缓冲区溢出(Buffer Overflow )是计算机安全领域内既经典而又古老的话题。随着计算机系统安全性的加强, 传统的缓冲区溢出攻击方式可能变得不再奏效,相应的介绍缓冲区溢出原理的资料也变得“大众化”起来。其中看 雪的Oday安全:软件漏洞分析技术一书将缓冲区溢出攻击的原理阐述得简洁明了。本文参考该书对缓冲区溢出 原理的讲解,并结合实际的代码实例进行验证。不过即便如此,完成一个简单的溢出代码也需要解决很多书中无法 涉及的问题,尤其是面对较新的具有安全特性的编译器比如MS的Visual Studio2010。接下来,我们结合具体 代码,按照对缓冲区溢出原理的循序渐进地理

2、解方式去挖掘缓冲区溢出背后的底层机制。一、代码 数据顾名思义,缓冲区溢出的含义是为缓冲区提供了多于其存储容量的数据,就像往杯子里倒入了过量的水一样。 通常情况下,缓冲区溢出的数据只会破坏程序数据,造成意外终止。但是如果有人精心构造溢出数据的内容,那么 就有可能获得系统的控制权!如果说用户(也可能是黑客)提供了水一一缓冲区溢出攻击的数据,那么系统提供了 溢出的容器一一缓冲区。缓冲区在系统中的表现形式是多样的,高级语言定义的变量、数组、结构体等在运行时可以说都是保存在缓冲 区内的,因此所谓缓冲区可以更抽象地理解为一段可读写的内存区域,缓冲区攻击的最终目的就是希望系统能执行 这块可读写内存中已经被蓄

3、意设定好的恶意代码。按照冯诺依曼存储程序原理,程序代码是作为二进制数据存储 在内存的,同样程序的数据也在内存中,因此直接从内存的二进制形式上是无法区分哪些是数据哪些是代码的,这 也为缓冲区溢出攻击提供了可能。OxffffffffOsOOOOOOOO图1进程地址空间分布图1是进程地址空间分布的简单表示。代码存储了用户程序的所有可执行代码,在程序正常执行的情况下,程 序计数器(PC指针)只会在代码段和操作系统地址空间(内核态)内寻址。数据段内存储了用户程序的全局变量, 文字池等。栈空间存储了用户程序的函数栈帧(包括参数、局部数据等),实现函数调用机制,它的数据增长方向 是低地址方向。堆空间存储了程

4、序运行时动态申请的内存数据等,数据增长方向是高地址方向。除了代码段和受操 作系统保护的数据区域,其他的内存区域都可能作为缓冲区,因此缓冲区溢出的位置可能在数据段,也可能在堆、 栈段。如果程序的代码有软件漏洞,恶意程序会“教唆”程序计数器从上述缓冲区内取指,执行恶意程序提供的数 据代码!本文分析并实现栈溢出攻击方式。二、函数栈帧栈的主要功能是实现函数的调用。因此在介绍栈溢出原理之前,需要弄清函数调用时栈空间发生了怎样的变化。 每次函数调用时,系统会把函数的返回地址(函数调用指令后紧跟指令的地址),一些关键的寄存器值保存在栈内, 函数的实际参数和局部变量(包括数据、结构体、对象等)也会保存在栈内。

5、这些数据统称为函数调用的栈帧,而 且是每次函数调用都会有个独立的栈帧,这也为递归函数的实现提供了可能。栈增上方向argOxOObdlCfOebpretESF9 FF FFTQBDEC-1 04inti-an. ( in*: 曰工gfI0addunct-xanC3Pr 1iflBDlfl5Fhpush.lh|70BD17C1 M ECsp703 B3 EC 4400BD170 53pushebx00BD1707 5E&0BD1708 57poshedi xnt- x-o &=-& i q * arg;obd17O5 bboa?-ax t dwoxd.ptr argQBD170CI DF ATD呂

6、t d.K-cxdptr argj00BD1710 S3 4S FC1ST日w口工d ptz(ret.eaxretiuxn xctj;0BD171345 FCme veax a d.wcxdPtr retlt0SCL71 5FP=PedJ.OOBC1717 5EP=POOBP171S 5EPF谕:KEB E500BD1719 5Dpsfbp00BE171C 匚mfunizt j. on 10)图2函数栈帧如图所示,我们定义了一个简单的函数func ti on,它接受一个整形参数,做一次乘法操作并返回。当调用 func tion(O)时,arg参数记录了值0入栈,并将call func tion

7、指令下一条指令的地址0x00bd16f0保存到栈内, 然后跳转到function函数内部执行。每个函数定义都会有函数头和函数尾代码,如图绿框表示。因为函数内需要 用ebp保存函数栈帧基址,因此先保存ebp原来的值到栈内,然后将栈指针esp内容保存到ebp。函数返回前需要 做相反的操作一一将esp指针恢复,并弹出ebp。这样,函数内正常情况下无论怎样使用栈,都不会使栈失去平衡。subesp,44h指令为局部变量开辟了栈空间,比如re t变量的位置。理论上,func tion只需要再开辟4字节空 间保存ret即可,但是编译器开辟了更多的空间(这个问题很诡异,你觉得呢?)。函数调用结束返回后,函数栈

8、 帧恢复到保存参数0时的状态,为了保持栈帧平衡,需要恢复esp的内容,使用add esp,4将压入的参数弹出。之所以会有缓冲区溢出的可能,主要是因为栈空间内保存了函数的返回地址。该地址保存了函数调用结束后后 续执行的指令的位置,对于计算机安全来说,该信息是很敏感的。如果有人恶意修改了这个返回地址,并使该返回 地址指向了一个新的代码位置,程序便能从其它位置继续执行。三、栈溢出基本原理上边给出的代码是无法进行溢出操作的,因为用户没有“插足”的机会。但是实际上很多程序都会接受用户的 外界输入,尤其是当函数内的一个数组缓冲区接受用户输入的时候,一旦程序代码未对输入的长度进行合法性检查 的话,缓冲区溢出

9、便有可能触发!比如下边的一个简单的函数。1.void fun (unsigned char *data)unsigned char bufferBUF_LEN;4. st rcpy(char*)buffer,(char*)da ta);/溢出点5. 这个函数没有做什么有“意义”的事情(这里主要是为了简化问题),但是它是一个典型的栈溢出代码。在使 用不安全的strcpy库函数时,系统会盲目地将data的全部数据拷贝到buffer指向的内存区域。buffer的长度是 有限的,一旦data的数据长度超过BUF_LEN,便会产生缓冲区溢出。dataebp返回地址拷贝数据缓冲区databuffer图3缓

10、冲区溢出由于栈是低地址方向增长的,因此局部数组buffer的指针在缓冲区的下方。当把data的数据拷贝到buffer 内时,超过缓冲区区域的高地址部分数据会“淹没”原本的其他栈帧数据,根据淹没数据的内容不同,可能会有产 生以下情况:1、淹没了其他的局部变量。如果被淹没的局部变量是条件变量,那么可能会改变函数原本的执行流程。这种 方式可以用于破解简单的软件验证。2、淹没了 ebp的值。修改了函数执行结束后要恢复的栈指针,将会导致栈帧失去平衡。3、淹没了返回地址。这是栈溢出原理的核心所在,通过淹没的方式修改函数的返回地址,使程序代码执行“意 外”的流程!4、淹没参数变量。修改函数的参数变量也可能改

11、变当前函数的执行结果和流程。5、淹没上级函数的栈帧,情况与上述4点类似,只不过影响的是上级函数的执行。当然这里的前提是保证函 数能正常返回,即函数地址不能被随意修改(这可能很麻烦!)。如果在data本身的数据内就保存了一系列的指令的二进制代码,一旦栈溢出修改了函数的返回地址,并将该 地址指向这段二进制代码的其实位置,那么就完成了基本的溢出攻击行为。栈壇长方向driU新返回地址sX缓冲区shtsll critic/buffer图4基本栈溢出攻击通过计算返回地址内存区域相对于buffer的偏移,并在对应位置构造新的地址指向buffer内部二进制代码的 其实位置,便能执行用户的自定义代码!这段既是代

12、码又是数据的二进制数据被称为shellcode,因为攻击者希望 通过这段代码打开系统的shell,以执行任意的操作系统命令一一比如下载病毒,安装木马,开放端口,格式化磁 盘等恶意操作。四、栈溢出攻击上述过程虽然理论上能完成栈溢出攻击行为,但是实际上很难实现。操作系统每次加载可执行文件到进程空间 的位置都是无法预测的,因此栈的位置实际是不固定的,通过硬编码覆盖新返回地址的方式并不可靠。为了能准确 定位shellcode的地址,需要借助一些额外的操作,其中最经典的是借助跳板的栈溢出方式。根据前边所述,函数执行后,栈指针esp会恢复到压入参数时的状态,在图4中即data参数的地址。如果我 们在函数的

13、返回地址填入一个地址,该地址指向的内存保存了一条特殊的指令jmp esp跳板。那么函数返回后, 会执行该指令并跳转到esp所在的位置一一即data的位置。我们可以将缓冲区再多溢出一部分,淹没data这样的 函数参数,并在这里放上我们想要执行的代码!这样,不管程序被加载到哪个位置,最终都会回来执行栈内的代码。栈增长力向bufferjmp esp跳板图5借助跳板的栈溢出攻击借助于跳板的确可以很好的解决栈帧移位(栈加载地址不固定)的问题,但是跳板指令从哪找呢? “幸运”的 是,在Windows操作系统加载的大量dl丨中,包含了许多这样的指令,比如kernel32.dll, n tdll.dll,这两

14、个动 态链接库是Windows程序默认加载的。如果是图形化界面的Windows程序还会加载user32.dll,它也包含了大量的 跳板指令!而且更“神奇”的是Windows操作系统加载dll时候一般都是固定地址,因此这些dll内的跳板指令的 地址一般都是固定的。我们可以离线搜索出跳板执行在dll内的偏移,并加上dl丨的加载地址,便得到一个适用的 跳板指令地址!/查询dll内第一个jmp esp指令的位置int findJmp(char*dll_name)char* handle=(char*)LoadLibraryA(dll_name);/获取 dll 加载地址for(int pos=0;po

15、s+)/遍历 dll 代码空间if(handlepos=(char)0xff&handlepos+1=(char)0xe4)/寻找 0xffe4 二 jmp espreturn(int) (handle+pos);这里简化了搜索算法,输出第一个跳板指令的地址,读者可以选取其他更合适位置LoadLibraryA库函数返 回值就是dll的加载地址,然后加上搜索到的跳板指令偏移pos便是最终地址ojmp esp指令的二进制表示为0xffe4, 因此搜索算法就是搜索dll内这样的字节数据即可。虽然如此,上述的攻击方式还不够好。因为在esp后继续追加shellcode代码会将上级函数的栈帧淹没,这样 做并没有什么好处,甚至可能会带来运行时问题。既然被溢出的函数栈帧内提供了缓冲区,我们还是把核心的 shellcode放在缓

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 学术论文 > 其它学术论文

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号