BinRec: Attack Surface Reduction Through Dynamic Binary Recovery - - PowerPoint PPT Presentation
BinRec: Attack Surface Reduction Through Dynamic Binary Recovery - - PowerPoint PPT Presentation
BinRec: Attack Surface Reduction Through Dynamic Binary Recovery Taddeus Kroes, Anil Altinay, Joseph Nash, Yeoul Na, Stijn Volckaert, Herbert Bos, Michael Franz, Cristiano Giuffrida October 19, 2018 Attack Surface Reduction x =
Attack Surface Reduction
x = getenv(“SET_ME”); if (x) cold_code(); hot_code();
2
Attack Surface Reduction
x = getenv(“SET_ME”); if (x) cold_code(); hot_code();
3
Buggy features ROP gadgets
Attack Surface Reduction
x = getenv(“SET_ME”); if (x) cold_code(); hot_code();
4
Remove unwanted features A t t a c k s u r f a c e r e d u c e d t
- w
e l l
- t
e s t e d c
- d
e
Attack Surface Reduction
5
setme_str: .asciz: “SET_ME” push setme_str call getenv cmp eax, 0 je main call cold_code main: call hot_code
Want to work on COTS binaries
Static approach
Input binary Transformed binary
6
Transform
Static approach
Input binary Transformed binary
7
i n c
- m
p l e t e d i s a s s e m b l y PIC?
- bfuscated?
Transform
Static approach
Input binary Transformed binary
8
i n c
- m
p l e t e d i s a s s e m b l y contains cold code PIC?
- bfuscated?
w h i c h c
- d
e i s r e a c h e d ?
Transform
Dynamic approach by BinRec
Transform
Input binary
9
Transformed binary p r e c i s e d i s a s s e m b l y
- nly hot code
Execute
Recovery
Dynamic approach by BinRec
Input binary Recovered binary
10
Transform Execute
Recovery
Dynamic approach by BinRec
Input binary Recovered binary
11
Transform Execute
can we make this more generic?
BinRec goal: complex binary transformation
Attack Surface Reduction / Binary rejuvenation / Profile-guided
- ptimization
/ (De)obfuscation / ISA retargeting
Input binary Recovered binary
12
many applications
Execute
BinRec goal: complex binary transformation
Attack Surface Reduction / Binary rejuvenation / Profile-guided
- ptimization
/ (De)obfuscation / ISA retargeting
Input binary Recovered binary
13
many applications r e q u i r e s h i g h
- l
e v e l c
- d
e !
Execute
BinRec design
Input binary Recovered binary Compiler IR Machine Code
14
Execute Transform
BinRec design
Lift
Input binary Recovered binary Compiler IR Machine Code
15
Execute Transform Lower
BinRec design
Lift
Input binary Recovered binary Compiler IR Machine Code
16
Execute Transform Lower
Sometimes we want more code coverage than a single code path
BinRec design
Lift
Input binary Recovered binary Compiler IR Machine Code
17
Symbolic execution
Transform Lower
Run with “symbolic” input and follow both sides of a branch
BinRec design
Lift
Input binary Recovered binary Compiler IR Machine Code
18
Symbolic execution
Transform Lower
Need to observe each instruction Want to support multiple architectures
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
19
Symbolic execution
Transform Lower
E m u l a t e i n V M , t r a n s l a t e i n s t r u c t i
- n
s t
- I
R
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
20
Symbolic execution
Transform Lower
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
21
Symbolic execution
Transform Compile
J u s t u s e t h e c
- m
p i l e r
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
22
Symbolic execution
Transform Compile
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
23
Symbolic execution
Transform Compile
What about unlifted code paths? ... if (getenv(“SET_ME”)) { puts(“thanks!”); // not recovered! } ...
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
24
Symbolic execution
Transform Compile
What about unlifted code paths?
- 1. do nothing (breaks conservative behavior)
... getenv(“SET_ME”); ...
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
25
Symbolic execution
Transform
What about unlifted code paths?
- 2. yield error
... if (getenv(“SET_ME”)) { abort(); } ... Compile Add errors
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
26
Symbolic execution
Transform
What about unlifted code paths?
- 3. fallback to old code
... if (getenv(“SET_ME”)) { goto old_code_address; } ... Compile Add errors / fallbacks
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
27
Symbolic execution
Transform
R e f e r e n c e s d a t a f r
- m
i n p u t b i n a r y Compile Add errors / fallbacks
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
28
Symbolic execution
Transform
Compile Add errors / fallbacks Link data sections
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
29
Symbolic execution
Transform
Compile Add errors / fallbacks Link data sections IR interacts with VM runtime
// Lifted code emit_event(BASIC_BLOCK_START) cpu_state.pc = 0x1000 ebx = &cpu_state.registers[R_EBX] *ebx = *ebx + 1 cpu_state.icount++ cpu_state.pc = 0x1234 emit_event(BASIC_BLOCK_END)
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
30
Symbolic execution
Transform
Compile Add errors / fallbacks Link data sections // machine code 0x1000: add ebx, 1 jmp 0x1234 IR interacts with VM runtime
// Lifted code emit_event(BASIC_BLOCK_START) cpu_state.pc = 0x1000 ebx = &cpu_state.registers[R_EBX] *ebx = *ebx + 1 cpu_state.icount++ cpu_state.pc = 0x1234 emit_event(BASIC_BLOCK_END)
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
31
Symbolic execution
Transform
Compile Add errors / fallbacks Link data sections events, counters // machine code 0x1000: add ebx, 1 jmp 0x1234
// Lifted code emit_event(BASIC_BLOCK_START) cpu_state.pc = 0x1000 ebx = &cpu_state.registers[R_EBX] *ebx = *ebx + 1 cpu_state.icount++ cpu_state.pc = 0x1234 emit_event(BASIC_BLOCK_END)
BinRec design
Input binary Recovered binary Compiler IR Machine Code
32
Symbolic execution
Transform
Compile Add errors / fallbacks Link data sections // machine code 0x1000: add ebx, 1 jmp 0x1234 registers in CPU state control flow through virtual program counter
Lift in VM Strip emulation
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
33
Symbolic execution
Transform
Compile Add errors / fallbacks Link data sections // stripped code global ebx lifted_1000: ebx = ebx + 1 goto lifted_1234 // machine code 0x1000: add ebx, 1 jmp 0x1234
// Lifted code emit_event(BASIC_BLOCK_START) cpu_state.pc = 0x1000 ebx = &cpu_state.registers[R_EBX] *ebx = *ebx + 1 cpu_state.icount++ cpu_state.pc = 0x1234 emit_event(BASIC_BLOCK_END)
Strip emulation
BinRec design
Lift in VM
Input binary Recovered binary Compiler IR Machine Code
34
Symbolic execution
Transform
Compile Add errors / fallbacks Link data sections
Strip emulation Pre-process Post-process
Needed to prevent over-optimization during transformations (details in paper)
This is quite bit of code
35
Implementation
Lift in VM
Input binary Recovered binary
36
Symbolic execution
Transform
Compile Add errors / fallbacks Link data sections
Strip emulation Pre-process Post-process
Implementation
Input binary Recovered binary
37
Symbolic execution
Transform
Compile Add errors / fallbacks Link data sections
Strip emulation Pre-process Post-process
S2E
Lift in VM
Implementation
Input binary Recovered binary
38
Symbolic execution
Transform
Compile Add errors / fallbacks Link data sections
Strip emulation Pre-process Post-process
S2E
Lift in VM
LLVM
Implementation
Input binary Recovered binary
39
Symbolic execution
Transform
Compile Add errors / fallbacks Link data sections
Strip emulation Pre-process Post-process
S2E
Lift in VM
LLVM Bash + Python Binutils
Case study
40
Lift in VM Input binary Recovered binary
41
Symbolic execution Transform Compile
Add errors / fallbacks
Link data sections Strip emulation Pre-process Post-process
// ab.c int main(int argc, char **argv) { char a = argv[1][0]; char b = argv[1][1]; if (a == 'a') { if (b == 'b') { puts("You entered \"ab\""); } } return 0; }
Lift in VM Input binary Recovered binary
42
Symbolic execution Transform Compile
Add errors / fallbacks
Link data sections Strip emulation Pre-process Post-process
Input binary Recovered binary
43
Symbolic execution Transform Compile
Add errors / fallbacks
Link data sections Strip emulation Pre-process Post-process
Raw code is heavily instrumented
- event triggers
- instruction counter
- program counter, registers, flags, etc. stored in CPU state in memory
Lift in VM
Input binary Recovered binary
44
Symbolic execution Transform Compile
Add errors / fallbacks
Link data sections Strip emulation Pre-process Post-process Lift in VM
cmp eax, 1 jle label
“heavily” instrumented
Input binary Recovered binary
45
Symbolic execution Transform Compile
Add errors / fallbacks
Link data sections Pre-process Post-process Lift in VM
Raw Pruned
Strip emulation
Input binary Recovered binary
46
Symbolic execution Transform Compile
Add errors / fallbacks
Link data sections Pre-process Post-process Lift in VM
Pruned Optimized Raw
Strip emulation
Input binary Recovered binary
47
Symbolic execution Transform Compile
Add errors / fallbacks
Link data sections Pre-process Post-process Lift in VM Strip emulation
Cascading optimizations
Input binary Recovered binary
48
Symbolic execution Transform
Add errors / fallbacks
Link data sections Pre-process Post-process Lift in VM Strip emulation Compile .text
Recovered code
...
Input binary Recovered binary
49
Symbolic execution Transform
Add errors / fallbacks
Pre-process Post-process Lift in VM Strip emulation Compile .text .rodata .data
Old binary
.got .plt ... .text
Recovered code
... .text .rodata .data
Recovered binary
.got .plt .text.new
= +
... Link data sections
entry entry
Input binary Recovered binary
50
Symbolic execution Transform
Add errors / fallbacks
Pre-process Post-process Lift in VM Strip emulation Compile .text .rodata .data
Old binary
.got .plt ... .text
Recovered code
... .text .rodata .data
Recovered binary
.got .plt .text.new
= +
... Link data sections
Remove for error, Keep for fallback
entry entry
Input binary Recovered binary
51
Symbolic execution Transform Compile
Add errors / fallbacks
Link data sections Pre-process Post-process Lift in VM Strip emulation
Original C Recovered LLVM
Input binary Recovered binary
52
Symbolic execution Transform Compile
Add errors / fallbacks
Link data sections Pre-process Post-process Lift in VM Strip emulation
Original LLVM Recovered LLVM
Experiments
53
Experiments
- Correctness
- Attack Surface Reduction: ROP gadgets
- Performance
54
Experiment: correctness
Do our transformations preserve semantics?
- Yield errors for unknown code paths
- Check that recovered binary has same output as input binary
55
Experiment: correctness
Do our transformations preserve semantics?
- Yield errors for unknown code paths
- Check that recovered binary has same output as input binary
24 input binaries from SPEC-CPU2006 (x86)
- 15 succeeded, 9 failed (unexpected fallback / crash)
56
Experiment: ROP gadget reduction
Is the attack surface actually smaller?
- 72% fewer instructions
- 48% fewer ROP gadgets
(both numbers are geomean)
57
Experiment: performance
- O3 input binaries: expect similar performance
- O0 input binaries: expect speedup
- Disable fallback errors: maybe expect speedup
58
~44% overhead
- O3 input binaries: expect similar performance
- O0 input binaries: expect speedup
- Disable fallback errors: maybe expect speedup
Experiment: performance
59
~2% overhead
- O3 input binaries: expect similar performance
- O0 input binaries: expect speedup
- Disable fallback errors: maybe expect speedup
Experiment: performance
60
~5% performance gain
Wish list / future work
- Gadget-aware compiler backend
- Improve performance
- Do aggressive profile-guided optimization
- Deobfuscation
61
- BinRec successfully transforms binaries at compiler IR level
- … and halves the ROP attack surface in the process
Also
- Binary lifting is hard
Conclusion
62