缓冲区溢出原理及防范.doc_第1页
缓冲区溢出原理及防范.doc_第2页
缓冲区溢出原理及防范.doc_第3页
缓冲区溢出原理及防范.doc_第4页
免费预览已结束,剩余1页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

摘要:正文:大纲:1. 引言;随着网络安全技术的飞速发展,缓冲区溢出漏洞已经成为当前最具安全威胁的漏洞之一,缓冲区溢出攻击也成为一种非常有效而常见的攻击方法。如Internet上的第1例蠕虫(Morris)攻击,就是利用了fingerd的缓冲区溢出漏洞。SANS评选出的2005年威胁最大的20个漏洞中,有8个跟缓冲区溢出有关。根据CNCERT最近几周的计算机安全漏洞的统计数据,与缓冲区溢出有关的安全事件占了很大的比例。这些都充分说明了研究缓冲区溢出的重要性。本文主要介绍了windows下的缓冲区溢出的相关知识。2. 漏洞原因和原理;2.1 产生原因;当向一个已分配了确定存储空间的缓冲区内复制多于该缓冲区处理能力的数据时,就会发生缓冲区溢出,溢出包括堆溢出和堆栈溢出。它与程序在内存中的分布有关,而它产生的直接原因是由于C/C+程序中的一些函数调用时,没有进行边界检查,如C函数库中的strcpy(),strcat(),sprintf(),gets()等都是不安全的。由上面的分析可知要产生缓冲区溢出,需要有几个条件: 1) 程序编译时在堆栈上分配了固定大小的缓冲区,并且在对缓冲区进行访问时没有提供边界检查。这条在C/C +语言中就满足,而对于有边界检查的语言,如Pascal 等,就没有这样的溢出问题。 2) 程序调用了没有进行边界检查的函数来访问(写操作) 缓冲区,这些函数没有对访问的缓冲区的大小进行判断。由于在C语言中,字符串以0字节来标识结尾,其中没有字符串的长度信息,所以几个没有判断字符串长度的字符串拷贝函数就是容易出现问题的函数。这些函数有: strcat()、strcpy()、sprintf()等。 3) 即使程序使用了上面所说的问题函数也不一定会出现溢出漏洞,漏洞发生的最后一个条件是程序员由于粗心,未检查用户输入数据的长度就将其直接复制到缓冲区中去。虽然这看起来是一件小事,很容易杜绝。可惜的是正因为有大量粗心的程序员的存在,使得溢出漏洞变得非常的普遍。2.2 原理;图1 堆栈缓冲区示意图程序的堆栈是先进后出的一种数据结构,堆栈的生长方向适合内存相反的(如图1)。当调用一个函数时,首先是函数的参数逆序进栈,然后将eip里面的内容进栈作为函数的返回地址(ret),即函数调用结束后程序跳转的地址,接着保存现在程序的栈基指针(ebp),并将当前栈顶指针(esp)拷入ebp作为新的基地址最后将esp减去一定数值用来为本地变量留出一定空间。缓存区往往就分配在这段空间中。由于堆栈是由内存高地址向内存低地址方向增长,而数组的变量是从内存低地址向高地址方向增长,这时如果没有对数组的越界进行检查和限制,通过向程序的数组缓冲区写入超出其长度的内容,覆盖堆栈原来的返回地址(ret),就会造成缓冲区溢出,从而破坏程序的堆栈。如果构造特殊的注入向量覆盖ret值使程序转而执行恶意代码(shellcode),就达到攻击的目的。3. 基于缓冲区漏洞的攻击过程;由上所述可知,堆栈缓冲区溢出漏洞的攻击利用的3个步骤是:1) 溢出点ret的定位;定位ret 的流程是用一定格式的字符串覆盖存在溢出漏洞的缓冲区,使程序溢出,然后根据溢出结果计算ret 的位置。最常用的方法是利用报错对话框精确计算出溢出返回点的方法,如图2中的报错对话框所示,可以看到是“0x79797979”覆盖到了溢出点。依次类推,我们可以不断给一个数组反复赋值,利用整除和求余等数学方法来精确计算溢出点的位置。图2 溢出报错对话框2) 构造shellcode;确定下来溢出点位置后,就需要有可以执行的shellcode来达到入侵的目的。shellcode的编写主要有两种lodsd方法,一是用C等高级语言编写经反汇编后提取二进制码。二是直接使用汇编语言编写并提取二进制码。使用c语言编写生成的代码较长,但编写调试简单,且可以根据不同的需要灵活更改代码。而利用汇编语言生成的代码更为简练,但调试复杂,一旦编写成功后不易修改。3) 用特定地址覆盖ret并且使其跳转到shellcode,并执行。是将返回点覆盖成jmp esp或call ebx的地址。为了通用性使用kernel32.dll中的指令地址因为同一系统中该模块装载地址变化可能小。覆盖方法主要有两种: NNNNNNNNNSSSSSSSSSSSRRRRRRRRRRRRRR型。适合于大缓冲区,“N”代表空指令(NOP),也就是0x90,在实际运行中,程序将什么也不做,而是一直延着这些NOPS运行下去,直到遇到不是NOPS的指令再执行之;“S”代表ShellCode;“R”代表覆盖的返回地址,思路是把返回地址R覆盖为nops的大概位置,这样就会跳到Nop中,然后继续执行,直到我们的ShellCode中。但这种方法由于定位不准确,所以使用起来也不准确。 RRRRRRRRRRNNNNNNNNNNNSSSSSSSSSS型。是用大量的“R”填满整个缓冲区,然后大量的Nop,最后是ShellCode。这里,“R”往后跳到Nop中,再顺着往下执行就会到ShellCode中。但在Windows下,“R”中必定会含有0,这样,整个构造就会被截断,所以这种方法只能用于Unix中。图3 Windows缓冲区分布Windows的系统核心dll包括kernel32.dll、user32.dll、gdi32.dll。这些dll一直位于内存中,而且对应于固定的版本,Windows加载的位置是固定的。用系统核心dll中的jmp esp地址来覆盖返回地址,而把ShellCode紧跟在后面,这样就可跳转到我们的ShellCode中。其利用格式是 NNNNNNRSSSSSS,NNop, SShellCode, Rjmp esp的地址。如图3所示。常用的JMP ESP的地址:0x7ffa4512(winXP/win2003通用);又是我们还可以利用JMP EBX的地址:0x7ffa1571(winXP/win2003通用);4. 检测方法及防范措施;根据缓冲区溢出攻击的步骤,可将常用的缓冲区溢出攻击检测技术分为以下3 种类型:基于输入字符串的检测方法,基于保护堆栈中的返回地址的检测方法和基于监视系统调用的检测方法。4.1 基于输入字符串的检测方法对输入的字符串进行检测,确定其为溢出攻击字符串时采取阻拦措施,使攻击者无法注入攻击代码。一般有以下3 种方法构建溢出攻击字符串。分别如下图4-1,图4-2,图4-3所示:图4-1 缓冲区大于ShellCode 长度图4-2缓冲区小于ShellCode 长度图4-3将ShellCode 放在环境变量里第1 种溢出攻击字符串适用于缓冲区大于ShellCode 长度的情况;第2 种溢出攻击字符串一般用于缓冲区小于ShellCode 长度的情况;第3 种方法是将ShellCode 放在环境变量里,是目前较为常用的方法。在第1 种和第2 种类型的溢出攻击字符串中ShellCode前都加了若干的NOP 指令,因为这2 种情况下ShellCode 的地址无法确定,但只要返回地址指向ShellCode 前的任一条NOP 指令,ShellCode 就可以执行,大大增加了ShellCode 执行的可能性。这些NOP 指令称为sledge。其他单字节指令如AAA 等也可构成sledge。因此缓冲区溢出攻击检测系统可以通过检查输入的字符串中是否含有大量NOP 等可构成sledge的指令来判断此字符串是否是溢出攻击字符串。不过这种方法并不适用于检测第3 种类型的攻击。但这3 种类型的攻击字符串中都含有ShellCode。因此,确定出ShellCode 的基本特征,如不含有“0x00”,含有某些特殊的系统调用等,然后利用人工智能、模式匹配、规则匹配等方法检查输入字符串中是否包含ShellCode 也可检测出是否有缓冲区溢出攻击发生。这些检测都可以在入侵检测等外围防御系统中实现,优点是实现较为简单,不会增加被保护系统的开销;缺点是漏报率较高,无法检测出无明显特征的溢出攻击字符串。4.2 基于保护堆栈中返回地址的检测方法缓冲区溢出攻击最关键的步骤是要通过修改函数返回地址来改变程序的流程,因此,在函数调用返回前,通过检查返回地址是否被修改可以判断是否有缓冲区溢出攻击发生。该检测的实现可以通过在源码中插入一些约束和判断的模块,然后在编译后的程序运行期间对有关变量和堆栈区域进行监控,检测是否有攻击发生。StackGuard 和StackShield 就是这一类型的工具,它们都是gcc 编译器的扩展工具,用于监控调用的函数返回地址是否正常。StackGuard 主要是在内存中的返回地址及缓冲区之间插入一个“Canary”字,如图5 所示。在函数调用返回前通过检查“Canary”字来判断返回地址是否已经被修改,如果这个Canary 的值被改变了,说明可能有人正进行缓冲区溢出攻击,程序会立刻响应,发送一则入侵警告消息,然后停止工作。为防止攻击者构造“Canary”字,StackGuard 选用“终止符”和“随机数”作为“Canary”字的值。但由于“Canary”字所在的位置是固定的,因此也可能被绕过。StackShield 对此作了改进,创建了一个新的堆栈用于备份被保护函数的返回地址。它在被保护函数开始处增加一段代码,用来将函数返回地址拷贝到一张特殊的表中;同样在被保护函数的结尾处也增加一段代码,用来将函数返回地址从表中拷贝回堆栈。从而保证函数正确返回。除这2 种工具外,还有其他一些类似的编译器扩展方法和工具,如PointGuard、Snarskii 等。这些工具提高了被保护系统的安全性,不过增加了系统开销,降低了系统性能。4.3 基于监视系统调用的检测方法如果攻击者成功注入攻击代码,并改变了程序的执行流程使指令的执行指针指向了ShellCode 的入口地址。按照一次缓冲区攻击的3 个步骤,还须执行ShellCode 来完成攻击目的。因此,通过检测是否有ShellCode 运行可以检测是否发生缓冲区溢出攻击。攻击者既希望ShellCode 利用获得的权限启动一个交互式的shell 进程来完成尽量多的事情,又希望ShellCode 尽量短小从而更加隐蔽,所以绝大多数ShellCode 都会调用系统函数。由于监视所有系统调用会耗费大量系统资源,因此只对ShellCode 常用的系统调用进行监视,根据某些特征判断受监视的系统调用是否为非法调用就可确定被保护系统是否遭到缓冲区溢出攻击。例如,如果发现系统调用的返回地址为堆栈,则可认为其为非法调用,因为很少有程序在堆栈上运行代码。4.4 缓冲区漏洞的防范措施上面三种方法是针对如何检测已经发生的缓冲区漏洞,方法虽然多,但是相对比较麻烦,所以我们最好能从根本上防范它,防止缓冲区漏洞的发生。首先在编写程序过程中,程序员有责任和义务养成安全编程的思想,应该熟悉那些可能会产生漏洞或需慎用的函数,清楚那些在编程中要小心使用的函数(特别是在使用C语言时),例如:gets()、strcpy()等等。在软件测试阶段,要专门对程序中的每个缓冲区作边界检查和溢出检测。但是,由于程序编写者的经验不足和测试工作不够全面、充分,目前还不可能完全避免缓冲区溢出漏洞,因此这些漏洞在已经使用以及正在开发的软件中还是有存在的可能,还需要在使用软件时,对它做实时的监测。其次是使用安全语言编写程序,应使用Java等安全的语言编写程序,因为Java在对缓冲区进行操作时,有相应的边界检查,所以可以有效地防止缓冲区溢出漏洞的产生。但是,Java也并非绝对安全,Java的解释器是用C语言编写的,而C并不是一种安全的语言,所以Java解释器还是可能存在缓冲区溢出漏洞并受到攻击。最后可以通过改进编译器,它的主要思想是在编译器中增加边界检查以及保护堆栈

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论