2025CISCN&长城杯半决赛 PWN typo详细题解
字数 1167 2025-08-30 06:50:35

2025CISCN&长城杯半决赛 PWN typo 详细题解

漏洞分析

程序功能

程序提供了三个主要功能:

  1. add - 分配堆块
  2. free - 释放堆块
  3. edit - 编辑堆块内容

漏洞位置

漏洞存在于edit功能中:

  • 可以读入0x100个字节到栈上
  • 使用snprintf函数将栈上的数据复制到堆块中
  • 存在堆溢出漏洞,但snprintf会被\x00截断

关键绕过技术

为了绕过\x00截断问题,可以使用格式化字符串技巧:

  • 将payload中的\x00替换为%n$p(例如%39$c
  • 寻找偏移为n且数据为0的位置
  • snprintf解析时会输出0到原来\x00的位置,从而绕过截断
def replace(payload):
    return payload.replace(b'\x00',b'%39$c')+b'\x00'

利用思路

1. 泄露libc地址

由于程序保护全开且没有show功能,需要:

  1. 利用堆溢出合并一个可以进入unsorted bins的堆块
  2. 在合并前保留一个小堆块在tcache bins中
  3. 修改main_arena的libc地址最后两位为stdout地址(远程需要爆破)
  4. 获取libc基址

2. getshell

  1. 将合并的堆块恢复回去
  2. 通过修改其中一个堆块的fd的size
  3. 利用两次修改:
    • 第一次修改后面堆块的fd为free_hook
    • 第二次修改为/bin/sh
  4. 最终执行free触发free_hook执行system("/bin/sh")

详细利用步骤

堆块合并

  1. 创建特定大小的堆块布局
  2. 利用堆溢出修改关键size字段
  3. 触发合并操作使特定堆块进入unsorted bins

泄露libc地址

  1. 使2号堆块同时位于tcache bins和unsorted bins中
  2. 修改为stdout-8(因为edit的读入在bk位)
  3. 通过特定操作泄露libc基址

修改tcache bins

  1. 修改一个size字段为特定值
  2. 修改tcache bins中堆块的fd为free_hook-8
  3. 分配并写入/bin/sh字符串
  4. 修改free_hook为system地址

EXP编写要点

  1. 使用格式化字符串绕过\x00截断
  2. 精心构造堆布局
  3. 处理远程爆破情况(stdout地址最后几位)
  4. 分阶段完成libc泄露和最终利用

调试技巧

  1. 使用gdb观察堆块合并过程
  2. 检查unsorted bins和tcache bins状态
  3. 验证libc地址泄露是否正确
  4. 确认free_hook覆盖成功

总结

这道题结合了堆溢出和格式化字符串的技巧,关键点在于:

  • 利用snprintf的特性绕过\x00截断
  • 通过堆布局控制实现libc地址泄露
  • 利用tcache poisoning修改free_hook
  • 需要精确控制堆块的大小和位置关系

通过这种多阶段利用方式,可以在保护全开且没有直接信息泄露功能的情况下完成利用。

2025CISCN&长城杯半决赛 PWN typo 详细题解 漏洞分析 程序功能 程序提供了三个主要功能: add - 分配堆块 free - 释放堆块 edit - 编辑堆块内容 漏洞位置 漏洞存在于 edit 功能中: 可以读入0x100个字节到栈上 使用 snprintf 函数将栈上的数据复制到堆块中 存在堆溢出漏洞,但 snprintf 会被 \x00 截断 关键绕过技术 为了绕过 \x00 截断问题,可以使用格式化字符串技巧: 将payload中的 \x00 替换为 %n$p (例如 %39$c ) 寻找偏移为n且数据为0的位置 snprintf 解析时会输出0到原来 \x00 的位置,从而绕过截断 利用思路 1. 泄露libc地址 由于程序保护全开且没有show功能,需要: 利用堆溢出合并一个可以进入unsorted bins的堆块 在合并前保留一个小堆块在tcache bins中 修改main_ arena的libc地址最后两位为stdout地址(远程需要爆破) 获取libc基址 2. getshell 将合并的堆块恢复回去 通过修改其中一个堆块的fd的size 利用两次修改: 第一次修改后面堆块的fd为 free_hook 第二次修改为 /bin/sh 最终执行 free 触发 free_hook 执行system("/bin/sh") 详细利用步骤 堆块合并 创建特定大小的堆块布局 利用堆溢出修改关键size字段 触发合并操作使特定堆块进入unsorted bins 泄露libc地址 使2号堆块同时位于tcache bins和unsorted bins中 修改为 stdout-8 (因为edit的读入在bk位) 通过特定操作泄露libc基址 修改tcache bins 修改一个size字段为特定值 修改tcache bins中堆块的fd为 free_hook-8 分配并写入 /bin/sh 字符串 修改 free_hook 为system地址 EXP编写要点 使用格式化字符串绕过 \x00 截断 精心构造堆布局 处理远程爆破情况(stdout地址最后几位) 分阶段完成libc泄露和最终利用 调试技巧 使用gdb观察堆块合并过程 检查unsorted bins和tcache bins状态 验证libc地址泄露是否正确 确认 free_hook 覆盖成功 总结 这道题结合了堆溢出和格式化字符串的技巧,关键点在于: 利用 snprintf 的特性绕过 \x00 截断 通过堆布局控制实现libc地址泄露 利用tcache poisoning修改 free_hook 需要精确控制堆块的大小和位置关系 通过这种多阶段利用方式,可以在保护全开且没有直接信息泄露功能的情况下完成利用。