对多米诺行动所用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指针的生命周期:

  1. 初始状态

    0:014> dd poi(ebp-68) L4
    18db9ea0 00000082 00000000 14028c38 1402bff8
    0:014> du 14028c38
    14028c38 "[L]"
    
  2. GC标记阶段

    • CollectGarbage函数导致的GcAlloc::SetMark阶段,GC的标志位被置位(|0x800)
    18db9ea0 00000882 00000000 14028c38 1402bff8
    
  3. GC回收阶段

    • GcAlloc::ReclaimGarbage阶段,GC标志位被清除(&7ff)
    18db9ea0 00000082 00000000 14028c38 1402bff8
    
  4. 内存释放阶段

    • 最终variant的type域被置为0,表示清除该variant
    18db9ea0 00000000 00000000 14028c38 1402bff8
    

3. 触发条件

由于JScript中GCBlock的缓存机制,GCBlock缓存链中的GCBlock数量大于50时才会将接下来被回收的GCBlock直接释放。因此需要在回收之前申请大量variant变量并进行释放来布控内存。

三、漏洞利用技术

1. 利用流程概述

  1. 通过漏洞泄露一个RegExpObj的指针
  2. 借助RegExpObj构造可以越界读取的BSTR
  3. 将整个RegExpObj的内存读入数组并修改成员
  4. 将精心设计的RegExpExec替换为原有的RegExpExec
  5. 转换得到伪造的RegExpObj
  6. 在伪造的RegExpObj基础上实现任意地址写原语
  7. 借助任意地址写和伪造的RegExpObj成员实现任意地址读
  8. 泄露JScript模块指针获取基址
  9. 通过IAT查找得到kernel32模块地址
  10. 从kernel32的EAT中查找VirtualProtect等函数
  11. 泄露Native栈指针并覆盖返回地址实现代码执行

2. 关键利用步骤详解

(1) 泄露RegExpObj指针

利用代码将两个对象相加的结果保存到str变量,随后存入nrefs数组。通过对nrefs数组的遍历找到被重用的variant,从而泄露RegExpObj指针。

内存分析示例

位于0xaba0b90处的variant是一个string类型,其+8处存储的BSTR指针保存着十进制数组字符串
转换为16进制后得到内存地址0xabf7360,这正是RegExpObj指针

(2) 内存占位技术

利用代码分两个阶段进行内存占位:

  1. 第一次占位

    • 使用特定字符串进行UAF占位
    • 在obj2的回调函数中执行占位操作
    • 占位后将一个RegExp对象的type改为number(3)
  2. 第二次占位

    • 从nrefs数组解析出泄露的RegExpObj指针
    • 将RegExpObj+2传入占位字符串
    • 目的是构造超长BSTR进行进一步利用

(3) 任意地址读写构造

通过修改RegExpObj成员实现:

  • 伪造RegExpExec函数指针
  • 构造任意地址写原语
  • 基于伪造对象实现任意地址读

(4) 权限提升与代码执行

  1. 泄露JScript模块基址
  2. 通过IAT查找kernel32地址
  3. 解析kernel32导出表获取关键API
  4. 泄露Native栈指针
  5. 覆盖返回地址执行Shellcode

四、防御与检测建议

  1. 补丁管理

    • 确保应用2020年4月及之后的Windows安全更新
    • 特别关注KB4549951等修复JScript引擎的补丁
  2. 缓解措施

    • 禁用不必要的Active Scripting功能
    • 使用EMET或同类工具进行内存保护
    • 启用控制流保护(CFG)缓解代码执行
  3. 检测方法

    • 监控异常JScript行为,特别是频繁的GC操作
    • 检测大量variant对象创建与释放的模式
    • 关注RegExpObj相关内存操作异常

五、技术对比

与之前JScript UAF漏洞利用的主要差异在于泄露RegExpObj指针的方式:

  • 传统方法:通过特定对象布局直接泄露
  • 本漏洞方法:利用variant重用机制间接泄露
  • 优势:更隐蔽,更难被行为检测发现

六、参考资源

  1. 微软安全公告:CVE-2020-0968
  2. Windows补丁KB4549951更新说明
  3. 《谈谈两年来的4个Jscript ITW 0day》技术分析
  4. 看雪学院相关技术讨论: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漏洞的原理和利用技术,为相关防御措施开发提供理论基础和实践指导。

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指针的生命周期: 初始状态 : GC标记阶段 : 在 CollectGarbage 函数导致的 GcAlloc::SetMark 阶段,GC的标志位被置位(|0x800) GC回收阶段 : 在 GcAlloc::ReclaimGarbage 阶段,GC标志位被清除(&7ff) 内存释放阶段 : 最终variant的type域被置为0,表示清除该variant 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 指针。 内存分析示例 : (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 附录:调试命令参考 通过本技术文档,安全研究人员可以全面理解CVE-2020-0968漏洞的原理和利用技术,为相关防御措施开发提供理论基础和实践指导。