Exploit-DB #40843
Description: Microsoft Internet Explorer 11 - MSHTML 'CGenerated­Content::Has­Generated­SVGMarker' Type Confusion
Type: dos
Platform: windows
Date: 2016-11-28
Author: Skylined

Exploit:
<!--
Source: http://blog.skylined.nl/[PII_REDACTED]1.html

Synopsis

A specially crafted web-page can cause a type confusion in HTML layout in Microsoft Internet Explorer 11. An attacker might be able to exploit this issue to execute arbitrary code.

Known affected software and attack vectors

Microsoft Internet Explorer 11

An attacker would need to get a target user to open a specially crafted web-page. Disabling Javascript should prevent an attacker from triggering the vulnerable code path.

Repro.html:
-->

<html>
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <script>
      window.onload = function () {
        document.getôÙElementsôÙByôÙTagôÙName("iframe")[0].src = "repro-iframe.html";
      }
    </script>
  </head>
  <body>
    <iframe></iframe>
  </body>
</html>

<!--

Repro-iframe.html:

<svg><path marker-start="url(#)"><title><q><button>

Description

Internally MSIE uses various lists of linked CTreeôÙPos objects to represent the DOM tree. For HTML/SVG elements a CTreeôÙNode element is created, which embeds two CTreeôÙPos instances: one that contains information about the first child of the element and one that indicates the next sibling or parent of the element. For text nodes an object containing only one CTreeôÙPos is created, as such nodes never have any children. CTreeôÙPos instances have various flags set. This includes a flag that indicates if they are the first (fôÙTPBegin) or second (fôÙTPEnd) CTreeôÙPos instance for an element, or the only instance for a test node (fôÙTPText).

The CTreeôÙPos::Branch method of an CTreeôÙPos instance embedded in a CTreeôÙNode can be used to calculate a pointer to the CTreeôÙNode. It determines if the CTreeôÙPos instance is the first or second in the CTreeôÙNode by looking at the fôÙTPBegin flag and subtract the offset of this CTreeôÙPos object in a CTreeôÙNode object to calculate the address of the later. This method assumes that the CTreeôÙPos instance is part of a CTreeôÙNode and not a TextôÙNode. It will yield invalid results when called on the later. In a TextôÙNode, the CTreeôÙPos does not have the fôÙTPBegin flag set, so the code assumes this is the second CTreeôÙPos instance in a CTreeôÙNode object and subtracts 0x24 from its address to calculate the address of the CTreeôÙNode. Since the CTreeôÙPos instance is the first element in a TextôÙNode, the returned address will be 0x24 bytes before the TextôÙNode, pointing to memory that is not part of the object.

Note that this behavior is very similar to another issue I found around the same time, in that that issues also caused the code to access memory 0x24 bytes before the start of a memory region containing an object. Looking back I believe that both issues may have had the same root cause and were fixed at the same time.

The CGeneratedôÙContent::HasôÙGeneratedôÙSVGMarker method walks the DOM using one of the CTreeôÙPos linked lists. It looks for any descendant node of an element that has a CTreeôÙPos instance with a specific flag set. If found, the CTreeôÙPos::Branch method is called to find the related CTreeôÙNode, without checking if the CTreeôÙPos is indeed part of a CTreeôÙNode. If a certain flag is set on this CTreeôÙNode, it returns true. Otherwise it continues scanning. If nothing is found, it returns false.

The repro creates a situation where the CGeneratedôÙContent::HasôÙGeneratedôÙSVGMarker method is called on an SVG path element which has a TextôÙNode instance as a descendant with the right flags set to cause it to call CTreeôÙPos::Branch on this TextôÙNode. This leads to type confusion/a bad cast where a pointer that points before a TextôÙNode is used as a pointer to a CTreeôÙNode.

Reversed code

While reversing the relevant parts, I created the following pseudo-code to illustrate the issue:

enum eôÙTreeôÙPosôÙFlags {
  fôÙTPBegin =           0x01, // if set, this is a markup node
  fôÙTPEnd =             0x02, // if set, this is a markup node
  fôÙTPText =            0x04, // if set, this is a markup node
  fôÙTPPointer =         0x08, // if set, this is not a markup node
  fôÙTPTypeôÙMask =        0x0f
  fôÙTPLeftôÙChild =       0x10,
  fôÙTPLastôÙChild =       0x20, // poôÙNextôÙSiblingôÙOrôÙParent => fôÙTPLastôÙChild ? parent : sibling
  fôÙTPData2Pos =        0x40, // valid if fôÙTPPointer is set
  fôÙTPDataôÙPos =         0x80,
  fôÙTPUnknownôÙFlag100 = 0x100, // if set, this is not a markup node
}
struct CTreeôÙPos {
  /*offs size*/                                             // THE BELOW ARE BEST GUESSES BASED ON INADEQUATE INFORMATION!!
  /*0000 0004*/ eôÙTreeôÙPosôÙType  fôÙFlags00;                     
  /*0004 0004*/ UINT          uôÙCharsôÙCount04;                // Seems to be counting some chars - not sure what exactly
  /*0008 0004*/ CTreeôÙPos*     poôÙFirstôÙChild;                 // can be NULL if no children exist.
  /*000C 0004*/ CTreeôÙPos*     poôÙNextôÙSiblingôÙOrôÙParent;        // fôÙFlags00 & fôÙTPLastôÙChild ? parent end tag : sibling start tag
  /*0010 0004*/ CTreeôÙPos*     poôÙThreadôÙLeft10;               // fôÙFlags00 & fôÙTPBegin ? previous sibling or parent : last child or start tag
  /*0014 0004*/ CTreeôÙPos*     poôÙThreadôÙRight14;              // fôÙFlags00 & fôÙTPBegin ? first child or end tag : 
                                                            
  /*0018 0004*/ flags  (0x10 = something with CDATA         
  /*0028 0004*/                                             
}                                                           

struct CTreeôÙNode {
  /*offs size*/                                             // THE BELOW ARE BEST GUESSES BASED ON INADEQUATE INFORMATION!!
  /*0000 0004*/ CElement*     poôÙElement00;                  
  /*0004 0004*/ CTreeôÙNode*    poôÙParent04;                   
  /*0008 0004*/ DWORD         dwôÙUnknown08;                  // flags?
  /*000C 0018*/ CTreeôÙPos      oôÙTreeôÙPos