Unsorted Bin Attack改一个 bk让 glibc 帮你写 libc 地址第一次看这个技巧的时候我没想通一件事凭什么我改一个指针就能往任意地址写东西后来在 magicheap 上手动走了一遍才明白——不是我在写是 glibc 在写我只是把它要写的地方挪了一下。这篇就按我当时踩坑的顺序写。先说清楚前提这个技巧能用得凑齐几件事。块得真的进 unsorted bin。fastbin 范围≤0x80进不去2.26 以后 tcache 范围内≤0x410也进不去这两条先排除。块后面得有一块活着的块挡着。原因下面讲我在这上面白折腾过一次。你的漏洞得能改到这个块的 bk。UAF 也行相邻块溢出也行反正得能碰。最后glibc 不能太新。2.29 之后这招就废了具体在文末。它为什么会进 unsorted binmalloc 返回的不是一块裸内存前面有 0x10 的头0x00 prev_size 0x08 size 0x10 fd 0x18 bk 0x20 用户数据malloc 返回的就是这里free 的时候glibc 会按顺序判断太小进 fastbintcache 没满进 tcache能跟邻居合并就先合并合并完挨着 top 就并进 top。四条都不满足才扔进 unsorted bin。所以「块后面要有东西挡着」这条是为了不让它并进 top。我第一次写 demo 就漏了这个free 完去看 bins空的——因为全并进 top 了。摘链的时候发生了什么下次 malloc_int_malloc会先把 unsorted 清一遍。核心就几行while ((victim unsorted_chunks (av)-bk) ! unsorted_chunks (av)) { bck victim-bk; if (size nb) { /* 尺寸正好够 */ unsorted_chunks (av)-bk bck; bck-fd unsorted_chunks (av); /* ← 就这一行 */ return victim; } }unsorted_chunks(av)是 bin 的头它不长在堆上而是在 libc 的 main_arena 里2.23 上等于main_arena 0x58。所以最后那行干了这么件事往bck 0x10写一个 libc 地址。于是就能算 offset 了fd 在 chunk 里偏移 0x10所以写入位置 bck 0x10 想让写入落在 target → bck target - 0x10magicheap 里 magic 在 0x4040f0所以 bk 要写成 0x4040e0。注意改的是 bk不是 fd——代码读的是victim-bk当作 bck。能写到哪和能写什么是两回事这是我最开始搞混的地方。写到哪你说了算。写什么unsorted_chunks(av)一个常量你说了不算。所以它不是「任意地址写任意值」。它只能把某个位置变成一个很大的 libc 地址写不了system那种精确值。很多 writeup 管这个叫 Write-Anything-Anywhere那是错的。一个能跑的 demo#include stdio.h #include stdlib.h unsigned long target_var 0; int main(void) { unsigned long *p malloc(0x400); unsigned long *guard malloc(0x100); /* 没有它下面的 free 会并进 top */ (void)guard; free(p); printf(fd %#lx bk %#lx\n, p[0], p[1]); p[1] (unsigned long)target_var - 0x10; malloc(0x400); /* 尺寸要对上才走精确匹配 */ printf(target_var %#lx\n, target_var); return 0; }2.23 上跑会看到 fd 和 bk 都是0x7ffff7dd1b78这种地址每次不一样最后target_var也变成这个值。2.27 上要改尺寸。0x400 请求拿到的是 0x410 的 chunk还在 tcache 范围里free 完直接进了 tcacheunsorted 里什么都没有。换成 0x500 才行——这个我试了两次才反应过来。别和 unlink 搞混网上经常把这段代码叫 unlink其实不是。真正的 unlink 是个宏在合并相邻块时调用它有两处写还有完整性检查if (FD-bk ! P || BK-fd ! P) malloc_printerr (corrupted double-linked list);而 unsorted 这里是把「victim 的 fd 一定是 head」写死了只留一处写 一处 head 更新2.23 上没有任何检查。也正是这个差别决定了两件事unlink 的写入值来自P的fd/bk你能控制所以能写任意值unsorted 摘链的写入值是 head 的地址你控制不了所以只能写一个大数。2.29 把检查补进这段内联代码之后unsorted bin attack 就没了。报错是malloc(): corrupted unsorted chunks 3不是corrupted double-linked list那是 unlink 宏的。版本glibc情况≤ 2.28可用2.29加校验触发即退出2.31 及以后只能拿来泄 libc写任意地址不行了2.34 之后__free_hook也被删了就算堆能打通落点也没了。最后这个技巧本身价值在「改变量」判据、标志位、size 字段。真要拿 shell还得靠 fastbin 或 tcache 接一刀——它们能写任意值只是需要先有入口。--- 相关阅读· 上一篇《02Fastbin Attackfasttop 只防连着两次A-B-A 就能绕》· 下一篇《04Large Bin Attack把一个堆地址写到任意位置》· 实战配套《Unsorted Bin Attack 实战把 main_arena 写进全局变量magicheap》全部 exp 与 gdb 脚本GitHub 链接
阅读完成 · 觉得有帮助?