内容提要:一、定制自己的WIN2000 SERVER: 1.版本的选择:Win2000有各种语言的版本,对于我们来说,可以选择英文版或简体中文版,我强烈建议:在语言不成为障碍的情况下,请一定使用英文版。要知道,微软的产品是以Bu …… |
我猜当你看到这里时一定也像我当初一样已经热血沸腾、迫不及待了吧?那就赶快来试一下吧。
|
图18 通过程序testsc.c验证我们的shellcode
将testsc.c编译成可执行程序,再运行testsc就可以看到shell了!
|
图19描绘了testsc.c程序所作的一切,相信有了前面那么长的铺垫,读者在看到图19时应该已经没有困难了。
图19 程序testsc.c的控制流程
下面我们该回头看看本文开头的那个Linux下缓冲区溢出攻击实例了。攻击程序exe.c利用了系统中存在漏洞的程序toto.c,通过以下步骤向系统发动了一次缓冲区溢出攻击:
- 通过命令行参数argv[2]得到toto.c程序中缓冲区buffer[96]的地址,并将该地址填充到large_string[128]中;
- 将我们已经准备好的shellcode拷贝到large_string[128]的开头;
- 通过环境变量KIRIKA将我们的shellcode注射到buffer[96]中;
- 当toto.c程序中的main函数返回时,buffer[96]中的shellcode得以运行;由于toto的属主为root,并且具有setuid属性,因此我们得到的shell便具有了root权限。
程序exe.c的控制流程与图19所示程序testsc.c的控制流程非常相似,唯一的不同在于这次我们的shellcode是寄宿在toto运行时的堆栈里,而不是在数据段中。之所以不能再将shellcode放在数据段中是因为当我们在程序exe.c中调用execle(3) 运行toto时,进程整个地址空间的映射会根据toto程序头部的描述信息重新设置,而原来的地址空间中数据段的内容已经不能再访问了,因此在程序exe.c中shellcode是通过环境变量来传递的。
怎么样,是不是感觉传说中的黑客不再像你想象的那样神秘了?暂时不要妄下结论,在上面的缓冲区溢出攻击实例中,攻击程序exe之所以能够准确的将shellcode注射到toto的buffer[96]中,关键在于我们在toto程序中打印出了buffer[96]在堆栈中的起始地址。当然,在实际的系统中,不要指望有像toto这样家有丑事还自揭疮疤的事情发生。
Linux下防御缓冲区溢出攻击的对策
了解了缓冲区溢出攻击的原理,接下来要做的显然就是要找出克敌之道。这里,我们主要介绍一种非常简单但是又比较流行的方法――Libsafe。
在标准C库中存在着很多像strcpy(3)这种用于处理字符串的函数,它们将一个字符串拷贝到另一个字符串中。对于何时停止拷贝,这些函数通常只有一个判断标准,即是否遇上了''\\0''字符。然而这个唯一的标准显然是不够的。我们在上一节刚刚分析过的Linux下缓冲区溢出攻击实例正是利用strcpy(3)对系统实施了攻击,而strcpy(3)的缺陷就在于在拷贝字符串时没有将目的字符串的大小这一因素考虑进来。像这样的函数还有很多,比如strcat、gets、scanf、sprintf等等。统计数据表明,在已经发现的缓冲区溢出攻击案例中,肇事者多是这些函数。正是基于上述事实,Avaya实验室推出了Libsafe。
在现在的Linux系统中,程序链接时所使用的大多都是动态链接库。动态链接库本身就具有很多优点,比如在库升级之后,系统中原有的程序既不需要重新编译也不需要重新链接就可以使用升级后的动态链接库继续运行。除此之外,Linux还为动态链接库的使用提供了很多灵活的手段,而预载(preload)机制就是其中之一。在Linux下,预载机制是通过环境变量LD_PRELOAD的设置提供的。简单来说,如果系统中有多个不同的动态链接库都实现了同一个函数,那么在链接时优先使用环境变量LD_PRELOAD中设置的动态链接库。这样一来,我们就可以利用Linux提供的预载机制将上面提到的那些存在安全隐患的函数替换掉,而Libsafe正是