漏洞原理
格式化字符串是一种很常见的漏洞,其产生根源是printf函数设计的缺陷,即printf()函数并不能确定数据参数arg1,arg2…究竟在什么地方结束,也就是说,它不知道参数的个数。它只会根据format中的打印格式的数目依次打印堆栈中参数format后面地址的内容
格式字符串漏洞发生的条件就是格式字符串要求的参数和实际提供的参数不匹配。
如图所示,执行的命令为printf("%s %d %d %d %x\n",buf, 1, 2, 3),紧随格式化字串后压入栈上的参数为4个,但格式化字串有五个参数,printf在解析第五个参数%x时,会继续往栈上读取,造成了信息泄露:
常见格式化字符串漏洞函数
格式化字符串符号说明:
转换指示符
长度
%n:将%n之前printf已经打印的字符个数赋值给偏移处指针所指向的地址位置,如%100x%10n表示将0x64写入偏移10处保存的指针所指向的地址(4字节),而hn表示写入的地址空间为2字节,%hhn表示写入的地址空间为1字节,lln表示写入的地址空间为8字节,在32bit和64bit环境下一样。有时,直接写4字节会导致程序崩溃或等候时间过长,可以通过%hn或hhn来适时调整。
%n是通过格式化字符串漏洞改变程序流程的关键方式,而其他格式化字符串参数可用于读取信息或配合%n写数据
#include <stdio.h>
int main(void)
{
int a;
printf("aaaaaaa%n\n",&a);
printf("%d\n",a);
return 0;
}
判断是否存在漏洞
拿到一个程序之后可以通过输入若干个%s来进行判断是否存在漏洞
%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s