对多米诺行动所用JScript漏洞(CVE-2020-0968)的详细分析
字数 2218 2025-08-15 21:33:28
JScript漏洞(CVE-2020-0968)分析与利用技术详解
一、漏洞背景
多米诺行动(Operation Domino)中使用的JScript漏洞是一个未被公开讨论过的漏洞,通过补丁分析确认该漏洞出现在CVE-2020-0674双星漏洞之后,并在2020年4月的补丁中被修复。微软最初将其标注为CVE-2020-0968并标记为"已被利用",后又修改为"未被利用"。
二、漏洞成因分析
1. 核心漏洞机制
JScript在处理两个对象(type=0x81)的相加操作时,CScriptRuntime::Run会连续两次调用VAR::GetValue获取对应的值。当对象实现了自定义toString方法时,VAR::GetValue内部会进一步调用NameTbl::InvokeInternal函数,从而触发自定义的toString回调。
关键问题点:
- 第一次
VAR::GetValue调用后将返回结果保存到栈上的一个variant指针 - 开发者没有将该指针加入GC(垃圾回收)追踪列表
- 在第二个
VAR::GetValue导致的toString回调中,可以手动释放相关variant - 回调函数返回时,
CScriptRuntime::Run会再次引用已被释放的variant指针,造成UAF(Use-After-Free)
2. 内存管理细节
通过调试分析可以观察到variant指针的生命周期:
-
初始状态:
0:014> dd poi(ebp-68) L4 18db9ea0 00000082 00000000 14028c38 1402bff8 0:014> du 14028c38 14028c38 "[L]" -
GC标记阶段:
- 在
CollectGarbage函数导致的GcAlloc::SetMark阶段,GC的标志位被置位(|0x800)
18db9ea0 00000882 00000000 14028c38 1402bff8 - 在
-
GC回收阶段:
- 在
GcAlloc::ReclaimGarbage阶段,GC标志位被清除(&7ff)
18db9ea0 00000082 00000000 14028c38 1402bff8 - 在
-
内存释放阶段:
- 最终variant的type域被置为0,表示清除该variant
18db9ea0 00000000 00000000 14028c38 1402bff8
3. 触发条件
由于JScript中GCBlock的缓存机制,GCBlock缓存链中的GCBlock数量大于50时才会将接下来被回收的GCBlock直接释放。因此需要在回收之前申请大量variant变量并进行释放来布控内存。
三、漏洞利用技术
1. 利用流程概述
- 通过漏洞泄露一个
RegExpObj的指针 - 借助
RegExpObj构造可以越界读取的BSTR - 将整个
RegExpObj的内存读入数组并修改成员 - 将精心设计的
RegExpExec替换为原有的RegExpExec - 转换得到伪造的
RegExpObj - 在伪造的
RegExpObj基础上实现任意地址写原语 - 借助任意地址写和伪造的
RegExpObj成员实现任意地址读 - 泄露JScript模块指针获取基址
- 通过IAT查找得到kernel32模块地址
- 从kernel32的EAT中查找
VirtualProtect等函数 - 泄露Native栈指针并覆盖返回地址实现代码执行
2. 关键利用步骤详解
(1) 泄露RegExpObj指针
利用代码将两个对象相加的结果保存到str变量,随后存入nrefs数组。通过对nrefs数组的遍历找到被重用的variant,从而泄露RegExpObj指针。
内存分析示例:
位于0xaba0b90处的variant是一个string类型,其+8处存储的BSTR指针保存着十进制数组字符串
转换为16进制后得到内存地址0xabf7360,这正是RegExpObj指针
(2) 内存占位技术
利用代码分两个阶段进行内存占位:
-
第一次占位:
- 使用特定字符串进行UAF占位
- 在obj2的回调函数中执行占位操作
- 占位后将一个RegExp对象的type改为number(3)
-
第二次占位:
- 从nrefs数组解析出泄露的RegExpObj指针
- 将RegExpObj+2传入占位字符串
- 目的是构造超长BSTR进行进一步利用
(3) 任意地址读写构造
通过修改RegExpObj成员实现:
- 伪造
RegExpExec函数指针 - 构造任意地址写原语
- 基于伪造对象实现任意地址读
(4) 权限提升与代码执行
- 泄露JScript模块基址
- 通过IAT查找kernel32地址
- 解析kernel32导出表获取关键API
- 泄露Native栈指针
- 覆盖返回地址执行Shellcode
四、防御与检测建议
-
补丁管理:
- 确保应用2020年4月及之后的Windows安全更新
- 特别关注KB4549951等修复JScript引擎的补丁
-
缓解措施:
- 禁用不必要的Active Scripting功能
- 使用EMET或同类工具进行内存保护
- 启用控制流保护(CFG)缓解代码执行
-
检测方法:
- 监控异常JScript行为,特别是频繁的GC操作
- 检测大量variant对象创建与释放的模式
- 关注RegExpObj相关内存操作异常
五、技术对比
与之前JScript UAF漏洞利用的主要差异在于泄露RegExpObj指针的方式:
- 传统方法:通过特定对象布局直接泄露
- 本漏洞方法:利用variant重用机制间接泄露
- 优势:更隐蔽,更难被行为检测发现
六、参考资源
- 微软安全公告:CVE-2020-0968
- Windows补丁KB4549951更新说明
- 《谈谈两年来的4个Jscript ITW 0day》技术分析
- 看雪学院相关技术讨论:https://bbs.pediy.com/thread-261581.htm
附录:调试命令参考
// 查看variant内容
dd poi(ebp-68) L4
// 查看字符串内容
du [address]
// 设置内存访问断点
ba w2 [address]
// 跟踪GC操作
bp jscript!GcAlloc::SetMark
bp jscript!GcAlloc::ReclaimGarbage
通过本技术文档,安全研究人员可以全面理解CVE-2020-0968漏洞的原理和利用技术,为相关防御措施开发提供理论基础和实践指导。