[翻译] 使用AFL对CSGO进行模糊测试
字数 1824 2025-08-20 18:18:04
使用AFL对CS:GO进行模糊测试 - 详细教学文档
1. 背景介绍
本教学文档基于Anciety在先知社区分享的使用AFL对CS:GO进行模糊测试的经验。通过这种方法,作者在3天内发现了CS:GO中的3个远程可利用的栈相关漏洞和5个堆相关的内存损坏问题。
2. BSP文件格式与攻击面
2.1 BSP文件概述
- BSP代表Binary Space Partitioning(二进制空间分区)
- 是Source引擎(包括CS:GO)使用的地图文件格式
- 包含3D空间信息和其他游戏所需数据
- 客户端和服务器都需要处理BSP文件
2.2 攻击面分析
- 客户端在初始化地图时会从服务器下载BSP文件
- 解析器入口函数:
CModeLoader::Map_LoadModel - 共享解析代码存在于2007年泄露的Source引擎源代码中
- 解析器安全防护较弱,是理想的模糊测试目标
3. 模糊测试环境搭建
3.1 基本设置
- 目标:Linux服务器二进制文件而非客户端
- 参考项目:https://github.com/niklasb/bspfuzz
- 预期性能:核心每秒100次执行
3.2 地图文件优化
- 原始地图文件过大(约300KB)
- 编写脚本去除无用数据,保留文件结构完整性
- 优化后文件大小:<16KB
- 虽然不能完全加载,但能被
Map_LoadModel处理
3.3 服务器加载测试
$ LD_LIBRARY_PATH=`pwd`/bin ./srcds_linux -game csgo -console -usercon \
+game_type 0 +game_mode 0 +mapgroup mg_active +map test \
-nominidumps -nobreakpad
4. Wrapper编写与补丁
4.1 Wrapper功能
- 调用
DedicatedMain启动服务器 - Patch
engine.so中的NET_CloseAllSockets使其跳转到startpoint() - 调用
forkserver()供AFL fork - 调用
CModelLoader::GetModelForName加载指定地图 - 快速退出
4.2 关键共享库
engine.so: 主要Source引擎代码(含BSP解析)dedicated.so: 专用服务器实现libtier0.so: Steam/应用管理相关
4.3 补丁说明
- 需要根据服务器版本调整偏移量
- 使用Python脚本自动打补丁
5. AFL配置与修改
5.1 AFL修改点
- 强制输入文件以
.bsp结尾 - 添加
AFL_ENTRY_POINT环境变量指定fork服务器启动点 - 增加fork等待超时时间乘数
5.2 运行命令
$ export AFL_ENTRY_POINT=$(nm bspfuzz |& grep forkserver | cut -d' ' -f1)
$ export AFL_INST_LIBS=1
$ afl-fuzz -m 2048 -Q -i fuzz/in -o fuzz/out -- ./bspfuzz @@
5.3 性能数据
- Ryzen 7 1800X处理器
- 平均每线程每秒50次执行
- 建议使用多进程并行fuzz
6. 漏洞分类与分析
6.1 分类方法
- 基于调用栈去重
- 使用Valgrind检查每个样本
- 搜索
Invalid write模式
6.2 分析步骤
$ sudo sysctl -w kernel.randomize_va_space=0 # 关闭ASLR
$ cd /path/to/bspfuzz/triage
$ ./triage.sh
$ ./valgrind.sh
$ egrep 'Invalid write' -A1 valgrind/* | egrep at | perl -n -e '/.*at (0x[print "$1\n";'
6.3 逆向辅助
- 使用泄露的源码辅助逆向
- 标记BSP解析代码符号
- 验证漏洞在Windows客户端上的表现
7. 示例漏洞分析
7.1 CVirtualTerrain::LevelInit堆溢出
- 漏洞位置:
cmodel_disp.cpp - 根本原因:
dphysdisp_t::numDisplacements可大于g_DispCollTreeCount - Release版本缺少assert检查
- 攻击者可控制
m_dispHullOffset缓冲区
7.2 漏洞代码片段
void LevelInit( dphysdisp_t *pLump, int lumpSize )
{
if ( !pLump ) {
m_pDispHullData = NULL;
return;
}
int totalHullData = 0;
m_dispHullOffset.SetCount(g_DispCollTreeCount);
// [[1]] Assert在release版本中不存在
Assert(pLump->numDisplacements==g_DispCollTreeCount);
unsigned short *pDataSize = (unsigned short *)(pLump+1);
for ( int i = 0; i < pLump->numDisplacements; i++ ) {
if ( pDataSize[i] == (unsigned short)-1 ) {
m_dispHullOffset[i] = -1;
continue;
}
// [[2]] 当numDisplacements > g_DispCollTreeCount时发生溢出
m_dispHullOffset[i] = totalHullData;
totalHullData += pDataSize[i];
}
}
7.3 触发条件
- 构造
numDisplacements = 0xffff g_DispCollTreeCount = 2- 可导致
csgo.exe崩溃
8. 经验总结
- AFL QEMU模式:灵活适用于小范围代码测试,配合wrapper效果更佳
- 输入文件大小:关键因素,从300KB降到16KB带来5倍性能提升
- 漏洞分类:对于未测试过的代码,分类至关重要
- 堆内存损坏:Valve认为没有完整利用程序的堆漏洞不予修复(WONTFIX)
- 逆向辅助:泄露的源码极大帮助了逆向工程
9. 扩展建议
- 尝试对Windows客户端进行模糊测试
- 探索其他Source引擎游戏的BSP解析器
- 开发自动化分类工具提高效率
- 研究更精确的漏洞利用链构建方法
10. 参考资料
- 原始文章:先知社区《使用AFL对CS:GO进行模糊测试》
- 参考项目:https://github.com/niklasb/bspfuzz
- Source引擎2007泄露代码:https://github.com/VSES/SourceEngine2007