0%

PWN中格式化字符串漏洞

0x00 前言

哈哈哈,太懒了,时隔一年半又来更新博客了。

0x01 漏洞原理

最近做pwn的练习,发现格式化字符串漏洞会经常遇到,不太理解,只能抽出时间来研究一下这古老的漏洞。

首先,我们来看一下常见的样式,(题目为“攻防世界”的string)ida反编译后在某个函数中看到如下的代码:

通常使用printf函数,根据cdcel调用约定,从右到左逐个压栈,如果传入字符串,则压入该字符串指针。由于printf无法知道被调用之前有多少参数被压入栈中,所以需要使用format参数用以指定到底有多少参数。

format类型

参数 表示
%d 表示输出十进制整数
%n 输出所有打印的字符数
%x 输出十六进制数
%s 从内存中读取字符串
%p 显示一个指针

# 特性一: printf()函数的参数个数不固定

当我们写作printf(str)时,此时参数可控,我们在控制了format参数之后结合printf()函数的特性就可以进行相应的攻击。

当我们输入format参数大于存在参数时,printf会读取内存内的数据,如图

此时我们只有3个参数,而我们使用printf(“%s %d %d %d %x\n”,buf,a,b,c)读取时,需要读取4个数据,此时便会读取到下一个地址的内容。

以下例进行分析

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(int argc, char *argv[])
{
char str[200];
fgets(str,200,stdin);
printf(str);
return 0;
}

当我们在fgets时输入AAAA%08x%08x%08x%08x%08x%08x(%08x为格式化为8位16进制数,左对齐,空位补0),调用printf时输出数值时便会读取到内存中的0x41414141(A的16进制为0x41),输出结果为AAAA000000c8b7fc1c20b7e25438080482100000000141414141。

如果我们将AAAA修改为某一敏感地址,使用%s读取地址里面的数据,如读取0x41414141地址的数据\x41\x41\x41\x41%08x%08x%08x%08x%08x%s

# 特性二:利用%n格式符写入数据

%n的作用是把前面已经打印的长度写入某个内存地址,(同一个printf中的输出长度)

如下代码

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
main()
{
int num=66666666;

printf("Before: num = %d\n", num);
printf("%d%n\n", num, &num);
printf("After: num = %d\n", num);

}

此时%n成功修改了num的值,输出结果为:

1
2
3
Before: num = 66666666
66666666
After: num = 8

# 特性三:自定义打印字符串宽度

此时我们修改printf("%d%n\n", num, &num);printf("%100d%n\n", num, &num);时,最终num输出为100。若改为%.100d或%0100d,则会在6之前输出92个0。

当我们要把0x8048000地址写入内存时,此时,我们可以使用如下方式

1
2
printf("%.134512640d%n\n", num, &num);
printf("After: num = %x\n", num);

此外还需要$的配合,如下的代码

1
printf("7th: %7$d, 4th: %4$05d\n", 10, 20, 30, 40, 50, 60, 70, 80);

会打印输出

1
7th: 70, 4th: 00040

即%7$d 获取的将是参数列表中第7个元素的值,%4$05d 获取的是第四个参数的值,且有效位长度是5。

0x02 其他相关

在Stack中Canary found绕过问题:

系统产生一个随机数,在程序开始和结尾时会进行检查,如果发生改变就会抛出异常。

某些题目需要将其先泄漏出来,再填充到结束的位置

0x03 参考

漏洞挖掘基础之格式化字符串

格式化字符串漏洞

-------本文结束  感谢您的阅读-------