Return of the sprayer
JIT Spraying: Exploits to beat DEP and ASLR
Jürgen Schmidt
The dream team of data execution prevention (DEP) and address space layout randomisation (ASLR) was long considered an almost insurmountable barrier for attackers. Then along came JIT spraying to move the goalposts and get attackers back in the game.
For a while, the combination of security mechanisms introduced in Windows Vista and XP SP2 held exploit developers in check. Even if they were able to discover security vulnerabilities which allowed them to modify the flow of execution, they could rarely exploit it to seize control of a system. If they jumped to code injected onto the stack or heap, "just like in the good old days", data execution prevention (DEP) would trigger an interrupt and the system would terminate the carefully pwned process before it could cause any damage.
More recent exploit techniques such as return-to-libc or the more refined return-oriented programming also fell short. Return-to-libc is based on executing existing system functions (e.g. memory management functions) and passing appropriate parameters to them. The random mixing of memory addresses performed by address space layout randomisation (ASLR) meant that an attacker no longer knew at what address the required code was located. The countermeasure to this – heap spraying – was in turn kiboshed by DEP, resulting in a virtuous circle. With the advent of JIT spraying, however, the tables have been turned and the attacker is now back in the game.
JIT spraying makes use of the fact that just-in-time (JIT) compilers generate executable code at runtime from scripts such as ActionScript. This can be utilised to have a Flash video generate executable code which DEP considers entirely legitimate. But ActionScript is not able to do everything a hacker needs for a fully-featured exploit. Exploit writers would, for example, love to disable DEP on the memory pages containing the code needed to take full control of a system using VirtualProtect()
. But ActionScript, designed for controlling multimedia content, does not offer this kind of low-level functionality.
To overcome this hurdle, in spring 2010, Dion Blazakis pulled a brilliant rabbit out of the hat. It is based on the fact that the code seen and executed by the system depends on where exactly you start reading a series of bytes. The JIT compiler compiles the ActionScript XOR command
var ret=(0x3C909090^0x3C909090^0x3C909090^0x3C909090^ …);
into the following machine code:
0x1A1A0100: 359090903C
XOR EAX, 3C9090900x1A1A0105: 359090903C
XOR EAX, 3C9090900x1A1A010A: 359090903C
XOR EAX, 3C909090
If, however, you jump to a memory address offset by one from where it starts with the value 0x90
, the CPU sees the following:
0x1A1A0101: 90
NOP0x1A1A0102: 90
NOP0x1A1A0103: 90
NOP0x1A1A0104: 3C35
CMP AL, 350x1A1A0106: 90
NOP...
Readers of our CSI:Internet series will instantly recognise this as a NOP slide, an important component of heap spraying techniques. Nothing happens in a NOP slide until the CPU eventually comes to the actual shellcode. Since 0x3C
also puts you on the slide, the chances of landing on the slide following a leap into the unknown are five times that of landing on the XOR.
And what makes it even better is that by carefully selecting the XOR value it is also possible to assemble other code – code to determine the virtual memory address of VirtualProtect()
, deactivate memory protection and then execute the second part of the shellcode, for example. There are now even tutorials available, such as Writing JIT-Spray Shellcode for fun and profit.
By spraying enough NOP slides, XOR commands and shell code into memory, an attacker can then afford to take that leap into the unknown – by, say, triggering a bug in the Flash plugin or in the browser. Alternatively, Blazakis has also demonstrated a means of using ActionScript to obtain the address for your shellcode despite the best efforts of ASLR. Because the JIT code is marked as executable, the CPU executes it without complaint and the exploit is good to go.
Not that this renders ASLR and DEP useless. They continue to offer excellent protection against the exploitation of many security vulnerabilities. Activating them via EMET as described in the article Damage Limitation thus remains advisable. But, after a period where the new security mechanisms introduced in Windows Vista appeared to have given the defenders the upper hand, JIT spraying has moved the goalposts yet again and the hare versus tortoise race is once more wide open. Initial musings on approaches to detecting and preventing JIT spraying were published in autumn 2010.
References:
- Dion Blazakis, Interpreter Exploitation: Pointer Inference and JIT Spraying (PDF)