作者:腾讯湛泸实验室
来源:https://weibo.com/ttarticle/p/show?id=2309404351596157885398

0x00 背景

近期谷歌威胁分析团队(Google's Threat Analysis Group)发现了一例野外攻击中的Chrome远程代码执行漏洞:CVE-2019-5786。攻击者利用该漏洞配合一个win32k.sys的内核提权(CVE-2019-0808 )可以在win7上穿越Chrome沙箱。野外利用并且带有沙箱逃逸的Chrome漏洞实属罕见,因此腾讯安全湛泸实验室在谷歌官方发布公告后针对此次攻击进行了技术还原分析。

由于微软在windows 7上并未实现win32k Lockdown机制,因此win7系统中的Chrome沙盒并不能充分防御win32k漏洞的利用。关于此次攻击中的CVE-2019-0808 win32k提权(https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/CVE-2019-0808)我们不作过多介绍,重点来探讨CVE-2019-5786这个漏洞的一些细节。

0x01 技术细节

根据谷歌在Chrome3月份的安全更新(https://chromereleases.googleblog.com/2019/03/stable-channel-update-for-desktop.html)中的描述:这是一个FileReader中的Use-after-free漏洞。

在Chrome浏览器中,FileReader 可以用来异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。

FileReader 有三种状态,如下图所示:

img

我们在github上查找这个漏洞的补丁信息如下:https://github.com/chromium/chromium/commit/ba9748e78ec7e9c0d594e7edf7b2c07ea2a904499

img

我们看补丁后的代码:在返回部分result的时候,不再直接返回raw_data_中的缓冲区,而是返回其拷贝。据此可以推测UAF应该是发生在这块直接返回的内存上。

通常情况下,如果我们构造以下JS片段

let arr1= new ArrayBuffer(0x1000)

let ta1 = new Uint8Array(arr1);

let ta2 = new Uint8Array(arr1);

neuter(arr1);

在上述代码中,如果ArrayBuffer arr1被分离(detach),即arr1的所有权被转移到一个worker线程,那么该对象内部的was_detached标志位会被设置,后续TypedArray在使用该对象时候,会先进行检查。

BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, was_detached,

                    JSArrayBuffer::WasDetachedBit)

也还要其他的操作来确保不会出现UAF,代码片段如下:

img

回到这个漏洞来看,

scoped_refptr<ArrayBuffer> ArrayBufferBuilder::ToArrayBuffer() {

  // Fully used. Return m_buffer as-is.

  if (buffer_->ByteLength() == bytes_used_)

?    return buffer_;



  return buffer_->Slice(0, bytes_used_);

}

raw_data_->ToArrayBuffer()可能会返回内部buffer的拷贝,或者是返回一个指向其内部buffer的智能指针。

ArrayBuffer应该被理解为是独占其内部的buffer的,在后一种情况下,如果已经结束加载后获取FileReader的result,raw_data_会被清零;然而,如果在没有完成加载的情况下,多次获取FileReader的result,Chrome会创建多个内部引用相同buffer区域的DomArrayBuffer。此时我们通过worker线程释放其中一个,就可以在主线程中造成UAF。

img

Poc关键代码如下:

   var reader1 = new FileReader();

   // …

   flag = reader1.result;

   flag2 = reader1.result;

   abc = new Uint8Array(flag);

   abc2 = new Uint8Array(flag2);

   neuter(flag);

   //...

   abc2[0] = 1;  //uaf !

以上代码即可造成ArrayBuffer非常稳定的UAF。熟悉浏览器漏洞的同行都了解ArrayBuffer的漏洞很好利用,这里不再对利用方式作进一步讨论。

0x02 结论

根据上文的分析可以看到CVE-2019-5786是一个非常高质量的远程代码执行漏洞。腾讯安全湛泸实验室提醒广大Chrome用户尽快将浏览器升级到官方最新版。同时,建议国内使用Chrome内核的浏览器厂商紧密关注此次更新,主动排查修复风险,保障广大用户安全。


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/862/