格式化字符串

fmt(格式化字符串漏洞)

格式化字符串函数介绍

格式化字符串函数可以接受可变数量的参数,并将第一个参数作为格式化字符串,根据其来解析之后的参数。通俗来说,格式化字符串函数就是将计算机内存中表示的数据转化为我们人类可读的字符串格式。几乎所有的 C/C++ 程序都会利用格式化字符串函数来输出信息,调试程序,或者处理字符串。

常见的有格式化字符串函数有

函数 基本介绍
printf 输出到 stdout
fprintf 输出到指定 FILE 流
vprintf 根据参数列表格式化输出到 stdout
vfprintf 根据参数列表格式化输出到指定 FILE 流
sprintf 输出到字符串
snprintf 输出指定字节数到字符串
vsprintf 根据参数列表格式化输出到字符串
vsnprintf 根据参数列表格式化输出指定字节到字符串
setproctitle 设置 argv
syslog 输出日志
err, verr, warn, vwarn 等 。。。

格式化字符串

这里我们了解一下格式化字符串的格式,其基本格式如下

%[parameter][flags][field width][.precision][length]type

每一种 pattern 的含义请具体参考维基百科的格式化字符串 。以下几个 pattern 中的对应选择需要重点关注

正常使用时的演示程序

32位演示

源文件test1.c

#include<stdio.h>
int main(){
	char *temp = "hello!this is a simple test!";
	printf("num1:%d\nnum2:%d\nnum3:%d\nnum4:%d\nnum5:%d\nnum6:%d\nnum7:%d\nstring in temp:%s",1,2,3,4,5,6,7,temp);
	return 0;
}

编译

gcc -g test1.c -o test1 -no-pie -m32

执行到printf时栈上的情况

在这里插入图片描述

64位演示

源文件同上

编译

gcc -g test1.c -o test1 -no-pie

执行到printf时栈上和寄存器的情况

在这里插入图片描述

hhn和hn

#include<stdio.h>
int main(){
	int a = 0x12345678;
	printf("%d,%hd,%hhd \n",a,a,a);
	return 0;
}

运行结果

在这里插入图片描述

fmt例1(内存泄露)

test2.c

#include<stdio.h>
int main(){
	printf("%x-%x-%x-%x");
	return 0;
}

编译

gcc -g test2.c -o test2 -no-pie

运行结果

在这里插入图片描述

fmt例2(指定参数泄露)

#include<stdio.h>
int main(){
	int a=1,b=2,c=3,d=4,e=5;
	printf("%1$d---%3$d\n",a,b,c,d,e);
	return 0;
}

编译

gcc -g test2.c -o test2 -no-pie

运行结果

在这里插入图片描述

fmt例3(内存修改)

#include<stdio.h>
int main(){
	int n = 1;
	printf("aaaa%n\n",&n);
	printf("n=%d\n",n);
	return 0;
}

编译

gcc -g test2.c -o test2 -no-pie

运行结果

在这里插入图片描述

fmt字符串漏洞的作用:泄露内存信息(栈上信息、程序pie偏移、cannary)、任意地址写入。