聚焦源代码安全,网罗国内外最新资讯!

编译:奇安信代码卫士团队

卡巴斯基发布博客文章,简要分析了微软在8月补丁星期二修复的一个已遭利用 0day CVE-2020-1380。如下内容编译自该文章。

文章指出,2020年5月,卡巴斯基阻止了利用 IE 恶意脚本攻击某韩国公司的一次攻击活动。进一步分析发现该攻击利用了此前未知的完整链,内含两个0day exploit:一个是IE 的远程代码执行 exploit,一个是 Windows 的提权 exploit。和此前 OperationWizardOpium 攻击使用的完整链不同,这个新的完整链利用的是 Windows 10的最新版本,测试发现对 IE 11 和 Windows 10 版本 18363 x64 的可靠利用。

2020年6月8日,卡巴斯基将问题告知微软并得到证实。当时,微软已开始为 CVE-2020-0986 准备补丁,不过刚开始对它的漏洞利用程度描述为“可能性较小”。该漏洞补丁在2020年6月9日发布。

微软在8月的补丁星期二为 JScript中的释放后使用漏洞分配编号 CVE-2020-1380。卡巴斯基将相关攻击活动称为“OperationPowerFall”。卡巴斯基表示目前尚无法确切地将它和任何威胁组织相联系,但鉴于和之前 exploit 存在的相似之处,它认为 DarkHotel 可能是攻击的幕后黑手。

IE 11 远程代码执行 exploit

近期发现的 IE 0day exploit 利用的是位于遗留的 JavaScript 引擎 jscript.dll 中的CVE-2020-0674、CVE-2019-1429、CVE-2019-0676和CVE-2018-8563。而CVE-2020-1380是存在于 jscript9.dll 中的漏洞,默认出现在IE9及后续版本中,因此,微软推荐的缓解措施(限制使用 jscript.dll)无法保护用户免受攻击。

CVE-2020-1380 是由 JIT 优化和缺乏对 JIT 编译代码进行检查造成的一个释放后使用漏洞。如下是触发该漏洞的 PoC:

function func(O, A, F, O2) {arguments.push = Array.prototype.push;O = 1;arguments.length = 0;arguments.push(O2);if (F == 1) {O = 2;}// execute abp.valueOf() and write by dangling pointerA[5] = O;
};// prepare objects
var an = new ArrayBuffer(0x8c);
var fa = new Float32Array(an);// compile func
func(1, fa, 1, {});
for (var i = 0; i < 0x10000; i++) {func(1, fa, 1, 1);
}var abp = {};
abp.valueOf = function() {// free worker = new Worker('worker.js');worker.postMessage(an, [an]);worker.terminate();worker = null;// sleepvar start = Date.now();while (Date.now() - start < 200) {}// TODO: reclaim freed memoryreturn 0
};try {func(1, fa, 0, abp);
} catch (e) {reload()
}

要理解该漏洞,首先明确 func() 是如何执行的。有必要了解下A[5] 的赋值是什么。从代码中可看到,它应该是一个参数 O。在函数启动时,参数O被重新赋值为1,但之后函数参数长度被设定为0。这一操作不会清空函数参数(通常对常规数组会清空),但允许通过使用Array.prototype.push 将参数O2放入索引为0的参数列表中,也就是说现在O = O2。此外,如果参数F等于1,那么 O 会被再次重新赋值,不过是赋值为整数2。这说明根据参数F的不同赋值,参数O要么被赋值为O2参数的值,要么是整数2。参数A是一个32位浮点数的类型化数组,在将值分配给该数组索引5处之前,这个值应该被转换为浮点数类型。虽然将整数转换为浮点数相对简单,但当对象转换为浮点数时就没有这么简单了。该 exploit 使用了具有覆盖了 valueOf() 方法的abp 对象。虽然当项目被转换为浮点数时会执行该方法,但方法内部含有释放 ArrayBuffer 的代码。该代码由 Float32Array 查看,并在其中设置返回值。为了阻止该值被存储在已释放的对象内存中,JavaScript 引擎需要在其中存储该值时检查对象的状态。为了安全地转换并存储浮点数值,JScript9.dll 使用了函数 Js::TypedArray<float,0>::BaseTypedDirectSetItem()。该函数的反编译代码如下:

int Js::TypedArray<float,0>::BaseTypedDirectSetItem(Js::TypedArray<float,0> *this, unsigned int index, void *object, int reserved)
{Js::JavascriptConversion::ToNumber(object, this->type->library->context);if ( LOBYTE(this->view[0]->unusable) )Js::JavascriptError::ThrowTypeError(this->type->library->context, 0x800A15E4, 0);if ( index < this->count ){*(float *)&this->buffer[4 * index] = Js::JavascriptConversion::ToNumber(object,this->type->library->context);}return 1;
}double Js::JavascriptConversion::ToNumber(void *object, struct Js::ScriptContext *context)
{if ( (unsigned char)object & 1 )return (double)((int)object >> 1);if ( *(void **)object == VirtualTableInfo<Js::JavascriptNumber>::Address[0] )return *((double *)object + 1);return Js::JavascriptConversion::ToNumber_Full(object, context);
}

该函数检查类型为浮点数的数组的view[0]->unusable和 count 字段以及在 valueOf()方法执行期间何时释放 ArrayBuffer。这两种检查都会失败,原因是 view[0]->unusable会被赋值为1,而count会在第一次调用 Js::JavascriptConversion::ToNumber()时赋值为0。问题在于,函数 Js::TypedArray<float,0>::BaseTypedDirectSetItem()仅用于解释模式下。

当函数 func() 被JIT编译时,JavaScript 引擎将使用如下易受攻击的代码。

if ( !((unsigned char)floatArray & 1) && *(void *)floatArray == &Js::TypedArray<float,0>::vftable )
{if ( floatArray->count > index ){buffer = floatArray->buffer + 4*index;if ( object & 1 ){*(float *)buffer = (double)(object >> 1);}else{if ( *(void *)object != &Js::JavascriptNumber::vftable ){Js::JavascriptConversion::ToFloat_Helper(object, (float *)buffer, context);}else{*(float *)buffer = *(double *)(object->value);}}}
}

Js::JavascriptConversion::ToFloat_Helper() 函数代码如下:

void Js::JavascriptConversion::ToFloat_Helper(void *object, float *buffer, struct Js::ScriptContext *context)
{*buffer = Js::JavascriptConversion::ToNumber_Full(object, context);
}

可以看到,和解释模式下不同,在 JIT 编译代码中,ArrayBuffer 的生命周期并未得到检查,其内存可被释放,随后通过调用 valueOf() 函数重新回收。另外,攻击者能够控制返回值编写的索引是什么。然而,当把 PoC 中的“arguments.length =0;”和“arguments.push(O2);”替换为“arguments[0] = O2;”时,那么由于间接调用会被禁用且它不会调用 valueOf() 函数,因此  Js::JavascriptConversion::ToFloat_Helper() 将不会触发该 bug。

为了确保函数 func() 会被JIT编译,exploit 会执行 0x10000 次函数,对整数进行非恶意转换,而且只有当 func() 被再次执行时,才会触发该 bug。为了释放 ArrayBuffer,该 exploit 使用了常见的 Web Workers API 滥用技术。函数 postMessage() 可用于将对象序列化到消息并将其发送给 worker。不过它带来的负面影响是,被传输的对象得到释放且在当前的脚本上下文中变得不稳定。当 ArrayBuffer 被释放时,exploit 通过模拟 Sleep() 函数使用的代码触发垃圾回收:它是一个 while 循环,检查 Data.now() 和之前所存储值之间的时间差。之后,该 exploit 会通过整数数组回收内存。

for (var i = 0; i < T.length; i += 1) {T[i] = new Array((0x1000 - 0x20) / 4);T[i][0] = 0x666; // item needs to be set to allocate LargeHeapBucket}

创建大量数组后,IE会分配新的 LargeHeapBlock 对象,用于 IE 的自定义堆实现。LargeHeapBlock 对象将会存储为这些数组分配的地址。如果预期的内存布局成功实现,那么该漏洞会覆盖 LargeHeapBlock的偏移量 0x14 处的值为0,而这恰好是分配的块计数。

之后,该 exploit 分配大量数组并将它们设置为在利用初始阶段的另外一个数组。然后该数组被赋值为 null,而 exploit 会调用函数 CollectGarbage()。这就导致堆碎片整理,并且修改后的 LargeHeapBlock 及其相关的数组缓冲区将被释放。在这个阶段,漏洞利用会创建大量的整数数组,以期收回之前释放的数组缓冲区。新创建的数组的magic 值设置为索引0,并且通过指向先前释放的数组的悬空指针检查该值,以检测利用是否成功。

        for (var i = 0; i < K.length; i += 1) {K[i] = new Array((0x1000 - 0x20) / 4);K[i][0] = 0x888; // store magic}for (var i = 0; i < T.length; i += 1) {if (T[i][0] == 0x888) { // find array accessible through dangling pointerR = T[i];break;}}

结果,该exploit 就创建了缓冲区指向同一位置的两个不同的JavascriptNativeIntArray 对象。这就使得检索对象地址、甚至是创建新的恶意对象成为可能。该 exploit 利用这些原语创建恶意 DataView 对象并获得对该进程整体地址空间的读/写访问权限。

构建了任意读/写原语后,就应该绕过 Control FlowGuard (CFG) 并执行代码。该exploit 利用 Array 的 vftable 指针获得 jscript9.dll 的模块基址。之后,解析 jscript9.dll 的PE标头获取 Import DirectoryTable 的地址并解析其它模块的基址。这样做的目的是找到函数 VirtualProtect() 的地址,从而使shellcode 变得可执行。之后,该 exploit 查找 jscript9.dll 中的两个签名。这些签名对应Unicode 字符串“split”和函数 JsUtil::DoublyLinkedListElement<ThreadContext>::LinkToBeginning<ThreadContext>()。该Unicode字符串“split”的地址用于获得该字符串的代码引用,以此解析实现字符串方法 split() 的函数 Js::JavascriptString::EntrySplit()的地址。函数 LinkToBeginning<ThreadContext>() 的地址用于获取全局连接列表中第一个ThreadContext 对象的地址。该 exploit 定位连接列表中的最后一个输入并以此获得负责执行该脚本的栈的位置。接下来就是最后一个阶段了。该 exploit 执行 split() 方法并且具有覆写的 valueOf() 方法的对象作为一个limit参数提供。在执行 Js::JavascriptString::EntrySplit()函数过程中执行被覆写的 valueOf() 方法时,该 exploit 会搜索线程的栈,找到返回地址,将shellcode 放在准备好的缓冲区中,获取其地址并最终构建一个和面向返回的编程 (ROP) 链,通过覆写该函数的地址执行 shellcode。

下一步

该 shellcode 是附加在 shellcode 的可移植可执行文件 (PE) 模块的反射型 DLL 加载器。该模块非常小,而且整个功能位于一个函数中。它在临时文件夹中创建了一份文件,文件名为“ok.exe”并写入另外一个位于远程代码执行 exploit 中的另一个可执行文件的内容。之后,”ok.exe”被执行。

可执行文件“ok.exe”中包含的是任意指针应用漏洞 CVE-2020-0986 的提权 exploit。最初该漏洞是由一名匿名研究员在2019年12月通过趋势科技的 ZDI 项目报告给微软的,但由于微软在6个月之后仍未修复该漏洞,因此ZDI在5月19日公开漏洞详情。第二天该漏洞遭利用。

CVE-2020-0986 使得能够通过进程间通信读写splwow64.exe进程的任意内存、在 splwow64.exe进程中实现代码执行、绕过 CFG 和 EncodePointer 防护措施。该 exploit 的资源中内嵌着两个可执行文件。第一个是以 XreateDC.exe 写入磁盘,用于创建设备上下文 (DC) 以实施利用。第二个可执行文件的名称是“PoPc.dll”,且如果利用成功,则会被具有中等完整性级别的 splwow64.exe执行。

PoPc.dll 的主要功能也存在于一个函数中。它执行编码的 PowerShell 命令,从 www[.]static-cdn1[.]com/update.zip中下载文件,在临时文件夹中保存为 upgrader.exe并执行。由于卡巴斯基在可执行文件下载前就已阻止该攻击,因此我们无法分析 upgrader.exe。

IoC

www[.]static-cdn1[.]com/update.zip

B06F1F2D3C016D13307BC7CE47C90594

D02632CFFC18194107CC5BF76AECA7E87E9082FED64A535722AD4502A4D51199

5877EAECA1FE8A3A15D6C8C5D7FA240B

7577E42177ED7FC811DE4BC854EC226EB037F797C3B114E163940A86FD8B078B

B72731B699922608FF3844CCC8FC36B4

7765F836D2D049127A25376165B1AC43CD109D8B9D8C5396B8DA91ADC61ECCB1

E01254D7AF1D044E555032E1F78FF38F

81D07CAE45CAF27CBB9A1717B08B3AB358B647397F08A6F9C7652D00DBF2AE24

推荐阅读

微软补丁星期二修复120个漏洞,含2个已遭利用的 0day

原文链接

https://securelist.com/ie-and-windows-zero-day-operation-powerfall/97976/

题图:Pixabay License

本文由奇安信代码卫士编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 www.codesafe.cn”。

奇安信代码卫士 (codesafe)

国内首个专注于软件开发安全的

产品线。

 觉得不错,就点个 “在看” 吧~

已遭利用的Windows 0day漏洞 CVE-2020-1380分析相关推荐

  1. 已遭利用的Windows 0day漏洞 CVE-2020-1380 分析

    卡巴斯基发布博客文章,简要分析了微软在8月补丁星期二修复的一个已遭利用 0day CVE-2020-1380.如下内容编译自该文章. 文章指出,2020年5月,卡巴斯基阻止了利用 IE 恶意脚本攻击某 ...

  2. 已遭利用的微软0day CVE-2020-1464,原来是两年前的老相识

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 在本月补丁星期二中,微软修复了一个已遭利用的 0day 漏洞 CVE-2020-1464.它可导致MSI 文件被转换为恶意的 Java ...

  3. 苹果修复三个已遭利用的 iOS 0day

     聚焦源代码安全,网罗国内外最新资讯! 今日,苹果发布安全更新,修复了24个影响 iOS 14.2和 iPadOS 14.2的漏洞,其中包含已修复三个遭在野利用的0day (CVE-2020-2793 ...

  4. 谷歌紧急修复已遭利用的新 0day

     聚焦源代码安全,网罗国内外最新资讯! 编译:代码卫士 上周五,谷歌紧急修复已遭利用的 Chrome 0day (CVE-2022-1096),和 V8 JavaScript 引擎中的类型混淆漏洞有关 ...

  5. 谷歌修复已遭利用的 Chrome 0day

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 谷歌修复了 Chrome 88.0.4324.150版本中一个已遭利用的 0day 漏洞,影响 Windows.Mac 和 Linux ...

  6. 微软补丁星期二修复已遭利用的 Defender 0day

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 微软在2021年1月补丁星期二中共修复了83个漏洞,其中10个为"严重"级别,1个已遭利用.它们影响Windows ...

  7. 谷歌修复4个已遭利用的安卓 0day

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士 本周三,谷歌更新2021年五月安卓安全通告称,Arm 和高通在本月早些时候修复的4个漏洞可能已在 0day 漏洞状况下遭利用. 安全通告指 ...

  8. 速升级!SonicWall 3个已遭利用的严重0day 影响企业邮件安全设备

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士 SonicWall 公司解决了托管和现场邮件安全 (ES) 产品中的三个严重漏洞,它们已遭在野利用. 其中,CVE-2021-20021和 ...

  9. 7天期限已过,谷歌披露已遭利用的 Windows 内核 0day 详情

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 上周五,谷歌安全研究员发现了已遭在野利用的一个 Windows 0day.谷歌 Project Zero 团队主管 Ben Hawke ...

最新文章

  1. 设计模式 之美 -- 代理模式
  2. ARM平台硬件时钟中断周期HZ值计算
  3. Visual Studio 2019更新到16.2.1
  4. VTK:PolyData之ExtractSelectionCells
  5. Google2012.9.24校园招聘会笔试题
  6. 分页offset格式_Thinkphp5 原生sql分页操作
  7. spring tiles_Spring MVC 3模板和Apache Tiles
  8. 从草根到百万年薪程序员的十年风雨之路,吊打面试官系列!
  9. Install Python 3.6 on Ubuntu 16.04, from source
  10. HTML弹窗上下一步,JS实现从网页顶部掉下弹出层效果的方法
  11. 芒果移动广告优化平台
  12. matlab绘正态/卡方/t/F分布概率密度图
  13. 相似度测试的软件,Plagiarism Checker X(文章相似度检测软件) V6.08 官方版
  14. Deepin Linux禁用笔记本自带键盘
  15. error: src refspec master does not match any. 错误的解决办法
  16. 【Java】Java中的常用工具类(排名前 16)
  17. 使用Windows Server 2003轻松建立森林间信任
  18. LaTex各种命令、符号
  19. 自学Web前端开发学习讲解 – 入门篇
  20. java connection用法_Java Connection.close方法代码示例

热门文章

  1. asp.net mvc(九)
  2. echarts 通过ajax实现动态数据加载
  3. zend studio使用xdebug调试程序不能单步调试的解决方案
  4. 外媒:巴基斯坦将成为南亚地区首个测试5G通讯的国家
  5. [文摘20071127]推销场上的十种失败的推销员
  6. python3正则表达式判断ipv4_Python 正则表达式验证IPv4地址
  7. Build.VERSION_CODES类
  8. https://github.com/nostra13/Android-Universal-Image-Loader
  9. php header 跳转 ie问题
  10. Error - ORA-26028