Is It the Beginning of the End For Use-After-Free Exploitation?

Use-after-free bugs have affected Internet Explorer for years. In the past year alone, Microsoft patched 122 IE vulnerabilities, the majority of which were use-after-free bugs. This year Microsoft has already patched 126 IE vulnerabilities to date. Of those vulnerabilities, 4 were actively being exploited in the wild. These 4 exploits (CVE-2014-1815, CVE-2014-1776, CVE-2014-0322, CVE-2014-0324) were all based on use-after-free bugs.

To deal with the increasing number of use-after-free bugs and associated exploits, Microsoft introduced a series of new control mechanisms in the most recent Internet Explorer patches. In June, Microsoft introduced a new isolated heap mechanism to solve the usage issue of use-after-free exploitation. They followed that up In July by implementing a deferred free method to solve the freeing issue of use-after-free bugs.

The main concept of an isolated heap is simple. It allocates a dedicated heap for select critical objects to use that is separate from other heaps that a user can directly access. The heap block will not be occupied by user-controlled data after the critical objects are freed. This mechanism prevents precise control of the data of a freed object from further exploitation.

 Figure 1. _g_hIsolatedHeap handle used for isolated heap

The isolated heap was applied to many but not all internal objects, leaving some still vulnerable. To address this, Microsoft introduced another protection method of deferred free named ProtectedFree. They encapsulate this method and apply it to almost every object in mshtml.dll. In IE9, for example, it has been applied to every object through MemoryProtection::HeapFree as shown in figure 2.

figure 2

Figure 2. References of MemoryProtection::HeapFree

The main idea of this protection mechanism is to delay the freeing action so that the intruder is unable to determine when they can occupy the freed object using controlled data. In this new patch, every time Internet Explorer tries to free an object, it is not freed immediately. Instead, the block to be freed is marked and filled with 0x00 data and added to a pool. When the size of the pool hits a predefined threshold, which is currently 100k (0x186A0 as highlighted in figure 3), it performs the real freeing operation (ReclaimUnmarkedBlocks).

  Figure 3. C++ style pseudo code of ProtectedFree function

Microsoft stores the to-be-freed blocks in a structure called st_ProtecFreeManageHeap. This structure is created in the function MemoryProtection::CMemoryProtector::ProtectCurrentThread and is used to manage deferred free heap blocks. Figure 4 shows an example of the structure in memory.

 Figure 4. st_ProtecFreeManageHeap

Figure 5 provides an alternate view of the structure in a C style code block.

 Figure 5. C style code of st_ProtecFreeManageHeap

If we were able to make the size of the current heap block in this structure larger than the threshold of 0x186A0 bytes and trigger CMemoryProtector::ProtectedFree, it is still possible to force a true freeing action and occupy the freed object with other data as we show in the following piece of javascript code in figure 6.

  Figure 6. Javascript proof of concept to force freeing

When creating the anchor element, the debug logs are shown in figure 7. The address of the anchor element is 0x0c3b3f98.

 Figure 7: Before free

We then manually decrease the reference number, so the CMemoryProtector::ProtectedFree function will fill the block with 0’s, but the object is still not freed.

Figure 8: decrease the reference number, not yet freed

Finally we make the size of the CMemoryProtector::ProtectedFree management structure larger than 0x186a0 forcing the freeing operation.

 Figure 9: field “TotalMemorySize” of st_ProtecFreeManageHeap is greater than threshold

The anchor element is now actually freed as shown in figure 10.

  Figure 10: object is in the free list now

From a researchers' point of view, deferred free created a few problems, one of the major ones being that the page heap feature may not work correctly. Page heap is a useful feature for debugging. When page heap is turned on, the system allows only one object in one memory page. Once this object is freed the whole page is marked as invalid. So the next time IE tries to access a freed object an invalid address exception would be raised. This mechanism is extremely helpful when researchers are trying to find use-after-free bugs.

With the introduction of the deferred free patch the object is no longer truly freed, so the page still exists. In this situation the researcher is no longer able to determine whether a use-after-free behavior has occurred because no exception would be thrown out. To reduce the impact of the deferred free patch, a research may consider patching the mshtml.dll in memory. For example, you can call MemoryProtection::CMemoryProtector::UnprotectProcess before you perform any fuzzing tasks.

The recent patches and introduction of isolated heap and deferred free are strong signs that Microsoft plans to address the fundamentals of use-after-free exploitation in a preventative manner rather than to passively patch the vulnerabilities as they are discovered. From the results of our research, applications of such methods can effectively stop unpatched use-after-free attacks. It can also make the exploitations of heap overflows or type confusion bugs significantly more difficult. But this is not the end.

For the foreseeable future, Microsoft may introduce more defensive mechanisms against use-after-free bugs or even heap fengshui to reduce the risk of being exploited. Could it be game over for use-after-free exploitation, or it is just the beginning of another cat and mouse game? Time will tell.