glibc堆all-in-one
字数 4397 2025-08-20 18:17:42

glibc堆利用全指南

1. 堆分配基础

1.1 malloc函数工作原理

  1. fastbin分配:

    • 大小范围: 0x20-0x80
    • LIFO(后进先出)策略
    • 流程:
      • 根据size计算idx
      • 如果fastbin[idx]不为空则取first chunk
      • 如果为空则进入unsorted bins大循环
  2. smallbin分配:

    • 大小范围: ≤0x3f0
    • FIFO(先进先出)策略
    • 流程:
      • 根据size计算idx
      • 如果smallbin[idx]不为空则取last chunk
      • 如果为空且已初始化则进入unsorted bins大循环
      • 如果未初始化则调用malloc_consolidate后再进入unsorted bins大循环
  3. largebin分配:

    • 大小范围: ≥0x400
    • 如果既不在fastbin也不在smallbin范围内:
      • 无fastchunks则直接进入unsorted bins大循环
      • 有fastchunks则调用malloc_consolidate后再进入unsorted bins大循环

1.2 malloc_consolidate函数

  1. 功能:

    • 合并fastbin中的chunk并放入unsorted bin
    • 与top chunk合并的chunk除外
  2. 流程:

    • 遍历fastbinY数组(每个元素是单向链表头部)
    • 检查prev inuse:
      • 为0则unlink prev chunk
      • 为1则检查next chunk
    • 检查next chunk:
      • 如果是top chunk则与之合并
      • 否则检查next inuse:
        • 为0则unlink next chunk
        • 为1则不做操作
    • 将合并后的chunk插入unsorted bins
    • 循环直到fastbinY为空

1.3 unsorted bins大循环

  1. 遍历unsorted bin寻找满足条件的chunk:

    • 大小刚好合适则返回
    • 在small bin范围内则放入small bin
    • large bin为空则放入large bin
    • 其他情况从large bin尾部寻找合适位置
  2. 切割机制:

    • 如果没有合适大小的free chunk
    • 检查是否有大的free chunk可以切割(除fastbins外)
    • 切割后的剩余部分成为last remainder并放入unsortedbin

1.4 free函数

  1. 释放流程:

    • 检查能否放入fastbin
    • 检查能否进行后向合并与unlink prev chunk
    • 检查能否和top chunk合并
    • 检查能否进行前向合并与unlink next chunk
    • 放入unsorted bin头部
    • 进行一系列安全检查
  2. 安全检查:

    • 检查chunk大小是否小于max fast
    • 防止fastbin double free
    • 检查chunk是否是mmaped
    • 检查当前chunk是否是inuse状态

2. 关键概念

2.1 基本概念

  1. bins链表:

    • 使用头插法
    • fd和bk只在bins中存在
    • 指向chunk头部而非mem区域
  2. chunk关系:

    • prev chunk: 地址较低的chunk
    • next chunk: 地址较高的chunk
  3. tcache:

    • 大小范围: 0x20-0x410
    • 高版本glibc中,tcache bin满后再free相同大小的chunk会尝试unlink

2.2 unlink操作

  1. 目的:

    • 从双向链表中取出空闲块(如free时合并相邻free chunk)
  2. 检查缺陷:

    • fd/bk指针通过与chunk头部的相对地址查找
    • 可用于绕过安全检查
  3. 特殊情况:

    • chunk大小<0x80时直接进入tcache,不参与unlink
    • unlink后的overlapping chunk都会进入unsorted bin

2.3 常见漏洞

  1. UAF(Use After Free):

    • 条件: free后未置NULL,紧接着申请相同大小内存
    • 利用: 操作系统会重新分配刚free的内存
  2. chunk extend/overlapping:

    • 条件: 可控制chunk header数据(常结合off-by-one使用)
    • 方法: 修改size字段后free,导致next chunk被overlapping
    • 作用: 控制chunk内容而非执行流程
  3. off-by-one/off-by-null:

    • 允许修改相邻chunk的size字段
    • 常用于构造chunk overlapping

3. 利用技巧

3.1 信息泄露

  1. 泄露heap base:

    • 通常为修改tcache_perthread_struct
    • 方法: 让tcache结构变成1->0,通过show函数泄露
  2. 泄露libc base:

    • 通过unsortedbin特性泄露
    • 方法:
      • 获取unsortedbin chunk
      • show出main_arena附近地址
      • 计算偏移得到libc base
    • 替代方法:
      • 利用largebin同时泄露libc和heap
      • 打__IO_2_1_stdout泄露
      • 利用fd/bk写入特性

3.2 常见攻击目标

  1. __free_hook:

    • 通过tcache poison修改
    • 常用gadget: system或one_gadget
  2. tcache_perthread_struct:

    • 修改counts数组可控制tcache分配
    • libc2.30以下: counts类型为char
    • libc2.30及以上: counts类型为uint16_t
  3. mp_结构体:

    • 通过large bin attack修改mp_.tcache_bins
    • 使large bin chunk进入tcache
  4. stdout/IO_2_1_stdout:

    • 用于泄露信息或FSOP
    • 可泄露出_environ获取栈地址

3.3 特殊技巧

  1. scanf触发malloc_consolidate:

    • 输入长字符串会调用malloc分配内存
    • 可用于合并fastchunks到unsorted bin
  2. calloc绕过tcache:

    • calloc不从tcache分配
    • 可用于绕过tcache相关保护
  3. environ变量利用:

    • 储存系统环境变量地址
    • 通过libc找到environ地址后可泄露栈地址
  4. magic gadget:

    • 如setcontext+53等
    • 用于控制执行流

4. 保护机制与绕过

4.1 glibc版本差异

  1. glibc-2.32:

    • tcache/fastbin堆指针异或加密
    • 堆内存对齐检查
  2. glibc-2.33:

    • tcachebin链数量检查
  3. glibc-2.34:

    • 移除__malloc_hook和__free_hook
    • 引入tcache_key检查
  4. glibc-2.36:

    • 移除IO处理函数
  5. glibc-2.37:

    • 移除__malloc_assert函数
    • global_max_fast类型改为uint8_t

4.2 绕过技巧

  1. 异或加密绕过:

    • 泄露heap base计算加密key
    • libc2.31: tcache-key为heapbase+0x10
  2. 检查绕过:

    • libc2.31不对tcache 0x10对齐检查
    • 利用large bin attack修改检查条件
  3. hook移除后的利用:

    • 转向FSOP或IO_FILE攻击
    • 使用house of apple/cat等新技术

5. 高级利用技术

5.1 House of系列攻击

  1. House of Orange:

    • 修改top chunk size
    • 分配大chunk使top进入unsorted bin
    • unsorted bin attack修改_IO_list_all
    • 布置FAKE FILE进行FSOP
  2. House of Pig:

    • 利用_IO_str_overflow的malloc/memcpy/free三连
    • 设置参数使free_hook被覆盖为system
    • 需要exit函数触发_IO_flush_all_lockp
  3. House of Kiwi:

    • 触发__malloc_assert
    • 修改_IO_file_jumps和IO_helper_jumps
    • 无需exit函数
  4. House of Emma:

    • 伪造_IO_cookie_file
    • 劫持pointer guard
    • libc2.34及以下可用
  5. House of Cat:

    • 在_IO_switch_to_wget_mode设置rdx
    • 调用setcontext+61进行ORW
    • 需要控制rcx不为0
  6. House of Apple2:

    • 覆盖vtable为_IO_wxxx_jumps
    • 执行_IO_wfile_overflow
    • 利用magic gadget

5.2 IO_FILE利用

  1. FSOP(File Stream Oriented Programming):

    • 劫持_IO_list_all伪造链表
    • 触发_IO_flush_all_lockp
    • 调用vtable中的_IO_overflow
  2. 关键结构:

    • _IO_FILE: 文件流基础结构
    • _IO_FILE_plus: 包含vtable
    • _IO_jump_t: 虚函数表
    • _IO_wide_data: 宽字符数据
  3. 利用条件:

    • 控制_IO_list_all
    • _lock设置为可写地址
    • _mode=0
    • _IO_write_ptr > _IO_write_base
  4. 常用目标:

    • _IO_list_all
    • IO_2_1_stderr
    • stderr

6. 实战技巧

6.1 调试技巧

  1. 关键断点:

    b *&_IO_cleanup
    b *&_IO_flush_all
    b *&_IO_flush_all_lockp
    b *&_IO_flush_all_lockp+223
    b *&_IO_wfile_seekoff
    b *&_IO_switch_to_wget_mode
    
  2. 符号表问题:

    • 从glibc-all-in-one获取有符号表的同版本libc
    • 便于pwndbg调试

6.2 利用模板

  1. House of Apple2利用:
fake_IO_addr = magic_gadget = libc_base + libc.sym["svcudp_reply"] + 0x1a
leave_ret = libc_base + 0x0000000000052d72
pop_rdi_ret = libc_base + 0x000000000002daa2
pop_rsi_ret = libc_base + 0x0000000000037c0a
pop_rdx_r12_ret = libc_base + 0x00000000001066e1

rop_address = fake_IO_addr + 0xe0 + 0xe8 + 0x70
orw_rop = b'./flag\x00\x00'
orw_rop += p64(pop_rdx_r12_ret) + p64(0) + p64(fake_IO_addr - 0x10)
orw_rop += p64(pop_rdi_ret) + p64(rop_address)
orw_rop += p64(pop_rsi_ret) + p64(0)
orw_rop += p64(libc_base + libc.sym['open'])
orw_rop += p64(pop_rdi_ret) + p64(3)
orw_rop += p64(pop_rsi_ret) + p64(rop_address + 0x100)
orw_rop += p64(pop_rdx_r12_ret) + p64(0x50) + p64(0)
orw_rop += p64(libc_base + libc.sym['read'])
orw_rop += p64(pop_rdi_ret) + p64(1)
orw_rop += p64(pop_rsi_ret) + p64(rop_address + 0x100)
orw_rop += p64(pop_rdx_r12_ret) + p64(0x50) + p64(0)
orw_rop += p64(libc_base + libc.sym['write'])

payload = p64(0) + p64(leave_ret) + p64(1) + p64(2)
payload = payload.ljust(0x38, b'\x00') + p64(rop_address)
payload = payload.ljust(0x90, b'\x00') + p64(fake_IO_addr + 0xe0)
payload = payload.ljust(0xc8, b'\x00') + p64(libc_base + libc.sym['_IO_wfile_jumps'])
payload = payload.ljust(0xd0 + 0xe0, b'\x00') + p64(fake_IO_addr + 0xe0 + 0xe8)
payload = payload.ljust(0xd0 + 0xe8 + 0x68, b'\x00') + p64(magic_gadget)
payload = payload + orw_rop
  1. 爆破模板:
while True:
    try:
        p=process(file)
        exp()
        break
    except:
        p.close()
        continue
  1. 一字节覆盖泄露libc:
add(0x40, p64(0xfbad1887)+p64(0)*3+b'\x00')

7. 总结

  1. 利用选择:

    • libc2.31以下: 优先打tcache和hook
    • libc2.34以下: 可用house of kiwi/emma
    • libc2.35+: 用house of apple2/cat
  2. 关键思路:

    • 无UAF时考虑off-by-one构造overlapping
    • 无edit功能时通过overlapping实现等效功能
    • 限制多时考虑tcache_perthread_struct攻击
    • 根据保护机制选择合适利用技术
  3. 发展趋势:

    • 从hook转向IO_FILE利用
    • 从直接控制执行流转向SROP/ORW
    • 适应glibc新增保护机制
glibc堆利用全指南 1. 堆分配基础 1.1 malloc函数工作原理 fastbin分配 : 大小范围: 0x20-0x80 LIFO(后进先出)策略 流程: 根据size计算idx 如果fastbin[ idx ]不为空则取first chunk 如果为空则进入unsorted bins大循环 smallbin分配 : 大小范围: ≤0x3f0 FIFO(先进先出)策略 流程: 根据size计算idx 如果smallbin[ idx ]不为空则取last chunk 如果为空且已初始化则进入unsorted bins大循环 如果未初始化则调用malloc_ consolidate后再进入unsorted bins大循环 largebin分配 : 大小范围: ≥0x400 如果既不在fastbin也不在smallbin范围内: 无fastchunks则直接进入unsorted bins大循环 有fastchunks则调用malloc_ consolidate后再进入unsorted bins大循环 1.2 malloc_ consolidate函数 功能: 合并fastbin中的chunk并放入unsorted bin 与top chunk合并的chunk除外 流程: 遍历fastbinY数组(每个元素是单向链表头部) 检查prev inuse: 为0则unlink prev chunk 为1则检查next chunk 检查next chunk: 如果是top chunk则与之合并 否则检查next inuse: 为0则unlink next chunk 为1则不做操作 将合并后的chunk插入unsorted bins 循环直到fastbinY为空 1.3 unsorted bins大循环 遍历unsorted bin寻找满足条件的chunk: 大小刚好合适则返回 在small bin范围内则放入small bin large bin为空则放入large bin 其他情况从large bin尾部寻找合适位置 切割机制: 如果没有合适大小的free chunk 检查是否有大的free chunk可以切割(除fastbins外) 切割后的剩余部分成为last remainder并放入unsortedbin 1.4 free函数 释放流程: 检查能否放入fastbin 检查能否进行后向合并与unlink prev chunk 检查能否和top chunk合并 检查能否进行前向合并与unlink next chunk 放入unsorted bin头部 进行一系列安全检查 安全检查: 检查chunk大小是否小于max fast 防止fastbin double free 检查chunk是否是mmaped 检查当前chunk是否是inuse状态 2. 关键概念 2.1 基本概念 bins链表 : 使用头插法 fd和bk只在bins中存在 指向chunk头部而非mem区域 chunk关系 : prev chunk: 地址较低的chunk next chunk: 地址较高的chunk tcache : 大小范围: 0x20-0x410 高版本glibc中,tcache bin满后再free相同大小的chunk会尝试unlink 2.2 unlink操作 目的: 从双向链表中取出空闲块(如free时合并相邻free chunk) 检查缺陷: fd/bk指针通过与chunk头部的相对地址查找 可用于绕过安全检查 特殊情况: chunk大小 <0x80时直接进入tcache,不参与unlink unlink后的overlapping chunk都会进入unsorted bin 2.3 常见漏洞 UAF(Use After Free) : 条件: free后未置NULL,紧接着申请相同大小内存 利用: 操作系统会重新分配刚free的内存 chunk extend/overlapping : 条件: 可控制chunk header数据(常结合off-by-one使用) 方法: 修改size字段后free,导致next chunk被overlapping 作用: 控制chunk内容而非执行流程 off-by-one/off-by-null : 允许修改相邻chunk的size字段 常用于构造chunk overlapping 3. 利用技巧 3.1 信息泄露 泄露heap base : 通常为修改tcache_ perthread_ struct 方法: 让tcache结构变成1->0,通过show函数泄露 泄露libc base : 通过unsortedbin特性泄露 方法: 获取unsortedbin chunk show出main_ arena附近地址 计算偏移得到libc base 替代方法: 利用largebin同时泄露libc和heap 打__ IO_ 2_ 1_ stdout泄露 利用fd/bk写入特性 3.2 常见攻击目标 __ free_ hook : 通过tcache poison修改 常用gadget: system或one_ gadget tcache_ perthread_ struct : 修改counts数组可控制tcache分配 libc2.30以下: counts类型为char libc2.30及以上: counts类型为uint16_ t mp_ 结构体 : 通过large bin attack修改mp_ .tcache_ bins 使large bin chunk进入tcache stdout/ IO_ 2_ 1_ stdout : 用于泄露信息或FSOP 可泄露出_ environ获取栈地址 3.3 特殊技巧 scanf触发malloc_ consolidate : 输入长字符串会调用malloc分配内存 可用于合并fastchunks到unsorted bin calloc绕过tcache : calloc不从tcache分配 可用于绕过tcache相关保护 environ变量利用 : 储存系统环境变量地址 通过libc找到environ地址后可泄露栈地址 magic gadget : 如setcontext+53等 用于控制执行流 4. 保护机制与绕过 4.1 glibc版本差异 glibc-2.32 : tcache/fastbin堆指针异或加密 堆内存对齐检查 glibc-2.33 : tcachebin链数量检查 glibc-2.34 : 移除__ malloc_ hook和__ free_ hook 引入tcache_ key检查 glibc-2.36 : 移除IO处理函数 glibc-2.37 : 移除__ malloc_ assert函数 global_ max_ fast类型改为uint8_ t 4.2 绕过技巧 异或加密绕过 : 泄露heap base计算加密key libc2.31: tcache-key为heapbase+0x10 检查绕过 : libc2.31不对tcache 0x10对齐检查 利用large bin attack修改检查条件 hook移除后的利用 : 转向FSOP或IO_ FILE攻击 使用house of apple/cat等新技术 5. 高级利用技术 5.1 House of系列攻击 House of Orange : 修改top chunk size 分配大chunk使top进入unsorted bin unsorted bin attack修改_ IO_ list_ all 布置FAKE FILE进行FSOP House of Pig : 利用_ IO_ str_ overflow的malloc/memcpy/free三连 设置参数使free_ hook被覆盖为system 需要exit函数触发_ IO_ flush_ all_ lockp House of Kiwi : 触发__ malloc_ assert 修改_ IO_ file_ jumps和IO_ helper_ jumps 无需exit函数 House of Emma : 伪造_ IO_ cookie_ file 劫持pointer guard libc2.34及以下可用 House of Cat : 在_ IO_ switch_ to_ wget_ mode设置rdx 调用setcontext+61进行ORW 需要控制rcx不为0 House of Apple2 : 覆盖vtable为_ IO_ wxxx_ jumps 执行_ IO_ wfile_ overflow 利用magic gadget 5.2 IO_ FILE利用 FSOP(File Stream Oriented Programming) : 劫持_ IO_ list_ all伪造链表 触发_ IO_ flush_ all_ lockp 调用vtable中的_ IO_ overflow 关键结构 : _ IO_ FILE: 文件流基础结构 _ IO_ FILE_ plus: 包含vtable _ IO_ jump_ t: 虚函数表 _ IO_ wide_ data: 宽字符数据 利用条件 : 控制_ IO_ list_ all _ lock设置为可写地址 _ mode=0 _ IO_ write_ ptr > _ IO_ write_ base 常用目标 : _ IO_ list_ all IO_ 2_ 1_ stderr stderr 6. 实战技巧 6.1 调试技巧 关键断点 : 符号表问题 : 从glibc-all-in-one获取有符号表的同版本libc 便于pwndbg调试 6.2 利用模板 House of Apple2利用 : 爆破模板 : 一字节覆盖泄露libc : 7. 总结 利用选择 : libc2.31以下: 优先打tcache和hook libc2.34以下: 可用house of kiwi/emma libc2.35+: 用house of apple2/cat 关键思路 : 无UAF时考虑off-by-one构造overlapping 无edit功能时通过overlapping实现等效功能 限制多时考虑tcache_ perthread_ struct攻击 根据保护机制选择合适利用技术 发展趋势 : 从hook转向IO_ FILE利用 从直接控制执行流转向SROP/ORW 适应glibc新增保护机制