WriteUp:QCTF Xman-stack2
题目描述
QCTF 的 Xman-stack2 题目。
题目本体见这里。
程序本身是一个用于算平均数的计算器,如图所示。
附上 checksec 结果
这里稍微要留意的就是没有开启 PIE 保护。
定位溢出点
直接拖进 IDA 一个 F5 大法好就能看到溢出点了
这里很明显 v13[v5] = v7
这里的 v5 和 v7 都没做任何检查,所以我们就有了任意地址写的能力。
同时观察到有一个叫作 hackhere 的函数
所以这道题的思路就是通过上面的任意地址写覆盖 main 函数的返回地址从而拿到 shell。
定位偏移
静态调试还是很难看出来要写的内存偏移的,所以这里我选择用 IDA 动态调试。
直接在 main 函数的 retn 语句上下断然后 exit 的时候就可以看到栈顶的返回地址了。
这里看到即将弹出的地址在栈的 0xFFA12B7C 处,然后我们再往上找数组的起始地址,可以看到
数组起始地址在 0xFFA12AF8,两者作差得 0x84,也就是说我们只要写入 v13[0x84]
~ v13[0x88]
就可以覆盖 main 函数的返回地址。
/bin/bash 没了
如果按照之前所说我们直接把 hackhere 的地址覆盖过去会发现提示这个
我当时还是挺懵逼的,不过好在这里的提示也有,那就是要弹 sh 而不是 bash。
构造字符串
那么怎么弹 sh 呢?
一开始我想的是在栈上写一个 /bin/sh
然后修改 system
调用之前的语句,但是我启动了两次发现栈的基址还是随机化的只能放弃。
最后经过提醒,发现 /bin/bash
这个字符串中本身就有 sh
这两个字符,所以我们只要覆盖 main 的返回地址为 _system
同时让栈顶指向这个字符串的第八个字符就好了,也就是调用 system(&"/bin/bash"[7])
,这样问题就迎刃而解了。
Exploit
所以最终 Exploit 如下
1 | from pwn import * |
后记
弹 sh 这个操作还是很有意思的。
另外我们还可以观察下这个环境
问了下作者说是用 dockerfile 自己构造的镜像,原来 docker 还有这种能力呀,下次试试吧。