格式化字符串漏洞(Format string vulnerability):无法修改指定字符变量值时构造输入触发目标代码输出"Print me!"
构造输入触发"Print me!"的解决方案
要让程序输出"Print me!",我们需要同时满足两个核心条件:
- 把
locals.iNeedSomeOverflow的初始值大写'P'改为小写'p' - 让全局变量
best_days的值不等于初始的0xdead
分析漏洞与内存布局
先拆解局部结构体locals的内存布局(以32位系统为例,指针和unsigned类型均占4字节):
int* pbest_days:4字节,已初始化为&best_days(全局变量best_days的内存地址)unsigned hereToHelp:4字节char array[60]:60字节,是scanf的输入目标,无边界检查char iNeedSomeOverflow:1字节,紧跟在array的内存区域之后
这里有两个可利用的漏洞:
- 缓冲区溢出:
scanf("%s", locals.array)不限制输入长度,我们可以填满60字节的array后,直接覆盖后续的iNeedSomeOverflow为'p'。 - 格式化字符串漏洞:
printf(locals.array)会把输入字符串当作格式串解析,我们可以用%n指令,借助结构体中已有的pbest_days指针,修改best_days的值。
构造输入的具体步骤
1. 覆盖iNeedSomeOverflow为'p'
先用60个任意字符(比如'A')填满array,然后在第61个字符的位置写入'p',这一步就能完成第一个条件的触发。
2. 利用格式化字符串修改best_days
结构体里的pbest_days已经存储了best_days的地址,我们需要先找到这个地址在printf参数栈中的偏移:
- 先构造测试输入:
60个'A' + 'p' + "%08x%08x%08x%08x%08x%08x",运行程序后观察输出的十六进制值,找到对应best_days地址的那个偏移位(假设是第5个%08x)。 - 把测试用的
%08x替换为%k$n(k是找到的偏移位,比如5),%n会将当前已打印的字符数写入到第k个参数指向的地址(也就是best_days的地址),这样best_days的值就会被修改,不再等于0xdead。
最终输入示例
假设偏移位为5,最终的输入字符串如下:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp%5$n
(前60个字符为'A',第61个为'p',后续是格式化指令)
程序执行流程:
scanf读取输入,填满array后覆盖iNeedSomeOverflow为'p'。printf解析输入的格式串,执行%5$n将已打印的字符数写入best_days,改变其值。- 两个条件均满足,程序输出
"Print me!"。
内容的提问来源于stack exchange,提问作者nullptrexception
相关产品推荐
相关产品推荐

