Back To The Epilogue
How to Evade Windows' Control Flow Guard
with Less than 16 Bytes

Andrea Biondo *Prof. Mauro Conti
Daniele Lain *SPRITZ Group
University of Padua, IT

GOALS- Return to function epilogue- Evade Windows’ Control Flow Guard- With less than 16 bytes

CFI VIOLATION!

FINE GRAINEDFINE GRAINEDCOARSE GRAINEDCONTROL FLOW GUARDOVERVIEW- Microsoft’s CFI implementation- Deployed since Windows 8.1- Coarse-grained (single target set)
- Forward-edge only

CONTROL FLOW GUARD
INTERNALS
1. Compile time: instrument calls and build target seta. Check modeb. Dispatch mode

CONTROL FLOW GUARDINTERNALS
1. Compile time: instrument calls and build target set
a. Check modeb. Dispatch mode

2. Load time: build bitmap, populate function pointers
3. Run time: checks in ntdll

CONTROL FLOW GUARD
INTERNALS- Fast checking through a bitmap- 2 bits map to 16 aligned bytes of target address space-00: No target allowed
01: Export suppression
10: Aligned allowed target
11: All targets allowedCONTROL FLOW GUARDKNOWN ATTACKS- Code reuse on modules built without CFG support- Return address overwrite- Improper protection of JITed code
- 11 by default on memory mappings- Lack of instrumentation in JITed code

- Unintended allowed calls (sensitive APIs)- Making check/dispatch function pointers R/W- Possibly R/W sections assumed to be RO

BACK TO THE EPILOGUE
THE IDEA- What if an allowed target is not 16-byte aligned?
- Can’t be 10, must be 11 → unintended targets?
- (MJ0011 noted this back in 2014)- Unaligned targets are still there in system libraries

ANATOMY OF A FUNCTION
func1

...
PrologueBodyfunc2

Epilogue
Prologue
Body
Epilogue...

Allocate stack frame
Business logic
Deallocate stack frame

BACK TO THE EPILOGUE
THE IDEA- We can reach instructions close to the entry point- Prologues are boring- Epilogues mess with the stack and return- Profit?

GOALS- Return to function epilogue- Evade Windows’ Control Flow Guard- With less than 16 bytes

BACK TO THE EPILOGUE
THE PLAN- Epilogues increment stack pointer and return- PR gadgets

BACK TO THE EPILOGUE
THE PLAN- Epilogues increment stack pointer and return- PR gadgets- Pivot return address into attacker-controlled data
- No backward-edge CFI → profit!

BACK TO THE EPILOGUE
64-BIT: THE PROBLEM- First four arguments not on the stack- Scumbag RPA foils our evil plan

BACK TO THE EPILOGUE
64-BIT: THE IDEA
- Spill attacker-controlled values to RPA- Need to call PR at the caller’s stack depth- Seems hard :(Compiler optimizations to the rescue:
Tail jumps!

BACK TO THE EPILOGUE
64-BIT: THE PLAN
- Find CFG-valid functions that:a. Spill attacker-controlled registers to the RPA
b. Have manageable side effects
c. End with an attacker-controlled indirect tail jump

- We call them S gadgets- Symbolic execution + taint tracking-<insert jankiest taint tracking ever><insert more analysis buzzwords>

GOALS- Return to function epilogue- Evade Windows’ Control Flow Guard- With less than 16 bytes

CONTROL FLOW GUARDKNOWN ATTACKSAOTT support- Code reuse on modules built without
CFGNEM- Return address overwrite RGUAN- Improper protection
A JITed code
Y ofTSLEGN- 11 by defaultOon memory
mappingsAD
LLLA in JITedHcodeGCRO- LackTof
instrumentation
DTI
ENT
W (sensitive APIs)E
CO RUP allowed- Unintendedcalls
LUR
DOOC- Making check/dispatch
function pointers R/WM
DAO
- Possibly
R/W sections assumed to be RO
LEVALUATION- Systematically evaluated Windows’ system libraries- Loaded by a large number of processes- Pattern matching PR gadgets

EVALUATION

32-bit64-bit57 PR GADGETS

22 PR GADGETS

msvcrt.dll (!!!)
MSVP9DEC.dll
jscript9.dll
msmpeg2vdec.dll

Load vuln lib → whole program vulnerable

EVALUATION- S gadgets via symex- 985 different ones
-IE & Edge JS engines - jscript9.dll, Chakra.dll
IE & EDGE HTML parsers - mshtml.dll, edgehtml.dll
Skype codecs...

EDGE EXPLOIT- CVE-2016-7200- Array.filter Infoleak- Leak address of object- CVE-2016-7201- FillFromPrototypes type confusion- Arbitrary memory R/WEDGE EXPLOITGADGET SELECTION- P16R0 from msmpeg2vdec.dll- S2 from chakra.dll- Spills rdx (2nd arg) to rsp+16- Calls fptr @ +0x50 in vtable of object in rcx (1st arg)

EDGE EXPLOITASLR BYPASS (chakra.dll)
1. Leak address of JavaScript object
2. Read vtable pointer from object
3. Read function pointer from vtableNow we have a code pointer in chakra.dll.

EDGE EXPLOITASLR BYPASS (msmpeg2vdec.dll)
1. Derandomize msvcrt.dll from chakra.dll’s IAT
2. Derandomize ntdll.dll from msvcrt.dll’s IAT
3. Look up msmpeg2vdec.dll in ntdll’s loaded
modules hash table

EDGE EXPLOITCONTROLLING ARGUMENTS- Most functions accept Var arguments- Var is either a pointer to object or a double
1. Create array → elements will be Vars
2. Corrupt array element via write primitive
3. Use corrupted element as argument

EDGE EXPLOITCONTROL FLOW HIJACKING
1. Hijack JavascriptFunction vtable
a. HasInstance @ +0x200 → S gadgetb. @ +0x50 → PR gadget

2. Call instanceof
a. LHS: JavascriptFunction (1st arg to HasInstance)
b. RHS: controlled Var (2nd arg to HasInstance)

GOALS- Return to function epilogue- Evade Windows’ Control Flow Guard- With less than 16 bytes

BLACK HAT SOUND BYTES- Attack your mitigations!
- Be careful in what you shrug off as not dangerous- Seemingly small issues might not be so small after all

an attack byANDREA BIONDO
MAURO CONTIDANIELE LAIN
UNIVERSITY OF PADUA - SPRITZ GROUP