内存溢出之黑客篇

http://baike.baidu.com/view/79183.htm

 

内存溢出已经是软件开发历史上存在了近40年的“老大难”问题,象在“红色代码”病毒事件中表现的那样,它已经成为黑客攻击企业网络的“罪魁祸首”。 如在一个域中输入的数据超过了它的要求就会引发数据溢出问题,多余的数据就可以作为指令在计算机上运行。据有关安全小组称,操作系统中超过50%的安全漏洞都是由内存溢出引起的,其中大多数与微软的技术有关。

  为了便于理解,我们不妨打个比方。缓冲区溢出好比是将十磅的糖放进一个只能装五磅的容器里。一旦该容器放满了,余下的部分就溢出在柜台和地板上,弄得一团糟。由于计算机程序的编写者写了一些编码,但是这些编码没有对目的区域或缓冲区——五磅的容器——做适当的检查,看它们是否够大,能否完全装入新的内容——十磅的糖,结果可能造成缓冲区溢出的产生。如果打算被放进新地方的数据不适合,溢得到处都是,该数据也会制造很多麻烦。但是,如果缓冲区仅仅溢出,这只是一个问题。到此时为止,它还没有破坏性。当糖溢出时,柜台被盖住。可以把糖擦掉或用吸尘器吸走,还柜台本来面貌。与之相对的是,当缓冲区溢出时,过剩的信息覆盖的是计算机内存中以前的内容。除非这些被覆盖的内容被保存或能够恢复,否则就会永远丢失。 

  在丢失的信息里有能够被程序调用的子程序的列表信息,直到缓冲区溢出发生。另外,给那些子程序的信息——参数——也丢失了。这意味着程序不能得到足够的信息从子程序返回,以完成它的任务。就像一个人步行穿过沙漠。如果他依赖于他的足迹走回头路,当沙暴来袭抹去了这些痕迹时,他将迷失在沙漠中。这个问题比程序仅仅迷失方向严重多了。入侵者用精心编写的入侵代码(一种恶意程序)使缓冲区溢出,然后告诉程序依据预设的方法处理缓冲区,并且执行。此时的程序已经完全被入侵者操纵了。 

  入侵者经常改编现有的应用程序运行不同的程序。例如,一个入侵者能启动一个新的程序,发送秘密文件(支票本记录,口令文件,或财产清单)给入侵者的电子邮件。这就好像不仅仅是沙暴吹了脚印,而且后来者也会踩出新的脚印,将我们的迷路者领向不同的地方,他自己一无所知的地方。 

  缓冲区溢出的处理 

  你屋子里的门和窗户越少,入侵者进入的方式就越少…… 

  由于缓冲区溢出是一个编程问题,所以只能通过修复被破坏的程序的代码而解决问题。如果你没有源代码,从上面“堆栈溢出攻击”的原理可以看出,要防止此类攻击,我们可以: 

  1、开放程序时仔细检查溢出情况,不允许数据溢出缓冲区。由于编程和编程语言的原因,这非常困难,而且不适合大量已经在使用的程序; 

  2、使用检查堆栈溢出的编译器或者在程序中加入某些记号,以便程序运行时确认禁止黑客有意造成的溢出。问题是无法针对已有程序,对新程序来讲,需要修改编译器; 

  3、经常检查你的操作系统和应用程序提供商的站点,一旦发现他们提供的补丁程序,就马上下载并且应用在系统上,这是最好的方法。但是系统管理员总要比攻击者慢一步,如果这个有问题的软件是可选的,甚至是临时的,把它从你的系统中删除。举另外一个例子,你屋子里的门和窗户越少,入侵者进入的方式就越少。

 

 

http://www.programbbs.com/bbs/tree35-14959-88915.htm

导致内存溢出问题的原因有很多,比如: 
(1) 使用非类型安全(non-type-safe)的语言如 C/C++ 等。 
(2) 以不可靠的方式存取或者复制内存缓冲区。 
(3) 编译器设置的内存缓冲区太靠近关键数据结构。 
下面来分析这些因素: 
1. 内存溢出问题是 C 语言或者 C++ 语言所固有的缺陷,它们既不检查数组边界,又不检查类型可靠性(type-safety)。众所周知,用 C/C++ 语言开发的程序由于目标代码非常接近机器内核,因而能够直接访问内存和寄存器,这种特性大大提升了 C/C++ 语言代码的性能。只要合理编码,C/C++ 应用程序在执行效率上必然优于其它高级语言。然而,C/C++ 语言导致内存溢出问题的可能性也要大许多。其他语言也存在内容溢出问题,但它往往不是程序员的失误,而是应用程序的运行时环境出错所致。 
2. 当应用程序读取用户(也可能是恶意攻击者)数据,试图复制到应用程序开辟的内存缓冲区中,却无法保证缓冲区的空间足够时(换言之,假设代码申请了 N 字节大小的内存缓冲区,随后又向其中复制超过 N 字节的数据)。内存缓冲区就可能会溢出。想一想,如果你向 12 盎司的玻璃杯中倒入 16 盎司水,那么多出来的 4 盎司水怎么办?当然会满到玻璃杯外面了! 
3. 最重要的是,C/C++ 编译器开辟的内存缓冲区常常邻近重要的数据结构。现在假设某个函数的堆栈紧接在在内存缓冲区后面时,其中保存的函数返回地址就会与内存缓冲区相邻。此时,恶意攻击者就可以向内存缓冲区复制大量数据,从而使得内存缓冲区溢出并覆盖原先保存于堆栈中的函数返回地址。这样,函数的返回地址就被攻击者换成了他指定的数值;一旦函数调用完毕,就会继续执行“函数返回地址”处的代码。非但如此,C++ 的某些其它数据结构,比如 v-table 、例外事件处理程序、函数指针等,也可能受到类似的攻击。 
好,闲话少说,现在来看一个具体的例子。 
请思考:以下代码有何不妥之处? 
void CopyData(char *szData) { 
char cDest[32]; 
strcpy(cDest,szData); 
// 处理 cDest 
... 
}  
奇怪,这段代码好象没什么不对劲啊!确实,只有调用上述 CopyData() 才会出问题。例如:这样使用 CopyData() 是安全的: 
char *szNames[] = {"Michael","Cheryl","Blake"}; 
CopyData(szName[1]); 
为什么呢?因为数组中的姓名("Michael"、"Cheryl"、"Blake")都是字符串常量,而且长度都不超过 32 个字符,用它们做 strcpy() 的参数总是安全的。再假设 CopyData 的唯一参数 szData 来自 socket 套接字或者文件等不可靠的数据源。由于 strcpy 并不在乎数据来源,只要没遇上空字符,它就会一个字符一个字符地复制 szData 的内容。此时,复制到 cDest 的字符串就可能超过 32 字符,进而导致内存缓冲区 cDest 的溢出;溢出的字符就会取代内存缓冲区后面的数据。不幸的是,CopyData 函数的返回地址也在其中!于是,当 CopyData 函数调用完毕以后,程序就会转入攻击者给出的“返回地址”,从而落入攻击者的圈套!授人以柄,惨! 
前面提到的其它数据结构也可能受到类似的攻击。假设有人利用内存溢出漏洞覆盖了下列 C++ 类中的 v-table : 
void CopyData(char *szData) { 
char cDest[32]; 
CFoo foo; 
strcpy(cDest,szData); 
foo.Init(); 

与其它 C++ 类一样,这里的 CFoo 类也对应一个所谓的 v-table,即用于保存一个类的全部方法地址的列表。若攻击者利用内存溢出漏洞偷换了 v-table 的内容,则 CFoo 类中的所有方法,包括上述 Init() 方法,都会指向攻击者给出的地址,而不是原先 v-table 中的方法地址。顺便说一句,即使你在某个 C++ 类的源代码中没有调用任何方法,也不能认为这个类是安全的,因为它在运行时至少需要调用一个内部方法——析构器(destructor)!当然,如果真有一个类没有调用任何方法,那么它的存在意义也就值得怀疑了。 

http://www.woacn.com/index.php?mod=group_thread&code=view&id=15004

 

 

航空史上一惨案:火箭坠地

  1996年6月4日9点34分,惨剧再次发生。当日,库鲁航天中心的工作人员再次按下了那重要的红色启动钮,这一按葬送了阿丽亚娜5号火箭的处女之航。火箭在升空37秒后偏离既定路线并最终解体,随后它的爆炸残骸碎片也落入了加勒比海之中。

仅从表面观察,就不难发现这起事故与阿丽亚娜系列火箭其他型号之间的联系,欧洲宇航局EAS的调查委员会也得出了类似结论。惨剧因火箭导航系统SRI的超负荷运作所致,这套导航系统则是工程师从4号火箭上原封不动地照搬而来。调查委员会的报告显示,照搬这套导航系统的动机正是基于一种存在已久的信条:对这套在4号火箭完美运行的导航系统进行任何修改都是不明智的举动。业界的另一说法则是:切勿碰一个正在运行的系统。

但新火箭不仅较其前辈更大,而且速度也达到了4号火箭的5倍。火箭导航系统SRI所需计算的数据在4号火箭上从未出现。火箭点火升空后测算所得的水平速度以64位浮点数值表示,而这套导航系统SRI无法将其转换为16位的整数值,因为16位整数值并不足以表示火箭的水平速度,最终导致系统的内存溢出,并复写了部分数据。在系统发生重大错误时,SRI理应自动关闭,并仅向火箭计算机提供状态数据而已,但这些状态数据却被错当成了导航数据,指引火箭偏离既定轨道,此时SRI奋力进行的轨道纠正也无非只是将火箭一步步带向了坠毁的深渊。

 

欧洲宇航局的报告最后得出了一个结论,即那些决定系统成败的关键软件必须进行严格的检查,具体而言,也许一次简单的测试就足以发现阿丽亚娜5号导航系统所存在的问题,但事实却是火箭导航系统未经任何检查就被送上了发射架。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值