VulnScan – 内存损坏问题的自动化分类与根因分析
微软安全响应中心(MSRC)负责接收产品潜在漏洞报告,工程团队需评估问题的严重性、影响和根本原因。实践中,大部分报告涉及内存损坏问题。MSRC安全工程师通常需要分析崩溃并理解错误原因,这一流程同样适用于通过模糊测试和变种调查发现的内部漏洞。
为此,MSRC多年投入开发自动化根因分析工具。VulnScan是MSRC设计的工具,帮助安全工程师和开发者确定内存损坏漏洞的类型和根本原因。它基于两个内部工具构建:Windows调试工具(WinDbg)和时间旅行调试(TTD)。
WinDbg是微软的Windows调试器,近期界面更新使其更易用。TTD是内部开发的记录和重放Windows应用程序执行的框架,该技术于2017年CPPCon大会发布。
通过结合WinDbg和TTD,VulnScan能自动推断最常见内存损坏问题的根本原因。应用验证器的PageHeap机制用于在接近问题根因时触发访问违规。分析从崩溃位置开始,向根因推进。VulnScan支持的内存损坏问题类型包括:
越界读/写
无效指针值被追溯至其起源。如果起源指向有效分配且指针随后无效,VulnScan尝试确定更改指令及原因。这意味着工具能检测整数溢出和下溢,以及由错误循环计数器引起的越界访问。
释放后使用
访问违规时的无效指针值用于反向查找,确定执行时间线中指针变为有效的点。从此点开始,VulnScan正向跟踪应用代码,追踪所有内存释放操作以确定指针释放位置。
在选择上述方法前,我们实验了多种技术。最初记录所有内存分配和释放,但这非常消耗资源和时间,也拖慢其他错误的分类速度,因为即使非释放后使用错误也会准备堆对象映射。此方法允许我们在未启用PageHeap时分类释放后使用错误。它仍可使用,但默认禁用。
类型混淆
对于此漏洞类型,工具使用启发式方法检查指针大小和对齐是否一致。如果在反向执行流中,污染指针值被相同大小的值部分覆盖(未对齐的结构成员内存写入)或被不同大小的值修改,可能表明类型混淆漏洞(不同结构成员类型)。
类型混淆错误的示例分析见下文博客案例研究。
未初始化内存使用
通过在内读取地址插入内存断点,验证每次内存读取操作是否初始化。然后代码反向运行至写入点。如果缺少写入操作,我们向用户报告未初始化内存使用并继续分析。
未初始化内存指针的示例分析:
[*] 当前指令:cmp qword ptr [r8+00000558h],rax
[*] 当前位置:0x2B3DC0000001
[*] 源内存值:0x2390E31B940
[*] 污染回溯寄存器:r8
[*] 寄存器值:0x0
[*] ----------------------------------------------------------------------
[*] 当前指令:mov r8,qword ptr <b style="color: orange">[rcx+00000410h]</b> <- 未初始化内存
[*] 当前位置:0x2b3d80000144
[*] 源有效地址:0x2417f9a2690
[*] 源内存值:0x0
[*] ----------------------------------------------------------------------
[*] 检测到未初始化堆对象漏洞!!!
空/常量指针解引用
VulnScan中的多分支污染引擎追踪所有值至其初始化。如果所有分支回溯至未修改的空或常量值,我们向用户报告空或常量指针解引用。
空指针解引用错误的示例分析:
[*] 当前指令:test byte ptr [rcx+4Ch],1
[*] 当前位置:0x6328B80000001
[*] 源内存值:0x1
[*] 污染回溯寄存器:rcx
[*] 寄存器值:0x0
[*] ----------------------------------------------------------------------
[*] 当前指令:mov rcx,qword ptr [rcx+20h]
[*] 当前位置:0x6328B4000014E
[*] 源有效地址:0x1E3A54FDC20
[*] 源内存值:0x0
[*] 内存已初始化 @TTTPos: 1744423515849038。
[*] 内存已初始化!
[*] 污染回溯内存:0x1E3A54FDC20
[*] ----------------------------------------------------------------------
[*] 当前指令:mov qword ptr [rbx+20h],rax
[*] 当前位置:0x6327FC00002AE
[*] 源内存值:0x0
[*] 污染回溯寄存器:rax
[*] 寄存器值:0x0
[*] ----------------------------------------------------------------------
[*] 当前指令:xor eax,eax
[*] 当前位置:0x6327FC00002AD
[*] 污染寄存器被清零!
[*] ----------------------------------------------------------------------
MSRC将VulnScan用作自动化框架Sonar的一部分。Sonar自动处理所有支持平台和软件版本的外部报告概念验证文件,用于复现和执行根因分析。为此,我们采用多种不同环境,并尝试不同配置多次复现问题。
VulnScan计划纳入Microsoft安全风险检测服务(Project Springfield),用于重复崩溃去重和提供通过模糊测试发现的漏洞的扩展分析。
在10个月期间,VulnScan用于分类Microsoft Edge、Internet Explorer和Microsoft Office产品的所有内存损坏问题,成功率约85%,为MSRC工程师节省约500小时工程时间。
案例研究 – 分类类型混淆错误(CVE-2017-0134)
借助时间旅行调试(TTD),我们可以在代码执行时间线的两个方向探索代码。我们使用污染技术跟踪寄存器更改,使用内存断点跟踪内存写入。污染过程中的每条指令都在先前执行指令的上下文中分析,以找到问题的可能根本原因并确定错误类别。
VulnScan污染分析是多分支的,意味着它可以顺序跟踪从单个指令获得的所有值。VulnScan有一个与执行时间线中特定位置关联的寄存器和内存地址队列。污染分析对每个分支单独执行。使用此技术,可以完整重建应用数据流。随时间推移,我们进行了一些简化和优化以加速分析过程。以下分析是一个简单示例,仅突出工具的基本概念和能力。
示例来自Jordan Rabet(微软进攻性安全研究团队)提交给MSRC的Chakra漏洞。
跟踪中的重要位置:
- 位置0x2D0780000001:访问违规位置。地址(0xA0000000A)通过mov指令解引用,未指向有效内存位置。我们通过从此指针计算中使用的寄存器(rcx)反向污染开始分析。
- 位置0x2CFA8000014D:启发式首次触发。这可能是此分析的最重要点。无效指针值作为64位值回溯至此点,但它在内存写入操作中作为32位值使用。启发式在分析中多次触发,但这些不重要,因为它们不影响我们在访问违规位置看到的无效指针值。
- 位置0x1D420000037E至0x1D40400000A7:污染值在这些位置之间更改。由于这是由NtReadFile系统调用外部设置的,意味着攻击者可能控制该值。进一步回溯显示内存设置为PageHeap特定常量值,这也表明我们正在处理堆分配。
调用栈:
00 ch!memcpy <- 位置0x1D420000037E
01 ch!memcpy_s
02 ch!_fread_nolock_s <- 系统调用
03 ch!fread_s
04 ch!fread
05 ch!Helpers::LoadScriptFromFile
...
0n <- 位置0x1D40400000A7
- 位置0x2A8C80001709:主分支污染分析在此结束。解引用地址(0x7FFC239B2358)是ChakraCore二进制文件中的只读全局变量。从此点执行其他分支(称为连接点)的分析。分析将在下一个分支继续,因为指令是目标操作数中寄存器的算术操作。
此操作在源代码中由dbl *= g_rgdblTens[lwExp]表示,其中g_rgdblTens是全局变量。
其他分支(位置0x2A8C800016F9和位置0x1D404000001A)导致常量和空值,但仍值得调查以确保不错过任何重要细节。
db db db db db d8b db .d8888. .o88b. .d8b. d8b db
88 88 88 88 88 888o 88 88' YP d8P Y8 d8' `8b 888o 88
Y8 8P 88 88 88 88V8o 88 `8bo. 8P 88ooo88 88V8o 88
`8b d8' 88 88 88 88 V8o88 `Y8b. 8b 88~~~88 88 V8o88`8bd8' 88b d88 88booo. 88 V888 db 8D Y8b d8 88 88 88 V888YP ~Y8888P' Y88888P VP V8P `8888Y' `Y88P' YP YP VP V8P[*] 加载跟踪。
[*] 在跟踪文件中找到异常!
[*] 当前指令:mov rax,qword ptr [rcx+8]
[*] 当前位置:<b style="color: red">0x2D0780000001</b>
[*] 源有效地址:0xA0000000A
[*] 污染回溯寄存器:rcx
[*] 寄存器值:0xA00000002
[*] ----------------------------------------------------------------------
[*] 当前指令:mov rcx,qword ptr [rsp+00000088h]
[*] 当前位置:0x2D0740000FE7
[*] 源有效地址:0x99C17FDCF8
[*] 源内存值:0xA00000002
[*] 内存已初始化 @TTTPos: 49509161766887。
[*] 内存已初始化!
[*] 污染回溯内存:0x99C17FDCF8
[*] ----------------------------------------------------------------------
[*] 当前指令:mov qword ptr [r15],rax
[*] 当前位置:0x2D0740000FD0
[*] 源内存值:0xA00000002
[*] 污染回溯寄存器:rax
[*] 寄存器值:0xA00000002
[*] ----------------------------------------------------------------------
[*] 当前指令:mov rax,qword ptr [rcx+18h]
[*] 当前位置:0x2D0740000FCC
[*] 源有效地址:0x2967D8CC0C0
[*] 源内存值:0xA00000002
[*] 内存已初始化 @TTTPos: 49509161766860。
[*] 内存已初始化!
[*] 污染回溯内存:0x2967D8CC0C0
[*] ----------------------------------------------------------------------
[*] 当前指令:mov dword ptr [r10+rax*4+18h],r11d
[*] 当前位置:<b style="color: orange">0x2CFA8000014D</b>
[*] 源内存值:0xA
<b style="color: orange">[*] 检测到指针大小不匹配!</b>
[*] 污染回溯寄存器:r11d
[*] 寄存器值:0xA
[*] ----------------------------------------------------------------------
...(详细分析日志继续)...
<b style="color: orange">[*] 检测到类型混淆漏洞!!!</b>
[*] 加载符号。
[*] 构建输出。
[*] 将发现写入文件:n:\CVE-2017-0134\ch.run.html
[*] 分析在00:01:08内完成
此初始输出提供错误的汇编语言分析。VulnScan然后生成更详细的报告,包含寄存器值、源代码、局部变量和调用栈。这帮助产品开发者提供准确全面的修复。
使用两个报告获得的数据,我们可以开始调查崩溃位置和触发启发式之间的源代码。我们可以观察到,用作指针的值在Js::JavascriptArray::DirectSetItemInLastUsedSegmentAt中设置为数组元素,并来自Js::JavascriptArray::EntryConcat函数。Jordan找到一种方法,通过在IntArray对象的属性上使用自定义getter,将数组类型更改为VarArray。函数JavascriptArray::ConcatIntArgs(如报告中调用栈所示)和JavascriptArray::ConcatFloatArgs使用数组对象的Symbol.isConcatSpreadable属性,并且是该符号上的自定义getter,可用于更改数组类型。这导致在类型更改后,连接的IntArray项被写入VarArray而不是IntArray,从而引起数组对象损坏。此问题的修复在此ChakraCore提交中引入。
今天的内容到此为止。如果您想了解更多关于此工具及其使用的启发式和污染技术,请留下反馈。我们的下一步高度依赖社区响应。该工具经常更新,添加Microsoft内部工具用户请求的新启发式和功能。
感谢MSRC英国团队的反馈和想法,Jordan Rabet发现的错误,Steven Hunter、Matt Miller和Gavin Thomas帮助撰写此博客文章。还应赞扬WinDbg、TTD、Sonar和Microsoft安全风险检测团队开发的惊人工具。
Mateusz Krzywicki来自微软安全响应中心(英国)。
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
公众号二维码

