这个知识点以前就看过了,但之前一直不是很懂,今天再来看的时候,把以前一些盲区扫了
参考资料:
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/unlink-zh/
从0到1 ctfer书籍
pwnki师傅的博客
这三篇其实讲的也差不多,但是在不同角度上某些东西显的比较清楚
原理
所谓的UNlink其实就是链表的一个remove操作,先来看看linux的源码
// 由于 P 已经在双向链表中,所以有两个地方记录其大小,所以检查一下其大小是否一致(size检查) if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0)) malloc_printerr ("corrupted size vs. prev_size"); // 检查 fd 和 bk 指针(双向链表完整性检查) if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) malloc_printerr (check_action, "corrupted double-linked list", P, AV); // largebin 中 next_size 双向链表完整性检查 if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0) || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0)) malloc_printerr (check_action, "corrupted double-linked list (not small)", P, AV); // fd bk if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) malloc_printerr (check_action, "corrupted double-linked list", P, AV);
在这种情况下,如果想利用unlink,那么必须要满足以下条件
此时
- FD->bk = target addr - 12 + 12=target_addr
- BK->fd = expect value + 8
那么我们上面所利用的修改 GOT 表项的方法就可能不可用了。但是我们可以通过伪造的方式绕过这个机制。
首先我们通过覆盖,将 nextchunk 的 FD 指针指向了 fakeFD,将 nextchunk 的 BK 指针指向了 fakeBK 。那么为了通过验证,我们需要
fakeFD -> bk == P
<=>*(fakeFD + 12) == P
fakeBK -> fd == P
<=>*(fakeBK + 8) == P
当满足上述两式时,可以进入 Unlink 的环节,进行如下操作:
fakeFD -> bk = fakeBK
<=>*(fakeFD + 12) = fakeBK
fakeBK -> fd = fakeFD
<=>*(fakeBK + 8) = fakeFD
如果让 fakeFD + 12 和 fakeBK + 8 指向同一个指向 P 的指针,那么:
*P = P - 8
*P = P - 12
即通过此方式,P 的指针指向了比自己低 12 的地址处。此方法虽然不可以实现任意地址写,但是可以修改指向 chunk 的指针,这样的修改是可以达到一定的效果的。
此外,其实如果我们设置 next chunk 的 fd 和 bk 均为 nextchunk 的地址也是可以绕过上面的检测的。但是这样的话,并不能达到修改指针内容的效果。
利用思路
条件
UAF ,可修改 free 状态下 smallbin 或是 unsorted bin 的 fd 和 bk 指针
已知位置存在一个指针指向可进行 UAF 的 chunk
效果
使得已指向 UAF chunk 的指针 ptr 变为 ptr - 0x18
思路
设指向可 UAF chunk 的指针的地址为 ptr
修改 fd 为 ptr - 0x18
修改 bk 为 ptr - 0x10
触发 unlink
ptr 处的指针会变为 ptr - 0x18。
疑问解答
1、-0x18和-0x10是什么意思?这里的-0x18和-0x10一直是我上次的疑问,后面发现这目的就是为的绕开检查,并且直接对uaf chunk 指针直接进行修改内容
2、为什么ptr会指向ptr-0x18?答:ptr变为ptr-0x18的原因是FD=ptr-0x18 ptr=FD->bk 并且 BK=ptr-0x10 ptr=BK->fd,由于unlink是remove操作,所以BK->fd=FD=ptr-0x18
相关例题可以在 ctf wiki上看