malloc_consolidate+unlink+rop
1. amd64(作者本地测试为kali,远程测试环境为ubuntu16.04),无libc要求,已经上传远程测试libc
2. 开启aslr
gcc -no-pie main.c -o main ; strip main
题目可以给出 bin 与 libc 供下载,也可以仅给出 bin 文件,通过查找 libc-db 的方式找到对应 libc 版本号(作为一只 pwn 狗,建议给出 libc,省去大家查 libc 的浪费的生命)
1. 首先给用户输入姓名,此时以 malloc 一个 chunk 的方式存储用户的输入
2. 给了 4 个功能,create、delete、edit、show,其中show功能无效
3. create 函数可以申请一个小于 4096 字节的 chunk,并往里面写入数据,然后置flag位为1,同时用一个全局变量 number 来记录已申请的 chunk 个数,number不得大于4。
4. delete 函数可以 free 一个指针并置 flag 位为 0,但是不检查是否已经 free 这个指针。
5. edit 检查 flag 位,只能修改已经 flag 为 1 的 chunk。
6. 数据结构如下:
1. uaf,在dele一个指针后没有清零,可以再次 free 这个 freed 的指针。
2. 漏洞什么的。
1. 主要利用 fastbin 的 malloc_consolidate 这个函数来造成 unlink,后面再布置栈构造 ropchain 即可。
2. 在申请 large bin 的时候,会将 freed fastbin 的 inuse 位清零,同时进行合并,将合并后的堆块放入 unsortbins 中。然后遍历 unsortbins,按照大小分别放入 smallbins 和 largebins 中。
3. 这时利用 uaf,free 一个 fastbin,也就是我们刚才申请的 0x30 大小的块,将它链入 fastbins 的单向链表中。因为当我们从fastbins中分配不会置后一个 chunk 的 inuse位为1,但是由于之前的 malloc_consolidate 已经使得该 fastbin 的后一个 chunk 的 inuse 位为 0,所以造成一个矛盾,是的我们能够 unlink。
4. 分配一个 0x20 大小的 chunk,置后一个 chunk 的 presize 位为我们刚才分配的fastbin 的大小,为 unlink 做准备,0x20 会从之前合并的 smallbins 中切割,然后该 smallbins 移到 unsortbins 中,并成为 last_remainder。
5. 修改 0x30 的 fastbin,并填充 unlink 的 payload,再在之后分配一个 smallbin 大小的 chunk,使得 unsortbin 中的 chunk 移到smallbins(因为 unsortbins 有一个 check,会检查第一个 chunk 的 bk 是否指向 unsortbin 的头),最后 delete 触发 unlink。
6. 接下来的事情就简单了,修改 fflush 的 got 表为 add rsp 8; ret 的 gadget,然后用rop 泄露 libc 基址,最后修改 free_got 为 system 即可。
7. free 一个事先写好 /bin/sh\0 的 chunk 拿 shell 即可。
PS:
因为可以 malloc 任意大小,还有 uaf,漏洞略大,但已经尽力避免未预料解法了。
PPS:
好像国内的 CTF 还没见过考 malloc_consolidate的,也可能我比赛打的少了XD...