专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »博文摘选 » 内存溢出:内存溢出攻击分析(下) »正文

内存溢出:内存溢出攻击分析(下)

来源: 发布时间:星期二, 2009年10月13日 浏览:1次 评论:0

非堆栈攻击

前面的例子里面我们展示了如何在接管了程序的控制权后执行自己代码的方法,但是如果被攻击者阻止执行任何在堆栈上面的代码,那么这个方法将立即失效。所以现在所谓的基于“非堆栈”的方法正在被越来越多的使用。其实这个方法的原理也不新鲜,就是我们返回地址不再填充为stack上面的地址,而是直接填系统函数的地址,比如WinExec的程序段地址。剩下的问题是,如何将参数压入堆栈,刚刚好在调用系统函数的时候可用,下图展示了“非堆栈”攻击方法的stack结构:

Fig. 4 A non-stack based exploit

 

Legend:

非堆栈攻击不需要在缓冲保存任何指令,只需要把调用WinExec的参数放在堆栈即可。因为我们不能在字符串里面加NULL,所以我们就使用‘|’代替,在WinExec的命令参数里面可以使用‘|’来分隔多个命令,这样WinExec将顺序执行|分隔开的命令。使用两个’||’就保证后面的填充物不会被当作命令来执行。在填充物的后面,我们将返回地址改写到WinExec的地址。此外改写了返回地址后,我们需要保证正确的堆栈长度。由于WinExec不对第二个参数进行限制,因此,我们只需要向前覆盖第一个命令行参数字符串指针的地址即可。

要测试这个方法,我们需要稍微修改一下被攻击的程序,这个和前面那个非常类似,唯一的不同是我们需要一个更大的缓冲空间(后面解释原因),我们把这个程序编译为victim2.exe,代码如下:

Listing 5 – A victim of a non-stack based exploit attack

#include

#define BUF_LEN 1024

void main(int argc, char **argv)

{

char buf[BUF_LEN];

if (argv > 1)

{

printf(„\nBuffer length: %d\nParameter length: %d”, BUF_LEN, strlen(argv[1]) );

strcpy(buf, argv[1]);

}

}

To exploit this program we need a piece given in Listing 6.

Listing 6 – Exploit of the program victim2.exe

#include

char* code = "victim2.exe \"cmd /c calc||AAAAA...AAAAA\xaf\xa7\xe9\x77\x90\x90\x90\x90\xe8\xfa\x12\"";

void main()

{

WinExec( code, 0 );

}

为了简化,我们忽略了部分的“AAAA”,程序中的字符串长度需要控制在1011.

WinExec函数返回的时候,程序跳转到我们替换的返回地址,然后会返回一个调用错误,不过那时候我们的命令已经被执行了。

有不少人会问,我们的“恶意代码”只有区区十几个字节,为啥要1K那么大的缓冲呢?为啥要填充那么多字节呢?其实原因前面也提到过,当函数返回的时候,堆栈的地址会回到返回地址的地方,后面调用开始转向执行返回地址的函数(WinExec函数)代码,在这个函数里面会先分配部分局部变量,这些局部变量需要压入堆栈,而正好刚刚我们改写的堆栈内容在函数返回后已经被认为是空闲的空间,会被那些局部变量改写。事实上,根据调试,程序开始的时候的WinExec函数会占用84字节的堆栈空间,在这个函数里面调用的别的子函数也会增加堆栈的大小,我们必须保证刚刚写入的那个命令行不会被冲掉,下图形象的展示了堆栈的内容结构:

Fig. 5 A sample non-stack based exploit: stack usage

 

联想:

这是另外的一个解决方法,它的优点是很容易编译,没有什么shellcode,而且还对监控不允许执行堆栈上面的非法代码的防御免疫!

System function calling

我们注意到,前面的方法预先获得了系统函数在内存中(程序段的)地址,这样的方法决定了我们的程序无法在各种Windows平台上面移植。为什么呢?因为各种Windows OS使用不同的userkernel地址,因此kernel基地址在不同的系统上面不同,下图是地址系统对照表:

Table 1. Kernel addresses vs. OS environment

Windows Platform

Kernel Base Address

Win95

0xBFF70000

Win98

0xBFF70000

WinME

0xBFF60000

WinNT (Service Pack 4 and 5)

0x77F00000

Win2000

0x77F00000

你可以在不同的系统(Windows NT/2000/XP)上面执行我们的代码来验证这一点。

有没有什么解决方法呢?关键点是增加一些代码,动态获得函数的地址。幸运的是有两个系统函数可以帮助我们完成这个目标,他们是GetProcAddress LoadLibraryA。更多的细节请参考Harmony开发的Kungfoo项目[6]

其它的获取缓冲开始地址的方法

所有之前的方法,我们都是基于Debugger去查找堆栈缓冲地址的起始位置的,而且我们需要非常精确的定位到这个地址。一般来说,这个并不是必须的。假如我们的修改后的返回地址计算的位置没有正好落在我们要执行的shellcode位置,但是落在了我们填充的NOP指令的话,那么会返回NOP,然后又一个一个的跳转,直到我们设定的返回代码被执行为止。换句话来说,如果我们用0x90填充直到代码开始,我们猜到正确的返回地址的概率将大大增加,如下图所示:

Fig. 6 Using NOPs during an overflow attack

 

联想:

0x90对应于NOP指令什么都不做,只是顺序的向下执行,直到我们的shellcode被执行。这个小技巧就避免了需要精确查找缓冲开始地址的麻烦。(译者注:但是对于第二个方法,如果目标程序阻止在堆栈里面执行代码的话,是否也会组织NOP的执行?如果这样,第二个方法就不能使用这个技巧了。)

危险存在在哪里?

糟糕的程序和存在缺陷的软件当然是存在这种风险。一般来说,对于那些处理文本字符串的函数,如果依赖于NULL结尾来判定字符串长度的话就存在一定的风险。比如标准的C/C++库函数strcpy(), strcat(), sprintf(), gets(), scanf()等都存在这个危险。如果他们的目标是一个固定尺寸的stack变量,内存溢出就有可能在他们接收用户输入的时候发生。

另外一个比较普通的情况是,通过一个循环反复的从一个文件读取内容,依靠某个特定的字符来退出循环,这种情况和上面的字符串函数一样危险。

阻止内存溢出攻击

最直接有效的方法就是使用安全的代码。在市场上,有好几款商业的和免费的解决方案能有效的防止大部分的内存溢出工具,以下两个方法比较普遍:

- 基于安全库的方法,他们重新实现了哪些不安全的函数,这些函数不会内存溢出,一个典型的例子是Libsafe项目。(译者注:VS2008的运行库提供了安全的函数,并且对使用不安全函数的程序会提出警告!)

- 另外的一个方法也是基于库的,不过这个库检测并阻止在堆栈上面执行非法的代码。如果程序被攻击,程序会发出警告,在SecureStack开发的SecureWave就是基于这个原理。

另外一个解决的技术是使用编译时运行边界检查,该技术最近被提出来并拥有非常好的前景。内存溢出问题始终是系统管理员头疼的问题之一,不管怎么说,好的编程始终是阻止安全漏洞的最好方法!

总结

当然,还有很多有趣的内存溢出问题没有在这里讨论,我们的目的是演示一下基本的概念和解决基本的问题。我们希望这个文章能够通过让程序员更清楚的理解内存溢出威胁的原因,从而更好的改进软件开发的过程,最终给我们提供更安全的软件。

引用

下面这些链接只是众多的相关文章中的一小部分:

[1] Aleph One, Smashing The Stack For Fun and Profit, Phrack Magazine nr 49, http://www.phrack.org/show.php?p=49&a=14
[2] P. Fayolle, V. Glaume, A Buffer Overflow Study, Attacks & Defenses, http://www.enseirb.fr/~glaume/indexen.html
[3] I. Simon, A Comparative Analysis of Methods of Defense against Buffer Overflow Attacks, http://www.mcs.csuhayward.edu/~simon/security/boflo.html
[4] Bulba and Kil3r, Bypassing StackGuard and Stackshield, Phrack Magazine 56 No 5, http://phrack.infonexus.com/search.phtml?view&article=p56-5
[5] many interesting papers on Buffer Overflow and not only: http://www.nextgenss.com/research.html#papers
[6] http://harmony.haxors.com/kungfoo
[7] http://www.research.avayalabs.com/project/libsafe/
[8] http://www.securewave.com/products/securestack/secure_stack.html

 

该文章翻译自:http://www.windowsecurity.com/articles/Analysis_of_Buffer_Overflow_Attacks.html
作者: Maciej Ogorkiewicz & Piotr Frej
翻译:陈伟
转载请注明!

0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: