[翻译] 使用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功能

  1. 调用DedicatedMain启动服务器
  2. Patch engine.so中的NET_CloseAllSockets使其跳转到startpoint()
  3. 调用forkserver()供AFL fork
  4. 调用CModelLoader::GetModelForName加载指定地图
  5. 快速退出

4.2 关键共享库

  • engine.so: 主要Source引擎代码(含BSP解析)
  • dedicated.so: 专用服务器实现
  • libtier0.so: Steam/应用管理相关

4.3 补丁说明

  • 需要根据服务器版本调整偏移量
  • 使用Python脚本自动打补丁

5. AFL配置与修改

5.1 AFL修改点

  1. 强制输入文件以.bsp结尾
  2. 添加AFL_ENTRY_POINT环境变量指定fork服务器启动点
  3. 增加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 分类方法

  1. 基于调用栈去重
  2. 使用Valgrind检查每个样本
  3. 搜索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. 经验总结

  1. AFL QEMU模式:灵活适用于小范围代码测试,配合wrapper效果更佳
  2. 输入文件大小:关键因素,从300KB降到16KB带来5倍性能提升
  3. 漏洞分类:对于未测试过的代码,分类至关重要
  4. 堆内存损坏:Valve认为没有完整利用程序的堆漏洞不予修复(WONTFIX)
  5. 逆向辅助:泄露的源码极大帮助了逆向工程

9. 扩展建议

  1. 尝试对Windows客户端进行模糊测试
  2. 探索其他Source引擎游戏的BSP解析器
  3. 开发自动化分类工具提高效率
  4. 研究更精确的漏洞利用链构建方法

10. 参考资料

  1. 原始文章:先知社区《使用AFL对CS:GO进行模糊测试》
  2. 参考项目:https://github.com/niklasb/bspfuzz
  3. Source引擎2007泄露代码:https://github.com/VSES/SourceEngine2007
使用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 服务器加载测试 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 运行命令 5.3 性能数据 Ryzen 7 1800X处理器 平均每线程每秒50次执行 建议使用多进程并行fuzz 6. 漏洞分类与分析 6.1 分类方法 基于调用栈去重 使用Valgrind检查每个样本 搜索 Invalid write 模式 6.2 分析步骤 6.3 逆向辅助 使用泄露的源码辅助逆向 标记BSP解析代码符号 验证漏洞在Windows客户端上的表现 7. 示例漏洞分析 7.1 CVirtualTerrain::LevelInit堆溢出 漏洞位置: cmodel_disp.cpp 根本原因: dphysdisp_t::numDisplacements 可大于 g_DispCollTreeCount Release版本缺少assert检查 攻击者可控制 m_dispHullOffset 缓冲区 7.2 漏洞代码片段 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