A Tough call : Mitigating Advanced Code-Reuse Attacks At The Binary - - PowerPoint PPT Presentation

a tough call
SMART_READER_LITE
LIVE PREVIEW

A Tough call : Mitigating Advanced Code-Reuse Attacks At The Binary - - PowerPoint PPT Presentation

A Tough call : Mitigating Advanced Code-Reuse Attacks At The Binary Level Victor van der Veen, Enes Gkta (joint first author) (VU) Moritz Contag, Andre Pawlowski, Thorsten Holz (RUB) Xi Chen, Sanjay Rawat, Herbert Bos, Elias Athanasopoulos,


slide-1
SLIDE 1

A Tough call:

Mitigating Advanced Code-Reuse Attacks At The Binary Level

Victor van der Veen, Enes Göktaş (joint first author) (VU) Moritz Contag, Andre Pawlowski, Thorsten Holz (RUB) Xi Chen, Sanjay Rawat, Herbert Bos, Elias Athanasopoulos, Cristiano Giuffrida (VU)

slide-2
SLIDE 2

Control-Flow Integrity

  • Promising way to stop code-reuse attacks
  • Hard to enforce in practice
  • Existing binary-level CFI cannot prevent function-reuse attacks (COOP)

2

slide-3
SLIDE 3

Control-Flow Integrity

  • Promising way to stop code-reuse attacks
  • Hard to enforce in practice
  • Existing binary-level CFI cannot prevent function-reuse attacks (COOP)

TypeArmor

  • A more precise binary-level CFI solution
  • Acceptable overhead (3% on SPEC)
  • Stops all published code-reuse attacks

3

slide-4
SLIDE 4

processor() { ... while (condition) { ... call fptr ... } ... }

Func1() { ... }

Running example: normal execution

Func2() { ... } Func3() { ... }

4

slide-5
SLIDE 5

processor() { ... while (condition) { ... call fptr ... } ... }

Func1() { ... }

Running example: advanced code-reuse

Func2() { ... } Func3() { ... }

5

slide-6
SLIDE 6

processor() { ... while (condition) { ... call fptr ... } ... }

Func1() { ... }

Running example: advanced code-reuse

Func2() { ... } Func3() { ... }

Gadget Gadget

Function-oriented programming

Attacker controlled ‘loop gadget’

6

slide-7
SLIDE 7

processor() { ... while (condition) { ... call fptr ... } ... }

Func1() { ... }

Running example: binary-level CFI

Func2() { ... } Func3() { ... }

Gadget Gadget Loop gadget

  • Unable to resolve indirect call targets
  • Indirect calls may go to any function

7

slide-8
SLIDE 8

processor() { ... while (condition) { ... call fptr ... } ... }

Func1() { ... }

Running example: binary-level CFI

Func2() { ... } Func3() { ... }

Gadget Gadget Loop gadget

  • Unable to resolve indirect call targets
  • Indirect calls may go to any function

Binary-level solutions

8

slide-9
SLIDE 9

processor() { ... while (condition) { ... call fptr ... } ... }

Func1() { ... }

Running example: source-level CFI

Func2() { ... } Func3() { ... }

Gadget Gadget Loop gadget

Source-level solutions

  • Enforce class hierarchy (VTV)
  • Match function argument types (IFCC)

9

slide-10
SLIDE 10

processor() { ... while (condition) { ... call fptr ... } ... }

Func1() { ... }

Running example: TypeArmor

Func2() { ... } Func3() { ... }

Gadget Gadget Loop gadget

TypeArmor

  • Approximate source-level accuracy

10

slide-11
SLIDE 11

processor() { ... while (condition) { ... call fptr ... } ... }

Func1() { ... }

Running example: TypeArmor

Func2() { ... } Func3() { ... }

Gadget Gadget Loop gadget

TypeArmor

  • Approximate source-level accuracy

Not as accurate as source

11

slide-12
SLIDE 12

processor() { ... while (condition) { ... call fptr ... } ... }

Func1() { ... }

Running example: TypeArmor

Func2() { ... } Func3() { … }

Gadget Gadget Loop gadget

TypeArmor

  • Approximate source-level accuracy

Not as accurate as source But still breaking exploits

12

slide-13
SLIDE 13

Approximate source-level invariants?

  • Extract argument count at callsite
  • Extract argument usage at callee
  • Allow only targets with matching function types

Function signature matchingby argcount

13

slide-14
SLIDE 14

Approximate source-level invariants?

  • Extract argument count at callsite
  • Extract argument usage at callee
  • Allow only targets with matching function types

Callsites preparing two args should never call functions expecting three or more

Function signature matchingby argcount

14

slide-15
SLIDE 15

Approximate source-level invariants?

  • Extract argument count at callsite
  • Extract argument usage at callee
  • Allow only targets with matching function types

Callsites preparing two args should never call functions expecting three or more Implemented for the x86-64 architecture:

  • Calling convention: pass arguments via registers
  • Search for write instructions at the callsite
  • Search for read-before-write instructions at the callee

Function signature matchingby argcount

15

slide-16
SLIDE 16

processor() { ... while (condition){ arg1 = x arg2 = y call fptr(arg1,arg2) ... } ... }

Func1(arg1,arg2){ return arg1+arg2 }

Running example: TypeArmor

Func2(arg1,arg2){ return arg1*arg2 } Func3(arg1,arg2,arg3){ return arg3-arg1+arg2 }

Loop gadget

  • Match argument count expectations

16

slide-17
SLIDE 17

processor() { ... while (condition){ arg1 = x arg2 = y call fptr(arg1,arg2) ... } ... }

Func1(arg1,arg2){ return arg1+arg2 }

Running example: TypeArmor

Func2(arg1,arg2){ return arg1*arg2 } Func3(arg1,arg2,arg3){ return arg3-arg1+arg2 }

Loop gadget

  • Match argument count expectations

Prepares 2 arguments Expects 2 arguments

17

slide-18
SLIDE 18

processor() { ... while (condition){ arg1 = x arg2 = y call fptr(arg1,arg2) ... } ... }

Func1(arg1,arg2){ return arg1+arg2 }

Running example: TypeArmor

Func2(arg1,arg2){ return arg1*arg2 } Func3(arg1,arg2,arg3){ return arg3-arg1+arg2 }

Loop gadget

  • Match argument count expectations

Prepares 2 arguments Expects 2 arguments Expects 2 arguments Working Gadget

18

slide-19
SLIDE 19

processor() { ... while (condition){ arg1 = x arg2 = y call fptr(arg1,arg2) ... } ... }

Func1(arg1,arg2){ return arg1+arg2 }

Running example: TypeArmor

Func2(arg1,arg2){ return arg1*arg2 } Func3(arg1,arg2,arg3){ return arg3-arg1+arg2 }

Broken Gadget Loop gadget

  • Match argument count expectations

Prepares 2 arguments Expects 2 arguments Expects 2 arguments Expects 3 arguments Working Gadget

19

slide-20
SLIDE 20

Precision

How accurate can we determine the prepared and used argument count?

Callsites Functions Server # As in source # As in source Memcached 48 41 (86%) 236 210 (89%) lighttpd 54 47 (87%) 353 311 (88%) Nginx 218 161 (74%) 1,111 869 (78%) MySQL 7,532 5,771 (77%) 9,961 6,977 (70%)

20

slide-21
SLIDE 21

Precision

How accurate can we determine the prepared and used argument count?

Callsites Functions Server # As in source # As in source Memcached 48 41 (86%) 236 210 (89%) lighttpd 54 47 (87%) 353 311 (88%) Nginx 218 161 (74%) 1,111 869 (78%) MySQL 7,532 5,771 (77%) 9,961 6,977 (70%)

21

slide-22
SLIDE 22

Precision

How accurate can we determine the prepared and used argument count?

Callsites Functions Server # As in source # As in source Memcached 48 41 (86%) 236 210 (89%) lighttpd 54 47 (87%) 353 311 (88%) Nginx 218 161 (74%) 1,111 869 (78%) MySQL 7,532 5,771 (77%) 9,961 6,977 (70%)

22

slide-23
SLIDE 23

processor() { ... while (condition){ arg1 = x arg2 = y CHECK TARGET: ID <= 2 call fptr(arg1,arg2) ... } ... }

ID: 2 Func1(arg1,arg2){ return arg1+arg2 }

Running example: TypeArmor

ID: 2 Func2(arg1,arg2){ return arg1*arg2 } ID: 3 Func3(arg1,arg2,arg3){ return arg3-arg1+arg2 }

Broken Gadget Loop gadget

  • Runtime enforcement

Working Gadget

23

slide-24
SLIDE 24

Performance

SPEC CPU2006: less than 3% (geometric mean)

24

slide-25
SLIDE 25

Performance

Server Overhead Language Memcached 1.4% C lighttpd 11.6% C Nginx 13.2% C MySQL 23.9% C++ SPEC CPU2006: less than 3% (geometric mean)

25

slide-26
SLIDE 26

Conclusion

  • Extract new invariants from binaries
  • Enforce strictest security policy at binary-level to date
  • Binary-level CFI solutions can mitigate sophisticated code-reuse attacks
  • Keep an eye on http://www.vusec.net

26