虽然基于Heap(堆)/BSS的溢出现在是相当普遍的,但并没有多少介绍它的资料。
本文将帮你理解什么是Heap溢出,也介绍了几种常用的攻击方法,同时给出了一些可
能的解决方案。阅读本文,您需要了解一些汇编,C语言以及堆栈溢出的基本知识。
一.为什么Heap/BSS溢出很重要?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
堆栈溢出的问题已经广为人知,越来越多的操作系统商家增加了不可执行堆栈的补
丁,一些个人也提供了自己的补丁,象著名的Solar Designer提供的针对Linux的不可
执行堆栈的kernel patch(目前已经推出了用于2.2.13内核的patch),也有一些人开发
了一些编译器来防止堆栈溢出,象Crispin Cowan等开发的StackGuard等等。这些方法
都一定程度上可以减少由堆栈溢出导致的安全问题,但是并却不能防止Heap/BSS的溢出。
在大多数的操作系统中,Heap和BSS段都是可写可执行的。这就使得Heap/BSS的溢出成
为可能。
大部分的基于heap的溢出都是不依赖于系统和硬件结构的,这将在后面进一步介绍。
二.一些概念
~~~~~~~~~~~
一个可执行的文件(比如常见的ELF--Executable and Linking
Format格式的可执行
文件)通常包含多个段,比如:PLT(过程连接表),GOT(全局偏移表),init(包含在初始化
时执行的指令),fini(包含程序终止时要执行的指令),以及ctors和dtors(包含一些全
局构造指令和析构指令)
所谓HEAP,就是由应用程序动态分配的内存区。在这里,"由应用程序"来分配是值得特别注
意的,因为在一个好的操作系统中,大部分的内存区实际上是在内核一级被动态分配的,而
Heap段则是由应用程序来分配的。它在编译的时候被初始化。
BSS段包含未被初始化的数据,在程序运行的时候才被分配。在被写入数据前,它始终保持
全零(至少从应用程序的角度看是这样的)
在大部分的系统中,Heap段是向上增长的(向高址方向增长)。因此,当我们说"X在Y的
下面"时,就是指"X的地址低于Y的地址"。
注意:下面提到的"基于heap的溢出"既包含HEAP段的溢出,也包含BSS段的溢出。
三.Heap/BSS溢出攻击
在这一部分中我们将介绍几种不同的利用Heap/BSS溢出的方法。大部分的例子都是针对
x86
Unix系统的。做一些适当的改变,也可以用于DOS和Windows系统。我们也介绍了几种专
门针对DOS/Windows的攻击方法。
注意:
在本文中,为了简单起见,我们使用了精确的偏移量。偏移量必须与实际的值相等,攻
击程序才能工作。当然你也可以象通常的堆栈攻击方法那样,通过提供多个返回地址及插入
空指令等方法以增加成功的机率。
下面的这个例子是给那些不熟悉Heap溢出的人看的,我会做一些简单的解释:
-----------------------------------------------------------------------------
/* 演示在heap段(已初始化的数据)发生的动态缓冲区溢出*/
#include
#include
#include
#include
#define BUFSIZE 16
#define OVERSIZE 8 /* 我们将覆盖buf2的前OVERSIZE个字节 */
int main()
{
u_long diff;
char *buf1 = (char *)malloc(BUFSIZE), *buf2 = (char *)malloc(BUFSIZE);
diff = (u_long)buf2 - (u_long)buf1;
printf("buf1 = %p, buf2 = %p, diff = 0x%x (%d)bytes\n", buf1, buf2,
diff, diff);
memset(buf2, ''A'', BUFSIZE-1), buf2[BUFSIZE-1] = ''\0'';/*
将buf2用''A''填充 */
printf("before overflow: buf2 = %s\n", buf2);
memset(buf1, ''B'', (u_int)(diff + OVERSIZE)); /*
用diff+OVERSIZE个''B''填充buf1 */
printf("after overflow: buf2 = %s\n", buf2);
return 0;
}
-----------------------------------------------------------------------------
当我们运行它后,得到下面的结果:
[warning3@testserver basic]$ ./heap1 8
buf1 = 0x8049858, buf2 = 0x8049870, diff = 0x18 (24)bytes
before overflow: buf2 = AAAAAAAAAAAAAAA
after overflow: buf2 = BBBBBBBBAAAAAAA
我们看到buf2的前8个字节被覆盖了。这是因为往buf1中填写的数据超出了它的边界进入了
buf2的范围。由于buf2的数据仍然在有效的heap区内,程序仍然可以正常结束。另外我们
可以注意到,虽然buf1和buf2是相继分配的,但他们并不是紧挨着的,而是有8个字节的间
距,这个间距可能随不同的系统环境而不同。
buf1 间距buf2
覆盖前:[xxxxxxxxxxxxxxxx][xxxxxxxx]
覆盖后:[BBBBBBBBBBBBBBBB][BBBBBBBB][BBBBBBBBAAAAAAA]
注意:
一个阻止heap溢出的可能的方法就是在heap段的所有变量之间放一个"canary"值(就象
StackGuard中所做的那样),若这个值在执行中被改变,就认为发生了溢出。
为了解释BSS段的溢出,我们来看下面这个例子:
-----------------------------------------------------------------------------
/* 演示在BSS段(未被初始化的数据)的静态缓冲区溢出 */
#include
#include
#include
#include
#include
#define ERROR -1
#define BUFSIZE 16
int main(int argc, char **argv)
{
u_long diff;
int oversize;
static char buf1[BUFSIZE], buf2[BUFSIZE];
if (argc <= 1)
{
fprintf(stderr, "Usage: %s
fprintf(stderr, "[Will overflow static buffer by
exit(ERROR);
}
diff = (u_long)buf2 - (u_long)buf1;
printf("buf1 = %p, buf2 = %p, diff = 0x%x (%d) bytes\n\n",
buf1, buf2, diff, diff);
memset(buf2, ''A'', BUFSIZE - 1), memset(buf1, ''B'', BUFSIZE - 1);
buf1[BUFSIZE - 1] = ''\0'', buf2[BUFSIZE - 1] = ''\0'';
printf("before overflow: buf1 = %s, buf2 = %s\n", buf1, buf2);
oversize = diff + atoi(argv[1]);
memset(buf1, ''B'', oversize);
buf1[BUFSIZE - 1] = ''\0'', buf2[BUFSIZE - 1] = ''\0'';
printf("after overflow: buf1 = %s, buf2 = %s\n\n", buf1, buf2);
return 0;
}
-----------------------------------------------------------------------------
当我们运行它后,得到下面的结果:
[warning3@testserver basic]$ ./heap2 8
buf1 = 0x8049874, buf2 = 0x8049884, diff = 0x10 (16) bytes
before overflow: buf1 = BBBBBBBBBBBBBBB, buf2 = AAAAAAAAAAAAAAA
after overflow: buf1 = BBBBBBBBBBBBBBB, buf2 = BBBBBBBBAAAAAAA
和heap溢出类似,buf2的前8个字节也被覆盖了。我们也可以注意到,buf1和buf2是紧挨着
的,这意味着我们可以不用猜测buf1和buf2之间的间距.
buf1buf2
覆盖前:[BBBBBBBBBBBBBBBB]
覆盖后:[BBBBBBBBBBBBBBBB][BBBBBBBBAAAAAAA]
从上面两个简单的例子,我们可以应该已经了解Heap/BSS溢出的基本方式了。我们能用它
来覆盖一个文件名,口令或者是保存的uid等等...
下面这个例子演示了一个指针是如何被覆盖的:
-----------------------------------------------------------------------------
/* 演示在BSS段(未被初始化的数据)中的静态指针溢出 */
#include
#include
#include
文章转载地址:http://www.cnpaf.net/Class/hack/06101110491730717240.html