ASLR (Address Space Layout Randomization) is one of the most effective protection mechanisms in modern operation systems. But it’s not perfect. Many recent APT attacks have used innovative techniques to bypass ASLR.
Here are just a few interesting bypass techniques that we have tracked in the past year:
- Using non-ASLR modules
- Modifying the BSTR length/null terminator
- Modifying the Array object
The following sections explain each of these techniques in detail.
Loading a non-ASLR module is the easiest and most popular way to defeat ASLR protection. Two popular non-ASLR modules are used in IE zero-day exploits: MSVCR71.DLL and HXDS.DLL.
MSVCR71.DLL, JRE 1.6.x is shipped an old version of the Microsoft Visual C Runtime Library that was not compiled with the /DYNAMICBASE option. By default, this DLL is loaded into the IE process at a fixed location in the following OS and IE combinations:
- Windows 7 and Internet Explorer 8
- Windows 7 and Internet Explorer 9
HXDS.DLL, shipped from MS Office 2010/2007, is not compiled with ASLR. This technique is now the most frequently used ASLR bypass for IE 8/9 on Windows 7. This DLL is loaded when the browser loads a page with ‘ms-help://’ in the URL.
The non-ASLR module technique requires IE 8 and IE 9 to run with old software such as JRE 1.6 or Office 2007/2010. Upgrading to the latest versions of Java/Office can prevent this type of attack.
Modify the BSTR length/null terminator
This technique first appears in the 2010 Pwn2Own IE 8 exploit by Peter Vreugdenhil. It applies only to specific types of vulnerabilities that can overwrite memory, such as buffer overflow, arbitrary memory write, and increasing or decreasing the content of a memory pointer.
The arbitrary memory write does not directly control EIP. Most of the time, the exploit overwrites important program data such as function pointers to execute code. For attackers, the good thing about these types of vulnerabilities is that they can corrupt the length of a BSTR so that using the BSTR can access memory outside of its original boundaries. Such accesses may disclose memory addresses that can be used to pinpoint libraries suitable for ROP. Once the exploit has bypassed ASLR in this way, it can then use the same memory corruption bug to control EIP.
Few vulnerabilities can be used to modify the BSTR length. For example, some vulnerabilities can only increase/decrease memory pointers by one or two bytes. In this case, the attacker can modify the null terminator of a BSTR to concatenate the string with the next object. Subsequent accesses to the modified BSTR have the concatenated object’s content as part of BSTR, where attackers can usually find information related to DLL base addresses.
The Adobe XFA zero-day exploit uses this technique to find the AcroForm.api base address and builds a ROP chain dynamically to bypass ASLR and DEP. With this vulnerability, the exploit can decrease a controllable memory pointer before calling the function pointer from its vftable:
Consider the following memory layout before the DEC operation:
After the DEC operation (in my tests, it is decreased twice) the memory becomes:
For further details, refer to the technique write-up from the immunityinc’s blog.
This technique usually requires multiple writes to leak the necessary info, and the exploit writer has to carefully craft the heap layout to ensure that the length field is corrupted instead of other objects in memory. Since IE 9, Microsoft has used Nozzle to prevent heap spraying/fengshui, so sometimes the attacker must use the VBArray technique to craft the heap layout.
Modify the Array object
The array object length modification is similar to the BSTR length modification: they both require a certain class of “user-friendly” vulnerabilities. Even batter, from the attacker’s view, is that once the length changes, the attacker can also arbitrarily read from or write to memory — or basically take control of the whole process flow and achieve code execution.
Here is the list of known zero-day exploits using this technique:
This exploit involves Adobe Flash player regex handling buffer overflow. The attacker overwrites the length of a Vector.<Number> object, and then reads more memory content to get base address of flash.ocx.
Here’s how the exploit works:
- Set up a continuous memory layout by allocating the following objects":
- Free the <Number> object at index 1 of the above objects as follows:
obj = null;
- Allocate the new RegExp object. This allocation reuses memory in the obj position as follows:
boom = "(?i)()()(?-i)||||||||||||||||||||||||";
var trigger = new RegExp(boom, "");
Later, the malformed expression overwrites the length of a Vector.<Number> object in obj to enlarge it. With a corrupted size, the attacker can use obj to read from or write to memory in a huge region to locate the flash.ocx base address and overwrite a vftable to execute the payload.
This vulnerability involves a IE CBlockContainerBlock object use-after-free error. This exploit is similar to CVE-2013-0634, but more sophisticated.
Basically, this vulnerability modifies the arbitrary memory content using an OR instruction. This instruction is something like the following:
or dword ptr [esi+8],20000h
Here’s how it works:
- First, the attacker sprays the target heap memory with Vector.<uint> objects as follows:.
- After the spray, those objects are stored aligned in a stable memory address. For example:
The first dword, 0x03f0, is the length of the Vector.<uint> object, and the yellow marked values correspond to the values in above spray code.
- If the attacker sets the esi + 8 point to 0x03f0, the size becomes 0x0203f0 after the OR operation — which is much larger than the original size.
- With the larger access range, the attacker can change the next object length to 0x3FFFFFF0.
- From there, the attacker can access the whole memory space in the IE process. ASLR is useless because the attacker can retrieve the entire DLL images for kernel32/NTDLL directly from memory. By dynamically searching for stack pivot gadgets in the text section and locating the ZwProtectVirtualMemory native API address from the IAT, the attacker can construct a ROP chain to change the memory attribute and bypass the DEP as follows:
By crafting the memory layout, the attacker also allocates a Vector.<object> that contains the flash.Media.Sound() object. The attacker uses the corrupted Vector.<uint> object to search the sound object in memory and overwrite it’s vftable to point to ROP payload and shellcode.
The use-after-free vulnerability in Firefox’s DocumentViewerImpl object allows the user to write a word value 0x0001 into an arbitrary memory location as follows:
In above code, all the variables that start with “m” are read from the user-controlled object. If the user can set the object to meet the condition in the second “if” statement, it forces the code path into the setImageAnimationMode() call, where the memory write is triggered. Inside the setImageAnimationMode(), the code looks like the following:
In this exploit, the attacker tries to use ArrayBuffer to craft the heap layout. In the following code, each ArrayBuffer element for var2 has the original size 0xff004.
This vulnerability involves a JAVA CMM integer overflow that allows overwriting the array length field in memory. During exploitation, the array length actually expands to 0x7fffffff, and the attacker can search for the securityManager object in memory and null it to break the sandbox. This technique is much more effective than overwriting function pointers and dealing with ASLR/DEP to get native code execution.
The Array object modification technique is much better than other techniques. For the Flash ActionScript vector technique, there are no heap spray mitigations at all. As long as you have a memory-write vulnerability, it is easily implemented.
The following table outlines recent APT zero-day exploits and what bypass techniques they used:
ASLR bypassing has become more and more common in zero-day attacks. We have seen previous IE zero-day exploits using Microsoft Office non-ASLR DLL to bypass it, and Microsoft also did some mitigation in their latest OS and browser to prevent use of the non-ASLR module to defeat ASLR. Because the old technique will no longer work and can be easily detected, cybercriminals will have to use the advanced exploit technique. But for specific vulnerabilities that allow writing memory, combining the Vector.<uint> and Vector.<object> is more reliable and flexible. With just one shot, extending the exploit from writing a single byte to reading or writing gigabytes is easy and works for the latest OS and browser regardless of the OS, application, or language version.
Many researchers have published research on ASLR bypassing, such as Dion Blazakis’s JIT spray and Yuyang’s LdrHotPatchRoutine technique. But so far we haven’t seen any zero-day exploit leveraging them in the wild. The reason could be that these techniques are generic approaches to defeating ASLR. And they are usually fixed quickly after going public.
But there is no generic way to fix vulnerability-specific issues. In the future, expect more and more zero-day exploits using similar or more advanced techniques. We may need new mitigations in our OSs and security products to defeat them.
Thanks again to Dan Caselden and Yichong Lin for their help with this analysis.