PWN--格式化字符串
简介
格式化字符串是指在编程过程中,通过特殊的占位符将相关对应的信息整合或提取的规则字符串。格式化字符串包括格式化输入和格式化输出,其本质是程序员调用相关格式化字符串的操作协议规定。错误的或不当的信息配置可能导致程序运行失效或产生未定义行为
在PWN中,格式化字符串漏洞是常见的考察点,仅次于栈溢出漏洞。
格式化字符串漏洞成因:程序使用了格式化字符串作为参数,并且格式化字符串为用户可控。其中触发格式化字符串漏洞函数主要是printf
、sprintf
、fprintf
、prin
等C库中print
家族函数
格式化说明符
%d - 十进制 - 输出十进制整数
%s - 字符串 - 从内存中读取字符串
%x - 十六进制 - 输出十六进制数
%c - 字符 - 输出字符
%p - 指针 - 指针地址
%n - 到目前为止所写的字符数
CPU利用ebp访问栈内东西
printf函数参数从右边向左入栈
补充:
EBP(Base Pointer)是栈帧基址指针寄存器,存放执行函数对应栈帧的栈底地址,用于C运行库访问栈中的局部变量和参数
举个栗子
#include <stdio.h>
int main viod{
printf("My name is %s","Cyy");
return 0;
}
输出为
My name is Cyy
漏洞
先来看一下正常的printf用法
#include <stdio.h> //包含标准输入输出库
int main() //主函数,程序的入口
{
char str[100]; //定义一个字符数组str,长度为100,用于存储用户输入的字符串
scanf("%s", str); //使用scanf函数从标准输入读取一个字符串,并存储到str中
printf("%s", str); //使用printf函数将str中的字符串输出到标准输出
return 0; //程序正常结束,返回0
}
规定字符串的格式化说明符,规定参数的输出类型
补充:
字符串格式化说明符--用于规定输出数据的类型,也就是代码中的%s,从内存中读取字符串
接下来看一下错误版本
#include <stdio.h>
int main()
{
char str[100];
scanf("%s",str);
printf(str);
return 0;
}
程序将格式化字符串的输入权交给用户,printf函数并不知道参数个数,它的内部有个指针,用来索检格式化字符串。对于特定类型%,就去取相应参数的值,直到索检到格式化字符串结束。所以没有参数,代码也会将format string 后面的内存当做参数以16进制输出。这样就会造成内存泄露。
举个栗子
#include <stdio.h>
int main(void)
{
char a[100];
scanf("%s",a);
printf(a);
return 0;
}
假设输入为
AAAA%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x
输出为
AAAA61fe4c,61ffcc,76e4d250,70734fbf,fffffffe,76e473da,41414141,252c7825,78252c78,2c78252c,252c7825
可以看到打印出了地址
漏洞利用
主要利用有:使程序崩溃、栈数据泄露、任意地址内存泄露、栈数据覆盖、任意地址内存覆盖。
格式化字符串与malloc free有关的格式化字符串漏洞
malloc()、calloc()、realloc()分配堆中空间
alloca()来分配栈中的空间
scanf输入和printf输出的字符过多的时候,会调用malloc来处理,且结束之后都会调用free。
所以当输入或输出较多的时候,可以覆盖_free_hook或者_malloc_hook为其他函数地址来调用其他函数