简介
格式化字符串函数:格式化字符串函数就是将计算机内存中表示的数据转化为我们人类可读的字符串格式
| 函数 | 基本介绍 |
|---|---|
| printf | 输出到 stdout |
| fprintf | 输出到指定 FILE 流 |
| vprintf | 根据参数列表格式化输出到stdout |
| vfprintf | 根据参数列表格式化输出到指定 FILE 流 |
| sprintf | 输出到字符串 |
| snprintf | 输出指定字节数到字符串 |
| vsprintf | 根据参数列表格式化输出指定字节到字符串 |
| setproctitle | 设置argv |
| syslog | 输出日志 |
| err、verr、warn、vwarn等 | … |
用 print() 为例,它们的第一个参数就是格式化字符串:“Color %s.Number %d.Float %4.2f”,然后printf函数会根据这个格式化字符串来解析
%d - 十进制-输出十进制整数 %s - 字符串-从内存中读取字符串 %x - 十六进制-输出十六进制 %c - 字符-输出字符 %p - 指针-指针地址 %n - 到目前为止所写的字符数
参数如下:
%[parameter][flags][field width][.precision][length]type
parameter:n$用来获取格式化字符串中的指定参数,比如%3$p,就是获取第三个参数flags:可以为0个或多个,可以是这些字符:+,空格,-,#,0field width:给出显示数值的最小宽度precision:常指明输出的最大长度length指出浮点型参数或整型参数的长度,可以是以下字符hh:输出1byteh:输出2bytel:输出4bytell:输出8byte- 在格式化字符串漏洞利用中我们通常使用
hh和h,也就是一次性写1字节和一次性写2字节
type,也被称为转换说明,可以是如下字符d/i:有符号整型,intu:无符号整型,unsigned intx/X:十六进制unsigned int,x使用小写字母输出,X使用大写字母输出s:输出null结尾字符串直到精度规定的上限;如果没有指定精度,则输出所有字节c:把int输出转为unsigned char类型输出,格式化漏洞利用中通常使用其输出大量字节p:void*型,输出对应变量的值n:不输出字符,但是把已经成功输出的字符个数写入对应的整型指针参数所指的变量
程序崩溃
攻击方式最简单,只需要输入一段%s就可以
%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s
对于每一个%s,printf()都会从栈上取一个数字,把数字视为地址,然后打印出该地址指向的内存内容,由于不可能获取每一个数字都是地址,所以数字对应的内容可能不存在,或者该地址被保护,那么就会使程序崩溃
泄露内存
# include <stdio.h>
int main(){
char s[100];
int a =1,b=0x22222222,c=-1;
scanf("%s",s);
printf("%08x.%08x.%08x.%s\n",a,b,c,s);
printf(s);
return 0;
}
编译一下:gcc -m32 -fno-stack-protector -no-pie -o fsl 1.c