CISCN&CCB25半决赛pwn题解
字数 1366 2025-08-29 08:29:59
CISCN&CCB25半决赛PWN题解 - 堆溢出漏洞分析与利用
题目概述
这是一道来自CISCN&CCB25半决赛的PWN题目,主要考察堆溢出漏洞的利用。题目实现了一个基于protobuf协议的程序,提供了增删查改四个功能,存在堆溢出漏洞,最终目标是获取shell。
漏洞分析
1. 程序交互与protobuf结构
程序使用protobuf协议进行通信,关键结构定义如下:
syntax = "proto2";
message devicemsg{
required int32 option = 1; // 功能选项
required int32 chunk_sizes = 2; // 堆块大小
required int32 heap_chunks_id = 3; // 堆块ID
required bytes heap_content = 4; // 堆内容
}
交互注意事项:
- 程序首先读取4字节作为payload长度
- 后续payload会被解析为protobuf结构
- 需要特别注意
chunk_sizes和实际堆块大小的区别
2. 漏洞点定位
主要漏洞存在于edit功能中:
v2 = **((_QWORD **)&heaplist + v1); // 获取堆块size
read(0, s, 0x100uLL);
snprintf(*((char **)&heaplist + v1), (size_t)"%lu", s, 8LL); // 溢出点
漏洞细节:
- 可以写入0x100字节数据到堆上
- 能够覆盖相邻堆块的元数据,特别是size字段
- 通过控制size字段可以实施后续攻击
3. 功能分析
程序提供四个主要功能:
- add - 分配堆块
- delete - 释放堆块
- edit - 编辑堆块(存在溢出)
- show - 显示堆块内容
漏洞利用步骤
1. 泄露libc地址
- 分配两个相邻堆块
- 使用edit功能溢出第一个堆块,覆盖第二个堆块的size字段
- 释放被修改size的堆块,使其进入unsorted bin
- 通过show功能泄露unsorted bin中的fd指针(指向main_arena)
2. 泄露堆地址
- 再次利用堆溢出修改unsorted bin的fd指针
- 通过特定布局使堆地址被包含在可读内存中
- 使用show功能泄露堆地址
3. Tcache攻击
- 使用堆溢出修改tcache的fd指针
- 通过tcache poisoning攻击tcache perthread结构
- 控制tcache的counters来操纵堆分配
4. 攻击IO结构体
- 伪造堆块size为0x1e1
- 通过tcache攻击申请到伪造的堆块
- 控制堆块数量为7后释放,使libc地址落入堆块fd位
- 修改fd指向stdout结构体上方
- 爆破倒数第四位地址
- 修改stdout结构体的flags为0xfbad1800
- 覆盖write_base低位以泄露libc地址
5. 获取shell
- 再次使用tcache攻击,这次目标是__free_hook
- 申请free_hook-8的堆块以便写入
- 将__free_hook覆盖为system地址
- 释放一个包含"/bin/sh"的堆块获取shell
关键技术点
- 堆溢出控制:精确控制溢出数据以修改相邻堆块的size和fd指针
- tcache攻击:利用tcache poisoning攻击tcache perthread结构
- IO结构体攻击:通过修改stdout结构体泄露libc地址
- 地址爆破:需要爆破倒数第四位地址以精确控制目标位置
- protobuf交互:正确构造protobuf消息与程序交互
防御措施
- 增加堆块间的保护机制(如canary)
- 对用户输入的size进行严格校验
- 使用安全的字符串拷贝函数替代snprintf
- 及时更新libc版本以利用新的防护机制
总结
这道题目综合考察了堆溢出、tcache攻击和IO结构体攻击等技术,需要选手对glibc堆管理机制有深入理解。通过精确控制堆布局和利用多种攻击技术组合,最终实现任意代码执行。