WriteUp-湖湘杯2018-contacts_plus
前言
这次湖湘杯真的是无力吐槽了,因为 PWN 学的太菜只好当 web 手结果整场比赛服务器都卡的要命,感觉还没隔壁 10 刀一年超售大王卖的 VPS 快,最后摸了个第十一名也是很气。
不过这道堆的 PWN 算是很基础了,也算是学习的起步吧,之前虽然看过 ptmalloc 的源代码也分析过内存分配流程了但是有很多东西还是得调过才能理解透彻。
题目本体见这里
题目描述
首先检查程序保护
1 | /m/h/C/h/n/pwn2 $ checksec contacts_plus |
可以看到保护全开。
逻辑分析
拖进 ida 一看,出题人竟然很贴心的保留了符号,和常规的堆题一致,就是增删改查四个功能。
漏洞点
关键的漏洞点有两个,不过道理是一样的。
第一处出在 RemoveContact :
第二处出在 ChangeName :
核心问题在于删除后没有把 Description 的指针置为
NULL 而且这时候 name 实际上就是
"",所以只要输入的 s 为 ""
就可以访问到已经移除的 Contact。
这样我们就很容易触发 Double Free。
利用
漏洞点很清晰,但是怎么利用?
很容易想到 fastbin attack
但是在那之前我们需要得到要写的地址,所以需要先泄露 libc
基址。
leak libc
首先要做的是泄露 libc 的基址,这里是利用
unsorted bins 来泄露。
我们知道 unsorted bins 实际上可以说是
small bins 和 large bins
的缓存,并且通过环形链表来管理,因此只要我们只要触发 UAF
就能带出 arena 的地址,而 arena 在
libc 中的偏移是固定的因此可以算出 libc
的地址。
为此需要构造 contacts[0]->Description 和
contacts[1]->Description 指向同一个 chunk
并且 contacts[1] 已经被删除,这时候只要再删除
contacts[1] 一次 contacts[0]->Description
指针就指向了一个被双链表连接的
unsorted bin,然后通过打印就可以泄露一个 arena
内的固定偏移地址了。
到这里我们就拿到了 libc 的基址了。
fastbin attack
下一步就是通过 fastbin attack 写 __malloc_hook 了,具体
fastbin attack 的原理ctf-wiki已经写得很详细了,这里不再赘述,关键是如何绕过
malloc 的检查。
最后我们需要把新的 fastbin 分配到
__malloc_hook,但是 malloc
会检查其大小,具体代码是
1 | if (victim != 0) |
我们可以观察 __malloc_hook 周围的内存
1 | pwndbg> hexdump (char*)(&__malloc_hook)-0x40 0x80 |
可以看到有一些 0x7f
可以供我们利用,因此可以利用错位分配让 0x7f 成为
chunk 的 size
字段就可以绕过检查了,这里我选择让 fastbin 分配到
(char*)&__malloc_hook - 0x23。
同时根据计算 0x7f 对应的 requestsize 是
0x70,减去prev_size和size也就是说我们要申请
0x60 的内存即可。
最终利用 one_gadget 尝试可利用的 gadget
写入 __malloc_hook 即可。
exp
整体 exp 如下
1 | from pwn import * |
后记
堆还是很有意思的,关键还是要摸熟 ptmalloc 的许多细节,内功还有待提升呀。