格式化字符串常见语法

%d 打印signed int
%u 打印unsigned int
%x 打印hex形式整数
%p 打印指针(地址),void*

%s 打印参数地址处的字符串

常见于以下函数

常见利用方式

%<正整数n> 打印宽度为n的字符串(打印长度为n)

%n 将当前已打印字符的个数(4字节)写入参数地址处
%hn 写入2字节
%hhn 写入1字节 【h short】

eg.

  1. printf(“%10c%n”, 0x41, 0x41414141);
    打印9个空格加上1个A ,所以会往地址0x41414141处写入10(4字节)【10是对应的n前的字符个数】

  2. printf(“%1337c%hhn”, 0x41, 0x804a000);
    1337=0x59, 又%hhn, 所以往地址0x804a000处写入1字节0x39
    【一个字节存储0~225】【因为1字节等于8bit,2^8-1】

%<正整数n>$ 指定占位符对应第n个参数,如%12$x 此处%x对应第12个参数
eg.
printf(“0x2$x:0x%1$x\n”, 0xdeadbeef, 0xcafebabe);
打印结果为 0xcafebabe:0xdeadbeef

如果printf参数不足
eg.
printf(“%p:%p:%p:%p\n”);
会假设参数存在,并在对应的栈/寄存器上找到这些参数,并做相应处理
对应x86下32位程序,参数都在栈上,因此pinrtf会把栈上的值一次打印出了

参数不足的情况下
32位:函数调用时参数在栈 格式化字符可控可以泄露站上数据
64位:函数调用使用寄存器+栈 格式化字符可控可以泄露特定寄存器和栈上的值

利用fmtstr_payload

可以生成相应的字符串
fmtstr_payload有两个参数
第一个参数是int,用于表示取参数的偏移个数
第二个参数是字典,字典的意义是往key的地址,写入value的值
fmtstr_payload(offset,{address1:value1})