Exploit-DB #40881
Description: Microsoft Internet Explorer 9 - 'jscript9' Java­Script­Stack­Walker Memory Corruption (MS15-056)
Type: remote
Platform: windows
Date: 2016-12-06
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. A pointer set up to point to certain data on the stack can be used after that data has been removed from the stack. This results in a stack-based analog to a heap use-after-free vulnerability. The stack memory where the data was stored can be modified by an attacker before it is used, allowing remote code execution.

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.

Repro.html:

<!doctype html>
<script>
  var oôÙWindow = window.open("about:blank");
  oôÙWindow.execôÙScript('window.oôÙURIError = new URIError();oôÙURIError.name = oôÙURIError;')
  try { "" + oôÙWindow.oôÙURIError; } catch(e) { }
  try { "" + oôÙWindow.oôÙURIError; } catch(e) { }
</script>

Description

A Javascript can construct an URIError object and sets that object's name property to refer to the URIError object, creating a circular reference. When that Javascript than attempts to convert the URIError object to a string, MSIE attempts to convert the URIError object's name to a string, which creates a recursive code loop that eventually causes a stack exhaustion.

MSIE attempts to handle this situation gracefully by generating a JavaôÙScript exception. While generating the exception, information about the call stack is gathered using the JavascriptôÙStackôÙWalker class. It appears that the code that does this initializes a pointer variable on the stack the first time it is run, but re-uses it if it gets called a second time. Unfortunately, the information the pointer points to is also stored on the stack, but is removed from the stack after the first exception is handled. Careful manipulation of the stack during both exceptions allow an attacker to control the data the pointer points to during the second exception.

This problem is not limited to the URIError object: any recursive function call can be used to trigger the issue, as shown in the exploit below.

Exploit

As mentioned above, the vulnerable pointer points to valid stack memory during the first exception, but it is "popped" from the stack before the second. In order to exploit this vulnerability, the code executed during the first exception is going to point this pointer to a specific area of the stack, while the code executed during the second is going to allocate certain values in that same area before the pointer is re-used.

Control over the stack contents during a stack exhaustion can be achieved by making the recursive calls with many arguments, all of which are stored on the stack. This is similar to a heap-spray storing values on large sections of the heap in that it is not entirely deterministic, but the odds are very highly in favor of you setting a certain value at a certain address.

The exploit triggers the first exception by making recursive calls using a lot of arguments. In each loop, a lot of stack space is needed to make the next call. At some point there will not be enough stack space left to make another call and an exception is thrown. If N arguments are passed during each call, N*4 bytes of stack are needed to store them. The number of bytes left on the stack at the time of the exception varies from 0 to about 4*N and thus averages to about 4*N/2. The vulnerable pointer gets initialized to point to an address near the stack pointer at the time of the exception, at approximately (bottom of stack) + 4*N/2.

The exploit then triggers another stack exhaustion by making recursive calls using many arguments, but significantly less than before. If M arguments are passed during each call this time, the number of bytes left on the stack at the time of the exception averages to about 4*M/2.

When the second exception happens, the vulnerable pointer points inside the stack that was "sprayed" with function arguments. This means we can control where it points to. The pointer is used as an object pointer to get a function address from a vftable, so by using the right value to spray the stack, we can gain full control over execution flow.

The below schematic shows the layout of the stack during the various stages of this exploit:

|                                                                              |
|<- bottom of stack                                             top of stack ->|
|                                                                              |
| Stack layout at the moment the first exception is triggered:                 |
|                                                                              |
|                 [--- CALL X ---][-- CALL X-1 --][-- CALL X-2 --][...........]|
|                                                                              |
|{---------------} Stack space available is less than 4*N bytes                |
|                                                                              |
|                ^^^                                                           |
|                Vulnerable pointer gets initialized to point around here      |
|                                                                              |
|                                                                              |
|                                                                              |
| Stack layout at the moment the second exception is triggered:                |
|                                                                              |
|    [CALL Y][CALL Y-1][CALL Y-2][CALL Y-3][CALL Y-3][........................]|
|                                                                              |
|{--} Stack space available is less than 4*M bytes