Alloc_to_Stack&Arbitary Alloc
AFttack Alloc_to_Stack 概述
Alloc_to_Stack&Arbitary Alloc(栈分配&任意地址分配) 如果你已经理解了 Fastbin Double Free 和 house of spirit 技术,那么理解该技术就不成问题了。他们的本质都在于 fastbin 链表的特性:当前 chunk 的 fd 指针指向下一个 chunk。
该技术的核心点在于劫持 fastbin 链表中 chunk 的 fd 指针,把 fd 指针指向我们想要分配的栈上,从而实现控制栈中的一些关键数据,比如返回地址等。
Alloc_to_Stack 利用过程
这次我们把 fake_chunk 置于栈中称为 stack_chunk,同时劫持了 fastbin 链表中 chunk 的 fd 值,通过把这个 fd 值指向 stack_chunk 就可以实现在栈中分配 fastbin chunk。
1 | typedef struct_chunk |
还是基本的 Fastbin Attack 利用,首先创建一个堆然后释放掉,free 后修改 chunk1 的 fd 指针;通过 malloc(0x10)再次取出 chunk1,然后在进行 malloc(0x10)取出的就是 stack_chunk 了。由于 gdb 调试和之前的步骤几乎一样,就不再演示 pwndbg 调试了。
总结一下:通过该技术我们可以把 fastbin chunk 分配到栈中,从而控制返回地址等关键数据。要实现这一点我们需要劫持 fastbin 中 chunk 的 fd 域,把它指到栈上,同时需要栈上存在有满足条件的 size 值。
Arbitary Alloc 概述
Arbitrary Alloc 其实与 Alloc to stack 是完全相同的,唯一的区别是分配的目标不再是栈中。 事实上只要满足目标地址存在合法的 size 域(这个 size 域是构造的,还是自然存在的都无妨),我们可以把 chunk 分配到任意的可写内存中,比如 bss、heap、data、stack 等等。
Arbitary Alloc 利用过程
在这个例子,我们使用字节错位来实现直接分配 fastbin 到_malloc_hook 的位置,相当于覆盖_malloc_hook 来控制程序流程。
1 | int main(void) |
这个我们用 pwngdb 调试一下看看
1 | ────────────────────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────────────────── |
这个时候 chunk_a 指向 0x7fffffffdfd0 地址,我们继续单步执行到 free(chunk1);之前
1 | ────────────────────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────────────────── |
此时可以看到申请的对空间 data 地址已经赋值给了 chunk1 指针。ni 执行 free(chunk1);
1 | ────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────── |
在说明下一行代码之前,先来说说代码错位的情况。由于这个程序的本意是控制 __malloc_hook,(__malloc_hook 是 glibc运行时库提供的一个全局函数指针变量,允许用户在malloc调用时插入自定义代码。)所以我们先找到它的地址:
1 | pwndbg> x/16gx &__malloc_hook |
想要控制 __malloc_hook 地址,就要先找到合法的 size 域,在地址 0x7ffff7bc4b10 向前找:
1 | pwndbg> x/16gx 0x7ffff7bc4b10-0x30 |
由于这个程序是 64 位的,因此 fastbin 的范围为 32 字节到 128 字节(0x20-0x80)如下:
1 | //这里的size指用户区域,因此要小2倍SIZE_SZ |
通过观察发现 0x7ffff7dd1af5 处可以现实错位构造出一个 0x000000000000007f
错位构造
这里解释一下上文的错位构造
1 | __malloc_hook 地址: 0x7ffff7bc4b10 |
我们不可以直接让 fastbin 指向 0x7ffff7bc4b10,因为glibc会检查第一个字段是size,
0x7ffff7dd1b10 处的值可能是0或其他值,不是合法的fastbin size。
1 | 内存地址 数据(小端序) 说明 |
如果把 0x7ffff7bc4b0b 视为一个 chunk 的起始地址0x7f 0x00 0x00 0x00 0x00 0x00 0x00 0x00,正好是地址 0x000000000000007f
把他当作一个堆,-0x08 可以修改 size 域
因为 0x7f 在计算 fastbin index 时,是属于 index 5 的,即 chunk 大小为 0x70 的。
1 | ##define fastbin_index(sz) \ |
由于堆内存还有 0x10 的 chunk_header,所以我们分配 0x60 的 fastbin 就可以了,并将其加入链表。最后经过两次分配可以观察到 chunk 被分配到 0x7ffff7dd1afd,因此我们就可以直接控制 __malloc_hook 的内容 (在我的 libc 中__realloc_hook 与__malloc_hook 是在连在一起的)。
1 | ────────────────────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────────────────── |
从 fastbin 中可以看出,如果进行两次 malloc 的话 1:第一次 malloc 使用空间0x602000,第二次 malloc 使用空间0x7ffff7dd1aed,此时堆内存就分配到了栈上,并且可以继续向下延伸控制占空间。
malloc_hook 攻击
篡改 __malloc_hook 函数指针,让 malloc 执行攻击者代码。
1 | // glibc的malloc首先检查这个钩子 |
利用堆漏洞修改__malloc_hook函数指针,下次调用malloc时就能执行任意代码(如获得shell)。
Arbitrary Alloc 总结
Arbitrary Alloc 在 CTF 中用地更加频繁。我们可以利用字节错位等方法来绕过 size 域的检验,实现任意地址分配 chunk,最后的效果也就相当于任意地址写任意值。
更新: 2026-02-07 23:07:39
原文: https://www.yuque.com/idcm/wnemg9/ztqmruey39vglzel