Microsoft Internet Explorer 11 (all versions before the June 2016 patch)
I've created two separate html files that can be used to reproduce this issue and shows control over a 32-bit vftable pointer in x86 versions of MSIE or a partial control over a 64-bit vftable pointer in x64 versions.
<meta http-equiv="X-UA-Compatible" content="IE=7"> <script> oElement = document.createElement("IMG"); var oAttr = document.createAttribute("loop"); oAttr.
nodeValue = oElement; oElement. loop = 0x41424344; // Set original value data to 44 43 42 41 oElement. setAttributeNode(oAttr); // Replace oElement with original value data oElement. removeAttributeNode(oAttr); CollectGarbage(); // Use original value data as address 0x41424344 of a vftable </script>
setAttributeNode is used to set an attribute of a HTML element, and the
nodeValue is not a valid value, this
nodeValue is set to the
value the attribute had before the call. This can happen for instance when you
try to set an attribute that must have a string or number value by using an
Attr node with a HTML element as its
nodeValue (as this is not a string or
number). The HTML element in
nodeValue is replaced with the string or number
value the attribute had before the call to
Attr node is then removed using
removeAttributeNode and the garbage
collector runs, the code appears to assume the nodeValue still contains an
object, rather than the string or number it has been changed into. This causes
the code to use the data for the string or number value as if it was a C++
object. It attempts to determine a function pointer for a method from the
object's virtual function table before calling this function using the pointer.
If the previous value is a string, the character data from the string is used to calculate the function pointer. If the previous value is a number, the value of the number is used. This provides an attacker with a large amount of control over the function pointer and may allow execution of arbitrary code.
Using this scanner, I found that the
loop attribute of the
INPUT elements accepts 32-bit integer values in the range
and that this value is used as a pointer when determining the address of the
function. Using a standard heap spray, it should be possible to create a
pointer that points to data under the attacker's control and so control
execution flow. However, the function call is protected by Control Flow Guard,
so additional tricks are needed to bypass this in order to execute arbitrary
code. The provided repro results in an access violation around address
On 64-bit systems, this element/attribute combination is not very useful as
none of the upper 32-bits of the address can be controlled. Various attributes
will take a limited set of valid string as their value, such as the
attribute of the
FORM element, which can be set to "get" or "post". The BSTR
character data of such strings end up being used as the pointer, allowing an
attacker to provide a pointer of the form
0x00??00??00??00??, but the number of
valid string values is very limited, so the number of possible pointer values
is very limited too. The chances of any of these values being useful are very,
There are however element/attribute combinations that require a number which is
stored as a BSTR, e.
size attribute of the
HR element. Setting this
attribute to 0 will cause the code to allocate a BSTR containing "0", setting
it to 3333 will cause it to allocate a BSTR containing "3333". This BSTR may
get allocated from the heap or "allocated" from the OLEAUT32 cache, heap-feng-
shui style. "3333" results in the pointer address
0x0033003300330033, but "0"
results in the address
?? can be data taken from
a reused BSTR that was "allocated" from the cache. This should allow an attacker
full control over the upper 32 bits of the pointer address, as well as some
control over the lower 4 bits. If an attacker can do a heap spray covering an
address that follows this format, and determine the address at which the heap
spray is located, full control over execution flow may be possible. Again, the
function call is protected by Control Flow Guard, so additional tricks are
needed to bypass this in order to execute arbitrary code. The provided repro
results in an access violation around address
In order to determine what elements and attributes are affected, I've created a web-page that can be used to scan for this. This scanner does the following:
When run, the scanner will show which element/attribute combination it is
scanning in the document's title as well as show a popup for each test. Clicking
on cancel stops the popups, allowing the scanner to proceed very fast. However,
when a crash occurs, the document's title may not have been updated in a while.
You can copy the element/attribute combination into the
sStartAt variable in
the scanner and run it again to start from that position. Now click ok at the
popups; your crash should happen relatively soon. This time the document's
title is up-to-date, so you know which element/attribute combination triggered
it. After finding a crashing combination, it can be added to the
blacklist, so the scanner can be restarted to find another combination.
The addresses in the access violations triggered by the scanner should indicate
the type and possible values of the attribute, e.
0x44444444 indicates the value must be an integer of
DWORD size. A crash at an address of the form
0x00??00?? (or on 64-bit systems
0x00??00??00??00??) indicates a the value
must be a string and if the address is around
0x0033003300330033, it must be an integer stored as a string.