Today we released MS13-063 which includes a defense in depth change to address an exploitation technique that could be used to bypass two important platform mitigations: Address Space Layout Randomization (ASLR) and Data Execution Prevention (DEP). As we’ve described in the past, these mitigations play an important role in making it more difficult and costly for attackers to exploit vulnerabilities. The bypass technique that has been addressed by MS13-063 was described by Yang Yu of NSFocus Security Labs at the CanSecWest security conference earlier this year. This bypass was also independently discovered by other researchers and was used by VUPEN in one of their exploits for the Pwn2Own 2013 contest as well. A few months ago, we released EMET 4.0 which included a mitigation for this specific bypass. In this blog post, we wanted to provide some background on how the bypass works and how it has been addressed by MS13-063.
How the bypass works
The bypass takes advantage of a predictable memory region known as SharedUserData that exists at a fixed location (0x7ffe0000) in every process on every supported version of Windows. On 64-bit versions of Windows prior to Windows 8, this region contains pointers to multiple functions in the 32-bit version of NTDLL that is used by WOW64 processes as shown below:
The presence of these pointers at a predictable location in memory can enable an attacker to bypass ASLR if they have the ability to read anywhere in memory. In this case, the bypass technique takes things a step further by taking advantage of one of the functions listed above: LdrHotPatchRoutine. This function is part of the hotpatching support provided by Windows and one of the noteworthy things it does when called is load a DLL from a path that has been passed in as a field of the first parameter. This means that if an attacker can use a vulnerability to call LdrHotPatchRoutine, they could execute arbitrary code as a side effect of loading a malicious DLL of their choosing, such as from a UNC path, and thus bypass DEP implicitly.
Depending on the vulnerability that is being exploited, it can be fairly straightforward for an attacker to trigger a call through the pointer to LdrHotPatchRoutine in SharedUserData with a controlled parameter, thus bypassing both ASLR and DEP. Use after free vulnerabilities involving C++ objects with a virtual table pointer are particularly well-suited for being able to apply this technique. These vulnerabilities have become a preferred vulnerability class of exploit writers in recent years. The reason use after free issues are particularly amendable is because attackers typically control the entire content of the C++ object that has been freed prior to a virtual method call. As such, an attacker only needs a virtual method call site where they can control the virtual table pointer being called through and the first parameter that is passed to the virtual method. For example, if we assume that EDX points to memory that is controlled by the attacker:
mov ecx, [edx+0x4] ; load pointer to fake object into ECX
mov eax, [ecx] ; load fake virtual table pointer 0x7ffe0344 into EAX
push ecx ; push pointer to controlled content as first parameter
call [eax+0xc] ; call [0x7ffe0344 + 0xc] which points to LdrHotPatchRoutine
As a result of the above sequence, LdrHotPatchRoutine will be called and the DLL path referred to in the fake structure that is passed as the first parameter will be loaded, thus bypassing both ASLR and DEP.
How the fix works
The bypass described above relies on the fact that a pointer to LdrHotPatchRoutine can be found at a predictable location in memory. As such, one way to mitigate this bypass is to simply eliminate the predictable pointer to LdrHotPatchRoutine from SharedUserData. This is approach taken in the security update for MS13-063. After installing this update on Windows 7 64-bit, we can see that not only has the pointer to LdrHotPatchRoutine been eliminated, but in fact all other image pointers have been eliminated as well:
As a result, not only is the LdrHotPatchRoutine bypass mitigated, but so is any other bypass that relies on leveraging the image pointers that were present in SharedUserData on 64-bit versions of Windows. The potential for abusing one or more of these pointers was something that we were aware of during the development of Windows 8 and as such we took steps to eliminate all image pointers from SharedUserData on both 32-bit and 64-bit versions of Windows 8. This is why Windows 8 was not susceptible to this bypass. It should be noted that although MS13-063 removes all image pointers from SharedUserData on 64-bit versions of Windows 7, there is still one image pointer present in SharedUserData on 32-bit versions of Windows 7 and prior (the SystemCall function pointer).
For those who are curious, the pointers that were originally stored in SharedUserData have now been moved to an exported global data structure named LdrSystemDllInitBlock in NTDLL. This data structure is populated during process initialization with the required pointers. Since NTDLL is randomized by ASLR, an attacker cannot reliably predict where these pointers will be stored in memory.
Although we were already aware of the underpinnings of this bypass before it was publicly described, it is a great example of a technique that could have qualified for our recently announced Mitigation Bypass Bounty Program. This bounty program offers exceptional rewards (up to $100,000) for novel exploitation techniques that affect the latest versions of our products. In this case, the bypass was generic, could be made reliable, had reasonable requirements, applied to high impact user mode application domains, and had elements that made it novel. Discovering and mitigating exploitation techniques of this nature can help us make our platform safer and more secure by breaking the techniques that attackers rely on to develop reliable exploits.
– Matt Miller and William Peteroy
Special thanks to our colleagues in Windows Sustained Engineering for their work on shipping this defense in depth update.