Memory (un)safety Deian Stefan Some slides adopted from Nadia - - PowerPoint PPT Presentation

memory un safety
SMART_READER_LITE
LIVE PREVIEW

Memory (un)safety Deian Stefan Some slides adopted from Nadia - - PowerPoint PPT Presentation

CSE 127: Computer Security Memory (un)safety Deian Stefan Some slides adopted from Nadia Heninger, Kirill Levchenko, Stefan Savage, Stephen Checkoway, Hovav Shacham, Raluca Popal, and David Wagner Today Return oriented programming (ROP)


slide-1
SLIDE 1

CSE 127: Computer Security

Memory (un)safety

Deian Stefan

Some slides adopted from Nadia Heninger, Kirill Levchenko, Stefan Savage, Stephen Checkoway, Hovav Shacham, Raluca Popal, and David Wagner

slide-2
SLIDE 2

Today

  • Return oriented programming (ROP)
  • Control flow integrity
slide-3
SLIDE 3

Last time: return-to-libc

  • Defense: W^X makes the stack not executable

➤ Prevents attacker data from being interpreted as code

  • What can we do (as the attacker)?

➤ Reuse existing code (either program or libc) ➤ E.g., use system(“/bin/sh”) ➤ E.g., use mprotect() to mark stack executable

slide-4
SLIDE 4

Return-to-libc is great, but…. what if there is no function that does what we want?

slide-5
SLIDE 5
slide-6
SLIDE 6

The Geometry of Innocent Flesh on the Bone: Return-into-libc without Function Calls (on the x86)

Hovav Shacham∗ hovav@cs.ucsd.edu

slide-7
SLIDE 7

Return-Oriented Programming

slide-8
SLIDE 8

Return-Oriented Programming

  • Idea: make shellcode out of existing code
  • Gadgets: code sequences ending in ret instruction

➤ Overwrite saved %eip on stack to pointer to first

gadget, then second gadget, etc.

slide-9
SLIDE 9

Return-Oriented Programming

  • Idea: make shellcode out of existing code
  • Gadgets: code sequences ending in ret instruction

➤ Overwrite saved %eip on stack to pointer to first

gadget, then second gadget, etc.

ret Steve Checkoway ret Dino Dai Zovi

slide-10
SLIDE 10

Return-Oriented Programming

  • Idea: make shellcode out of existing code
  • Gadgets: code sequences ending in ret instruction

➤ Overwrite saved %eip on stack to pointer to first

gadget, then second gadget, etc.

slide-11
SLIDE 11

Return-Oriented Programming

  • Idea: make shellcode out of existing code
  • Gadgets: code sequences ending in ret instruction

➤ Overwrite saved %eip on stack to pointer to first

gadget, then second gadget, etc.

  • Where do you often find ret instructions?
slide-12
SLIDE 12

Return-Oriented Programming

  • Idea: make shellcode out of existing code
  • Gadgets: code sequences ending in ret instruction

➤ Overwrite saved %eip on stack to pointer to first

gadget, then second gadget, etc.

  • Where do you often find ret instructions?

➤ End of function (inserted by compiler)

slide-13
SLIDE 13

Return-Oriented Programming

  • Idea: make shellcode out of existing code
  • Gadgets: code sequences ending in ret instruction

➤ Overwrite saved %eip on stack to pointer to first

gadget, then second gadget, etc.

  • Where do you often find ret instructions?

➤ End of function (inserted by compiler) ➤ Any sequence of executable memory ending in 0xc3

slide-14
SLIDE 14
slide-15
SLIDE 15

x86 instructions

  • Variable length!
  • Can begin on any byte boundary!
slide-16
SLIDE 16

b8 01 00 00 00 5b c9 c3 mov $0x1,%eax pop %ebx leave ret

One ret, multiple gadgets

=

slide-17
SLIDE 17

b8 01 00 00 00 5b c9 c3 add %al,(%eax) pop %ebx leave ret

=

One ret, multiple gadgets

slide-18
SLIDE 18

b8 01 00 00 00 5b c9 c3 add %bl,-0x37(%eax) ret

=

One ret, multiple gadgets

slide-19
SLIDE 19

b8 01 00 00 00 5b c9 c3 pop %ebx leave ret

=

One ret, multiple gadgets

slide-20
SLIDE 20

b8 01 00 00 00 5b c9 c3 leave ret

=

One ret, multiple gadgets

slide-21
SLIDE 21

b8 01 00 00 00 5b c9 c3 ret

=

One ret, multiple gadgets

slide-22
SLIDE 22

Why is ret?

  • Attacker overflows stack allocated buffer
  • What happens when function returns?

➤ Restore stack frame

➤ leave = movl %ebp, %esp; pop %ebp

➤ Return

➤ ret = pop %eip

  • If instruction sequence at %eip ends in ret


what do we do?

slide-23
SLIDE 23

%esp v1 pop %edx ret

What happens if this is what we

  • verflow the stack with?
slide-24
SLIDE 24

%esp 0xdeadbeef 0x08049bbc 0x08049bbc: pop %edx 0x08049bbd: ret 0x08049b62: nop 0x08049b63: ret ... %eip %edx = 0x00000000

relevant register(s): relevant code: relevant stack:

slide-25
SLIDE 25

%esp 0xdeadbeef 0x08049bbc 0x08049bbc: pop %edx 0x08049bbd: ret 0x08049b62: nop 0x08049b63: ret ... %eip %edx = 0x00000000

relevant register(s): relevant code: relevant stack:

slide-26
SLIDE 26

%esp 0xdeadbeef 0x08049bbc 0x08049bbc: pop %edx 0x08049bbd: ret 0x08049b62: nop 0x08049b63: ret ... %eip %edx = 0x00000000

relevant register(s): relevant code: relevant stack:

slide-27
SLIDE 27

%esp 0xdeadbeef 0x08049bbc 0x08049bbc: pop %edx 0x08049bbd: ret 0x08049b62: nop 0x08049b63: ret ... %eip %edx = 0xdeadbeef

relevant register(s): relevant code: relevant stack:

slide-28
SLIDE 28

This is a ROP gadget!

%esp v1 pop %edx ret

movl v1, %edx

slide-29
SLIDE 29
  • Overflow the stack with values and addresses to

such gadgets to express your program

  • E.g., if shellcode needs to write a value to %edx,

use the previous gadget
 
 
 


v1

How dow you use this as an attacker?

%esp pop %edx ret

slide-30
SLIDE 30

v2 v1

Let’s look at another gadget

%esp pop %eax ret pop %ebx ret mov %eax, %(ebx) ret

slide-31
SLIDE 31

0x08049b90 0xbadcaffe 0x08049b63 0xdeadbeef 0x08049bbc %esp 0x08049bbc: pop %eax 0x08049bbd: ret 0x08049b63: pop %ebx 0x08049b64: ret ... %eip %eax = 0x00000000 %ebx = 0x00000000

relevant register(s): relevant code: relevant stack:

0x08049b90: mov %eax, %(ebx) 0x08049b91: ret ...

relevant memory:

0x08049b00: ret ... 0xbadcaffe: 0x00000000

slide-32
SLIDE 32

0x08049b90 0xbadcaffe 0x08049b63 0xdeadbeef 0x08049bbc %esp 0x08049bbc: pop %eax 0x08049bbd: ret 0x08049b63: pop %ebx 0x08049b64: ret ... %eip %eax = 0x00000000 %ebx = 0x00000000

relevant register(s): relevant code: relevant stack:

0x08049b90: mov %eax, %(ebx) 0x08049b91: ret ...

relevant memory:

0x08049b00: ret ... 0xbadcaffe: 0x00000000

slide-33
SLIDE 33

0x08049b90 0xbadcaffe 0x08049b63 0xdeadbeef 0x08049bbc %esp 0x08049bbc: pop %eax 0x08049bbd: ret 0x08049b63: pop %ebx 0x08049b64: ret ... %eip %eax = 0xdeadbeef %ebx = 0x00000000

relevant register(s): relevant code: relevant stack:

0x08049b90: mov %eax, %(ebx) 0x08049b91: ret ...

relevant memory:

0x08049b00: ret ... 0xbadcaffe: 0x00000000

slide-34
SLIDE 34

0x08049b90 0xbadcaffe 0x08049b63 0xdeadbeef 0x08049bbc %esp 0x08049bbc: pop %eax 0x08049bbd: ret 0x08049b63: pop %ebx 0x08049b64: ret ... %eip %eax = 0xdeadbeef %ebx = 0x00000000

relevant register(s): relevant code: relevant stack:

0x08049b90: mov %eax, %(ebx) 0x08049b91: ret ...

relevant memory:

0x08049b00: ret ... 0xbadcaffe: 0x00000000

slide-35
SLIDE 35

0x08049b90 0xbadcaffe 0x08049b63 0xdeadbeef 0x08049bbc %esp 0x08049bbc: pop %eax 0x08049bbd: ret 0x08049b63: pop %ebx 0x08049b64: ret ... %eip %eax = 0xdeadbeef %ebx = 0xbadcaffe

relevant register(s): relevant code: relevant stack:

0x08049b90: mov %eax, %(ebx) 0x08049b91: ret ...

relevant memory:

0x08049b00: ret ... 0xbadcaffe: 0x00000000

slide-36
SLIDE 36

0x08049b90 0xbadcaffe 0x08049b63 0xdeadbeef 0x08049bbc %esp 0x08049bbc: pop %eax 0x08049bbd: ret 0x08049b63: pop %ebx 0x08049b64: ret ... %eip %eax = 0xdeadbeef %ebx = 0xbadcaffe

relevant register(s): relevant code: relevant stack:

0x08049b90: mov %eax, %(ebx) 0x08049b91: ret ...

relevant memory:

0x08049b00: ret ... 0xbadcaffe: 0x00000000

slide-37
SLIDE 37

0x08049b90 0xbadcaffe 0x08049b63 0xdeadbeef 0x08049bbc %esp 0x08049bbc: pop %eax 0x08049bbd: ret 0x08049b63: pop %ebx 0x08049b64: ret ... %eip %eax = 0xdeadbeef %ebx = 0xbadcaffe

relevant register(s): relevant code: relevant stack:

0x08049b90: mov %eax, %(ebx) 0x08049b91: ret ... 0xbadcaffe: 0xdeadbeef

relevant memory:

0x08049b00: ret ...

slide-38
SLIDE 38

v2 v1

What does this gadget do?

%esp pop %eax ret pop %ebx ret mov %eax, %(ebx) ret

movl v2, %ebx movl v1, %(%ebx)

slide-39
SLIDE 39

What does this gadget do?

%esp pop %esp ret

slide-40
SLIDE 40

Can express arbitrary programs

slide-41
SLIDE 41

Can find gadgets automatically

slide-42
SLIDE 42

Return-oriented programming

not even really about “returns”…

slide-43
SLIDE 43

What the heck do we do?

Observation: In almost all the attacks we looked at, the attacker is overwriting jump targets that are in memory (return addresses and function pointers)

slide-44
SLIDE 44

Control Flow Integrity

  • Idea: don’t try to stop the memory writes.

Instead: restrict control flow to legitimate paths

➤ I.e., ensure that jumps, calls, and returns can only go

to allowed target destinations

slide-45
SLIDE 45

Restrict indirect transfers of control

slide-46
SLIDE 46
  • Why do we not need to do anything about direct

transfer of control flow (i.e., direct jumps/calls)?

Restrict indirect transfers of control

slide-47
SLIDE 47
  • Why do we not need to do anything about direct

transfer of control flow (i.e., direct jumps/calls)?

➤ Address is hard-coded in instruction. Not under

attacker control

Restrict indirect transfers of control

slide-48
SLIDE 48

Restrict indirect transfers of control

slide-49
SLIDE 49

Restrict indirect transfers of control

  • What are the ways to transfer control indirectly?
slide-50
SLIDE 50

Restrict indirect transfers of control

  • What are the ways to transfer control indirectly?
  • Forward path: jumping to (or calling function at)

an address in register or memory

➤ E.g., qsort, interrupt handlers, virtual calls, etc.

  • Reverse path: returning from function (uses

address on stack)

slide-51
SLIDE 51

What’s a legitimate target?

Look at the program control-flow graph (CFG)!

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

slide-52
SLIDE 52

call sort call sort ret sort2()

What’s a legitimate target?

Look at the program control-flow graph (CFG)!

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

slide-53
SLIDE 53

call sort call sort ret sort2() sort() ret

call arg$3

What’s a legitimate target?

Look at the program control-flow graph (CFG)!

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

slide-54
SLIDE 54

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

What’s a legitimate target?

Look at the program control-flow graph (CFG)!

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

slide-55
SLIDE 55

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

What’s a legitimate target?

Look at the program control-flow graph (CFG)!

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

slide-56
SLIDE 56

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

What’s a legitimate target?

Look at the program control-flow graph (CFG)!

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

slide-57
SLIDE 57

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

What’s a legitimate target?

Look at the program control-flow graph (CFG)!

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

slide-58
SLIDE 58

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

What’s a legitimate target?

Look at the program control-flow graph (CFG)!

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

slide-59
SLIDE 59

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

What’s a legitimate target?

Look at the program control-flow graph (CFG)!

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

slide-60
SLIDE 60

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

What’s a legitimate target?

Look at the program control-flow graph (CFG)!

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

slide-61
SLIDE 61

How do we restrict jumps to CFG?

  • Assign labels to all indirect jumps and their targets
  • Before taking an indirect jump, validate that target

label matches jump site

➤ Like stack canaries, but for for control flow target

  • Need hardware support

➤ Otherwise trade off precision for performance

slide-62
SLIDE 62

Fine grained CFI (Abadi et al.)

  • Statically compute CFG
  • Dynamically ensure program never deviates

➤ Assign label to each target of indirect transfer ➤ Instrument indirect transfers to compare label of

destination with the expected label to ensure it's valid

slide-63
SLIDE 63

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

Fine grained CFI (Abadi et al.)

slide-64
SLIDE 64

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

label 1 label 1

Fine grained CFI (Abadi et al.)

slide-65
SLIDE 65

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

label 1 label 1

check 1 then

Fine grained CFI (Abadi et al.)

slide-66
SLIDE 66

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

label 2 label 1 label 1

check 1 then

Fine grained CFI (Abadi et al.)

slide-67
SLIDE 67

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

label 2 label 1 label 1

check 1 then

check 2 then check 2 then

Fine grained CFI (Abadi et al.)

slide-68
SLIDE 68

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

label 2 label 3 label 3 label 1 label 1

check 1 then

check 2 then check 2 then

Fine grained CFI (Abadi et al.)

slide-69
SLIDE 69

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

void sort2(int a[],int b[], int len {
 sort(a, len, lt);
 sort(b, len, gt);
 }
 
 bool lt(int x, int y) { return x < y; }
 
 bool gt(int x, int y) { return x > y; }

direct call indirect call return

label 2 label 3 label 3 label 1 label 1

check 1 then

check 2 then check 2 then check 3 then

Fine grained CFI (Abadi et al.)

slide-70
SLIDE 70

Coarse-grained CFI (bin-CFI)

  • Label for destination of

indirect calls

➤ Make sure that every

indirect call lands on function entry

  • Label for destination of

rets and indirect jumps

➤ Make sure every

indirect jump lands at start of BB

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

slide-71
SLIDE 71

Coarse-grained CFI (bin-CFI)

  • Label for destination of

indirect calls

➤ Make sure that every

indirect call lands on function entry

  • Label for destination of

rets and indirect jumps

➤ Make sure every

indirect jump lands at start of BB

call sort call sort ret sort2() ret lt() ret gt() sort() ret

call arg$3

check then ret-label ret-label ret-label func-label func-label

check then

check then check then

slide-72
SLIDE 72

How else can you choose labels?

slide-73
SLIDE 73

How else can you choose labels?

WebAssembly does it by looking at function type

slide-74
SLIDE 74

CFI limitations

  • Overhead

➤ Runtime: every indirect branch instruction ➤ Size: code before indirect branch + encode label at

destination

  • Scope

➤ CFI does not protect against data-only attacks ➤ Needs reliable W^X

slide-75
SLIDE 75
  • Imprecision can allow for control-flow hijacking

➤ Can jump to functions that have same label

➤ E.g., even if we use Wasm’s labels int

system(char*) and int myFunc(char*) share the same label

➤ Can return to many more sites

➤ But, real way to do backward edge CFI is to use a

shadow stack. (This is actually great!)

How can you defeat CFI?

slide-76
SLIDE 76
  • Imprecision can allow for control-flow hijacking

➤ Can jump to functions that have same label

➤ E.g., even if we use Wasm’s labels int

system(char*) and int myFunc(char*) share the same label

➤ Can return to many more sites

➤ But, real way to do backward edge CFI is to use a

shadow stack. (This is actually great!)

How can you defeat CFI?

slide-77
SLIDE 77
  • Imprecision can allow for control-flow hijacking

➤ Can jump to functions that have same label

➤ E.g., even if we use Wasm’s labels int

system(char*) and int myFunc(char*) share the same label

➤ Can return to many more sites

➤ But, real way to do backward edge CFI is to use a

shadow stack. (This is actually great!)

How can you defeat CFI?

slide-78
SLIDE 78

Today

  • Return oriented programming (ROP)
  • Control flow integrity