VulnScan:自动化内存损坏问题的分类与根因分析

微软安全响应中心开发的VulnScan工具,利用WinDbg和时间旅行调试技术,自动分析内存损坏漏洞的根因,支持越界读写、释放后使用、类型混淆等常见问题,显著提升漏洞处理效率。

VulnScan – 自动化内存损坏问题的分类与根因分析

微软安全响应中心(MSRC)接收关于我们产品中潜在漏洞的报告,我们的工程团队负责评估这些问题的严重性、影响和根因。实际上,这些报告中很大一部分是内存损坏问题。为了根因分析这些问题,MSRC安全工程师通常需要分析崩溃并尝试理解出错原因。这种工作流程不仅适用于外部报告的漏洞;通过模糊测试和变体调查内部发现的漏洞通常也是内存损坏问题,这些也需要进行分类和可利用性评估。

因此,MSRC多年来投入了大量资源来构建工具,以帮助我们自动化根因分析过程。VulnScan是MSRC设计和开发的一个工具,旨在帮助安全工程师和开发者确定内存损坏漏洞的漏洞类型和根因。它建立在两个内部开发的工具之上:Windows调试工具(WinDbg)和时间旅行调试(TTD)。

WinDbg是微软的Windows调试器,最近进行了用户界面改造,使其更易于使用。您可以在此处找到有关新WinDbg预览版本的更多信息。 时间旅行调试是一个内部开发的框架,用于记录和重放Windows应用程序的执行。该技术在CPPCon 2017期间发布。

通过利用WinDbg和TTD,VulnScan能够自动推断最常见类型的内存损坏问题的根因。应用程序验证器的PageHeap机制用于在更接近问题根因的位置触发访问违规。分析从崩溃位置开始,并向根因推进。VulnScan支持的内存损坏问题类别:

越界读/写

无效指针值被追踪回其起源。如果起源指向有效分配,并且指针随后变得无效,VulnScan尝试确定哪条指令进行了更改以及原因。 这也意味着该工具可以检测整数溢出和下溢,以及由错误循环计数器值引起的基本越界访问。

释放后使用

访问违规时无效指针的值用于反向查找,以识别执行时间线中无效指针变为有效的点。从这一点开始,VulnScan对应用程序代码进行正向跟踪,跟踪所有内存释放操作以确定指针在何处被释放。 在选择上述方法之前,我们尝试了几种技术。最初所有内存分配和释放都被记录,但这非常耗费资源和时间。它还对其他错误的分类速度产生了负面影响,因为即使对于非释放后使用错误,也会准备堆对象映射。这种方法使我们能够在未启用PageHeap的情况下分类释放后使用错误。它仍然可以使用,但默认情况下禁用。

类型混淆

对于这种漏洞类型,该工具使用启发式方法检查指针大小和对齐是否一致。如果在反向执行流中污染的指针值被相同大小的值部分覆盖(未对齐的结构成员内存写入)或用不同大小的值修改,则可能表示类型混淆漏洞(不同的结构成员类型)。 类型混淆错误的一个示例分类可以在本博客文章的下一部分找到。

未初始化内存使用

通过在内存的读取地址插入内存断点来验证每个内存读取操作的初始化。然后代码反向运行到写入点。如果写入操作缺失,我们向用户报告未初始化内存使用并继续分析。 未初始化内存指针的示例分类:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[*]     当前指令:cmp         qword ptr [r8+00000558h],rax
[*]     当前位置:0x2B3DC0000001
[*]     源内存值:0x2390E31B940
[*]     污染回寄存器:r8
[*]     寄存器值:0x0
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         r8,qword ptr [rcx+00000410h] <- 未初始化内存
[*]     当前位置:0x2b3d80000144
[*]     源有效地址:0x2417f9a2690
[*]     源内存值:0x0
[*]     ----------------------------------------------------------------------
[*]     检测到未初始化堆对象漏洞!!!

空/常量指针解引用

VulnScan中的多分支污染引擎将所有值追踪回其初始化。如果所有分支都导致空或常量值而未修改,我们向用户报告空或常量指针解引用。 空指针解引用错误的示例分类:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[*]     当前指令: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、Microsoft Internet Explorer和Microsoft Office产品的所有内存损坏问题。其成功率约为85%,为MSRC工程师节省了估计500小时的工程时间。

案例研究 – 分类类型混淆错误(CVE-2017-0134)

借助时间旅行调试(TTD),我们可以在代码执行时间线的两个方向上探索代码。我们使用污染技术跟踪寄存器更改,并使用内存断点跟踪内存写入。污染过程中的每条指令都在先前执行的指令上下文中进行分析,以找到问题的可能根因并确定错误类别。 VulnScan污染分析是多分支的,这意味着它可以顺序跟踪从单条指令获得的所有值。VulnScan有一个与执行时间线中特定位置关联的寄存器和内存地址队列。污染分析对每个分支单独执行。使用这种技术,可以完全重建应用程序数据流。随着时间的推移,我们进行了一些简化和优化以加速分析过程。以下分析是一个简单示例,仅用于突出工具的基本概念和能力。 该示例来自Jordan Rabet(Microsoft攻击性安全研究团队)提交给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)导致常量和空值,但无论如何调查它们以确保我们没有错过任何重要细节。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
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  V888
   YP    ~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
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         r11d,r8d
[*]     当前位置:0x2CFA8000013E
[*]     污染回寄存器:r8d
[*]     寄存器值:0xA
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         r8d,r9d
[*]     当前位置:0x2CFA8000013A
[*]     污染回寄存器:r9d
[*]     寄存器值:0xA
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         r9d,dword ptr [rdi+rax*4+18h]
[*]     当前位置:0x2CFA8000012C
[*]     源有效地址:0x2967D8B4898
[*]     源内存值:0xA
[*]     内存初始化 @TTTPos: 49454400930092。
[*]     内存已初始化!
[*]     污染回内存:0x2967D8B4898
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         qword ptr [rax],rcx
[*]     当前位置:0x2CC280001D5A
[*]     源内存值:0x140000000A
[*]     检测到指针大小不匹配!
[*]     污染回寄存器:rcx
[*]     寄存器值:0x140000000A
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         rcx,qword ptr [rdx]
[*]     当前位置:0x2CC280001D59
[*]     源有效地址:0x2967E1B4070
[*]     源内存值:0x140000000A
[*]     内存初始化 @TTTPos: 49213882768729。
[*]     内存已初始化!
[*]     污染回内存:0x2967E1B4070
[*]     ----------------------------------------------------------------------
[*]     当前指令:movups      xmmword ptr [rcx-10h],xmm0
[*]     当前位置:0x2C68400005CB
[*]     源内存值:0x140000000A
[*]     污染回寄存器:xmm0
[*]     寄存器值:0x140000000A
[*]     ----------------------------------------------------------------------
[*]     当前指令:movups      xmm0,xmmword ptr [rdx+rcx]
[*]     当前位置:0x2C68400005C7
[*]     源有效地址:0x2967D713D30
[*]     源内存值:0x140000000A
[*]     内存初始化 @TTTPos: 48826261964231。
[*]     内存已初始化!
[*]     污染回内存:0x2967D713D30
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         dword ptr [rax+8],ecx
[*]     当前位置:0x2C4A80000537
[*]     源内存值:0x14
[*]     检测到指针大小不匹配!
[*]     污染回寄存器:ecx
[*]     寄存器值:0x14
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         ecx,dword ptr [rdx+8]
[*]     当前位置:0x2C4A80000535
[*]     源有效地址:0x2967E1BC078
[*]     源内存值:0x14
[*]     内存初始化 @TTTPos: 48698486687029。
[*]     内存已初始化!
[*]     污染回内存:0x2967E1BC078
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         dword ptr [rbx+rcx*4+4],eax
[*]     当前位置:0x2C4A800004E5
[*]     源内存值:0x14
[*]     污染回寄存器:eax
[*]     寄存器值:0x14
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         eax,dword ptr [rbp+18h]
[*]     当前位置:0x2C4A800004E0
[*]     源有效地址:0x2967DDB9AA8
[*]     源内存值:0x14
[*]     内存初始化 @TTTPos: 48698486686944。
[*]     内存已初始化!
[*]     污染回内存:0x2967DDB9AA8
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         dword ptr [rax+18h],ebp
[*]     当前位置:0x2A8C80001858
[*]     源内存值:0x14
[*]     污染回寄存器:ebp
[*]     寄存器值:0x14
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         ebp,edx
[*]     当前位置:0x2A8C80001827
[*]     污染回寄存器:edx
[*]     寄存器值:0x14
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         edx,dword ptr [rdi+000000E0h]
[*]     当前位置:0x2A8C8000181F
[*]     源有效地址:0x99C17FEE00
[*]     源内存值:0x14
[*]     内存初始化 @TTTPos: 46782931277855。
[*]     内存已初始化!
[*]     污染回内存:0x99C17FEE00
[*]     ----------------------------------------------------------------------
[*]     当前指令:mov         dword ptr [rax],edx
[*]     当前位置:0x2A8C80001738
[*]     源内存值:0x14
[*]     污染回寄存器:edx
[*]     寄存器值:0x14
[*]     ----------------------------------------------------------------------
[*]     当前指令:cvttsd2si   edx,xmm1
[*]     当前位置:0x2A8C80001728
[*]     污染回寄存器:xmm
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计