缓冲区溢出攻击的分析及防范策略(编辑修改稿)内容摘要:

存位置时一样的。 利用下面的程序可以近似的得到这个位置(在环境变量不同、传入的命令行参数不同时,这个值略有变动): unsigned long get_esp(void) { _asm_(―movl %esp,%eax‖)。 } void main(void) { printf(―0x%x\n‖,get_esp())。 } 通常,进程运行时向堆栈中写入的数据不会超过数百个字节或数千个字节,有了这个起始地址,用简单的一个个尝试的方法也是可以攻击的。 但显然这不是一种效率高的方法。 解决的办法是在缓冲区前端填充几百字节 NOP 指令,只要猜测的地址落在 NOP 指令序列中,仍可以执行 shellcode,从而成倍地增加猜中的机会。 ( 3) 攻击代码中字节代码为零的消除 Unix的程序中大量使用了 strcpy函数, shellcode 中含有 0x00,由 于通常是攻击一个字符缓冲区,如果攻击代码中含有 0,则它会被当成字符串的结尾处理,于是攻击代码被截断。 消除的方法是对代码做适当的变换,因此在这里需要使用一些汇编程序设计技巧,把 shellcode 转换成不含 0x00 的等价代码。 ( 4)被攻击的缓冲区很小的情况 当缓冲区太小,可能使 NOP 部分或 shellcode 部分覆盖返回地址 ret,导致缓冲区起址到返回地址的距离不足以容纳 shellcode,这样设定的跳转地址就没有用上,攻击代码不能被正确执行。 一个方法就是利用环境变量。 当一个进程启动时,环境变量被映射到进程堆 栈空间的顶端。 这样就可以把攻击代码( NOP 串 +Shellcode)放到一个环境变两中,而在被溢出的缓冲区中填上攻击代码的地址。 比如,可以把 shellcode 放在环境变量中,并把环境变量传入到要攻击的程序中,就可以对有缓冲区溢出漏洞的程序进行攻击。 利用这样方法,还可以设计很大的攻击代码。 2. 2缓冲区溢出攻击的类型 缓冲区溢出的目的在于扰乱具有某些特权运行程序的功能,这样就可以让攻击者取得程序的控制权,如果该程序具有足够的权限,那么整个主机甚至服务器就被控制了。 一般而言,攻击者攻击 root程序,然后执行类 似 ―exec(sh)‖的执行代码来获得 root的 shell。 但并不总是这样,为了达到这个目的,攻击者必须达到如下两个目标: l 在程序的地址空间里安排适当的代码 l 通过适当地初始化寄存器和存储器,让程序跳转到安排好的地址空间执行。 我们可以根据这两个目标来对缓冲区溢出攻击进行分类。 1.在程序的地址空间里安排适当的代码有两种在被攻击程序地址空间里安排攻击代码的方法: ( 1) 植入法: 攻击者向被攻击的程序输入一个字符串,程序会把这个字符串放到缓冲区里。 这个字符串所包含的数 据是可以在这个被攻击的硬件平台运行的指令流。 在这里攻击者用被攻击程序的缓冲区来存放攻击代码,具体方式有以下两种差别: a.攻击者不必为达到此目的而溢出任何缓冲区,可以找到足够的空间来放置攻击代码; b.缓冲区可设在任何地方:堆栈(存放自动变量)、堆(动态分配区)和静态数据区(初始化或未初始化的数据)。 ( 2) 利用已经存在的代码 有时候攻击者所要的代码已经存在于被攻击的程序中了,攻击者所要做的只是对代码传递一些参数,然后使程序跳转到想要执行的代码那里。 比如,共及代码要求执行 ―exec(‗bin/sh‘)‖,而在 libc 库中的代码执行―exec(arg)‖,其中 arg是一个指向字符串的指针参数,那么攻击者只要把传入的参数指针改向指向 ―/bin/sh‖,然后调转到 libc 库中相应的指令序列即可。 2.控制程序转移到攻击代码的方法 所有这些方法都是在试图改变程序的执行流程,使之跳转到攻击代码。 其基本特点就是给没有边界检查或有其他弱点的程序送出一个超长的缓冲区,以达到扰乱程序正常执行顺序的目的。 通过溢出一个缓冲区,攻击者可以用几乎暴力的方法(穷尽法)改写相邻 的程序空间面直接跳过系统的检查。 这里 的分类基准是攻击者所寻求的缓冲区溢出的程序空间类型。 原则上可以是任意的空间。 比如起初的 Morris Worm(莫尔斯蠕虫)就是使用了 fingerd程序的缓冲区溢出,扰乱 fingerd要执行的文件的名字。 实际上许多的缓冲区溢出是用暴力的方法来寻求改变程序指针的。 这类程序不同的地方就是程序空间的突破和内存空间的定位不同。 一般来说,控制程序转移到攻击代码的方法有以下几种: ( 1) 函数返回地址 每当一个函数调用发生时,调用者会在堆栈中留下函数返回地址,它包含了函数结束时返回的地址。 攻击者通过溢出这些自动变量 ,使这个返回地址指向攻击代码,这样就通过改变程序的返回地址,当函数调用结束时,程序跳转到攻击者设定的地址,而不是原先的地址。 这类的缓冲区进出被称为 ―stack smashing attack‖,是目前常用的缓冲区溢出攻击方式。 ( 2) 函数指针 ―Void(*foo)()‖中声明了一个返回值为 Void函数指针的变量 foo。 函数指针定位任何地址空间,所以攻击者只需在任何空间内的函数指针附近找到一个能够溢出的缓冲区,然后溢出来改变函数指针,当程序通过函数指针调用函数时,程序的流程就会发生改变而实现攻击者的 目的。 ( 3) 长跳转缓冲区 在 C 语言中包含了一个简单的检验 /恢复系统,称为 ―setjmp/longjmp‖,意思是在检验点设定 ―setjmp(buffer)‖,用 longjmp(buffer)―来恢复检验点。 然而,如果攻击时能够进入缓冲区的空间,那么 ―longjmp(buffer)‖实际上是跳转到攻击者的代码。 像函数指针一样, longjmp缓冲区能够指向任何地方,所以攻击者所要做的就是找到一个可供溢出的缓冲区。 一个典型的例子就是 Perl ,攻击者首先进入用来恢复缓冲区溢出的 longjmp缓冲区,然后诱导进入恢复模式,这样就使 Perl的解释器跳转到攻击代码上了。 3.综合代码植入和流程控制技术 最简单和常见的溢出缓冲区攻击类型就是在一个字符串里综合了代码植入和激活记录。 攻击者定位一个可供溢出的自动变量,然后向程序传递一个很大的字符串,在引发缓冲区溢出改变激活记录的同时植入了代码(因为 C 语言程序员通常在习惯上只为用户和参数开辟很小的缓冲区)。 代码植入和缓冲区溢出不一定要在一次动作内完成,攻击者可以在一个缓冲区内放置代码(这个时候并不能溢出缓冲区),然后攻击者通过溢出另一个缓冲区来转移程序的指 针。 这样的方法一般用来解决可供溢出的缓冲区不够大(不能放下全部的代码)。 如果攻击者试图使用已经常驻的代码而不是从外部植入代码,他们通常必须把代码做为参数。 举例说明,在 libc(几乎所有的 C 程序都用它来连接)中的一部分代码段会执行 ―exec(something)‖,其中的 something就是参数,攻击者使用缓冲区溢出改变程序的参数,然后利用另一个缓冲区溢出,使程序指针指向 libc 中的特定的代码段。 三 缓冲区溢出攻击的防范策略 缓冲区溢出攻击的防范是和整个系统的安全性分不开的。 如果整个网络系 统的安全设计很差,则遭受缓冲区溢出攻击的机会也大大增加。 针对缓冲区溢出,我们可以采取多种防范策略。 1.系统管理上的防范策略 ( 1) 关闭不需要的特权程序 由于缓冲区溢出只有在获得更高的特权时才有意义,所以带有特权的 Unix 下的 suid程序和 Windows 下由系统管理员启动的服务进程都经常是缓冲区溢出攻击的目标。 这时候,关闭一些不必要的特权程序就可以降低被攻击的风险。 如 Solaris 下的 fdformat 是个有缓冲区溢出漏洞的 suid程序,因为这个格式化软盘的命令用的较少,最直接的措施是去掉这个程序或 者去掉 suid位。 当有缓冲区溢出漏洞的程序还没有补丁时,就可以用这种方法。 ( 2) 及时给程序漏洞打补丁 这是漏洞出现后最迅速有效的补救措。
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。