ss 6 Cl Class CSC 472/583 Software Security Return-oriented - - PowerPoint PPT Presentation

ss 6
SMART_READER_LITE
LIVE PREVIEW

ss 6 Cl Class CSC 472/583 Software Security Return-oriented - - PowerPoint PPT Presentation

ss 6 Cl Class CSC 472/583 Software Security Return-oriented programming (ROP) Dr. Si Chen (schen@wcupa.edu) Compile the code gcc -m32 fno-stack-protector z execstack o ./overflow2 ./overflow2.c Page 2 No eXecute (NX) -z


slide-1
SLIDE 1

CSC 472/583 Software Security Return-oriented programming (ROP)

  • Dr. Si Chen (schen@wcupa.edu)

Cl Class ss6

slide-2
SLIDE 2

Page § 2

Compile the code

gcc -m32 –fno-stack-protector –z execstack –o ./overflow2 ./overflow2.c

slide-3
SLIDE 3

Page § 3

No eXecute (NX)

§ -z execstack § Also known as Data Execution Prevention (DEP), this protection marks writable regions of memory as non-executable. § This prevents the processor from executing in these marked regions of memory.

slide-4
SLIDE 4

Page § 4

No eXecute (NX)

After the function returns, the program will set the instruction pointer to 0xbfff0000 and attempt to execute the instructions at that address. However, since the region of memory mapped at that address has no execution permissions, the program will crash.

slide-5
SLIDE 5

Page § 5

No eXecute (NX)

Thus, the attacker's exploit is thwarted.

slide-6
SLIDE 6

Page § 6

Data Execution Prevention (DEP): No eXecute bit (NX)

NX bit is a CPU feature

– On Intel CPU, it works only on x86_64 or with Physical

Address Extension (PAE) enable

Enabled, it raises an exception if the CPU tries to

execute something that doesn't have the NX bit set

The NX bit is located and setup in the Page Table Entry

slide-7
SLIDE 7

Page § 7

Page Table

  • Each process in a multi-tasking OS runs in its own memory

sandbox.

  • This sandbox is the virtual address space, which in 32-bit mode

is always a 4GB block of memory addresses.

  • These virtual addresses are mapped to physical memory by page

tables, which are maintained by the operating system kernel and consulted by the processor.

  • Each process has its own set of page tables.
slide-8
SLIDE 8

Page § 8

Page Table

To each virtual page there corresponds one page table entry (PTE) in the page tables, which in regular x86 paging is a simple 4-byte record shown below:

slide-9
SLIDE 9

Page § 9

Data Execution Prevention (DEP): No eXecute bit (NX)

  • The last bit is the NX bit (exb)

0 = disabled 1 = enabled

slide-10
SLIDE 10

Page § 10

Return-oriented programming (ROP)

slide-11
SLIDE 11

Page § 11

ROP Introduction

  • When Good Instructions Go Bad: Generalizing Return-

Oriented Programming to RISC

[1] -Buchanan, E.; Roemer, R.; Shacham, H.; Savage, S. (October 2008)

  • Return-Oriented Programming: Exploits Without Code Injection

[2] -

Shacham, Hovav; Buchanan, Erik; Roemer, Ryan; Savage, Stefan. Retrieved 2009-08-12.

slide-12
SLIDE 12

Page § 12

slide-13
SLIDE 13

Page § 13

Ordinary programming: the machine level

insn insn insn insn instruction pointer

  • Instruction pointer (EIP) determines which instruction to fetch

& execute

  • Once processor has executed the instruction, it automatically

increments EIP to next instruction

  • Control flow by changing value of EIP
slide-14
SLIDE 14

Page § 14

EIP

  • Instruction pointer (EIP) determines which instruction to fetch & execute
  • Once processor has executed the instruction, it automatically increments EIP to next

instruction

  • Control flow by changing value of EIP
slide-15
SLIDE 15

Page § 15

ROP: The Main Idea

slide-16
SLIDE 16

Page § 16

ROP Gadget “The Gadget”: July 1945

slide-17
SLIDE 17

Page § 17

Attack Process on x86

  • So, the real execution is:
  • Gadget1 is executed and returns
  • Gadget2 is executed and returns
  • Gadget3 is executed and returns
slide-18
SLIDE 18

Page § 18

How can we find gadgets?

Several ways to find gadgets

  • Old school method : objdump and grep
  • Some gadgets will be not found: objdump aligns

instructions

  • Make your own tool which scans an executable

segment

  • Use an existing tool
slide-19
SLIDE 19

Page § 19

Finding instruction sequences

  • Any instruction sequence ending in “ret” is useful —

could be part of a gadget

  • Algorithmic problem: recover all sequences of valid

instructions from libc that end in a “ret” insn

  • Idea: at each ret (c3 byte) lookback:
  • are preceding i bytes a valid length-i insn?
  • recurse from found instructions
  • Collect instruction sequences in a trie
slide-20
SLIDE 20

Page § 20

ROPgadget

slide-21
SLIDE 21

Page § 21

main() à vulnerable_function (hacked) à add_bin() à add_bash() à exec_string() à Spawn shell Execution Path

slide-22
SLIDE 22

Page § 22

x

à add_bin() à magic == 0xdeadbeef à add_bash() à magic1 == 0xcafebabe à magic2 == 0x0badf00d à exec_string() à Spawn shell Execution Path

slide-23
SLIDE 23

Page § 23

Basic Structure of Return Chaining

slide-24
SLIDE 24

Page § 24

Return Chaining

Function Address Return Address (Old EIP) Arguments

slide-25
SLIDE 25

Page § 25

Return Chaining

Dummy Character “A”s Address for Add_bin() Address for Add_bash() Address for exec_string()

Add_bin() Add_bash()

main() à vulnerable_function (hacked) à add_bash() à add_bin() à exec_string() à Spawn shell Execution Path

Exec_string() Without parameters, the ROP chain looks much simpler Similarly to lab1, we use gdb to adjust the length of the dummy characters to trigger buffer

  • verflow
slide-26
SLIDE 26

Page § 26

Return Chaining

Dummy Character “A”s Address for Add_bin() Address for Add_bash() 0xdeadbeef Address for exec_string()

Add_bin() Add_bash()

à add_bin() à magic == 0xdeadbeef à add_bash() à magic1 == 0xcafebabe à magic2 == 0x0badf00d à exec_string() à Spawn shell

Execution Path

Exec_string() For add_bin(), we need to pass 0xdeadbeef, So the ROP chain looks like:

à magic == 0xdeadbeef

Function Address Return Address (Old EIP) Arguments

Broken link

slide-27
SLIDE 27

Page § 27

Return Chaining

Dummy Character “A”s Address for Add_bin() Address for pop_ret 0xdeadbeef Address for Add_bash()

Add_bin() Add_bash()

à add_bin() à magic == 0xdeadbeef à add_bash() à magic1 == 0xcafebabe à magic2 == 0x0badf00d à exec_string() à Spawn shell

Execution Path

Exec_string() The previous ROP chain does not work, because argument 0xdeadbeef is still on the stack, we need to find a way to ”clean” it

à magic == 0xdeadbeef

Solution: use a pop, ret gadget to push the argument 0xdeadbeef into a register to remove it from the stack

slide-28
SLIDE 28

Page § 28

Return Chaining

Dummy Character “A”s Address for Add_bin() Address for pop_ret 0xdeadbeef Address for Add_bash() Address for pop_pop_ret 0xcafebabe 0x0badf00d

Add_bin() Add_bash()

à add_bin() à magic == 0xdeadbeef à add_bash() à magic1 == 0xcafebabe à magic2 == 0x0badf00d à exec_string() à Spawn shell

Execution Path

Exec_string() For add_bash(), we need to pass 0xcafebabe and 0x0badf00d, So we need to pop twice to remove both of them from the stack

à magic1 == 0xcafebabe à magic2 == 0x0badf00d

slide-29
SLIDE 29

Page § 29

Return Chaining

Dummy Character “A”s Address for Add_bin() Address for pop_ret 0xdeadbeef Address for Add_bash() Address for pop_pop_ret 0xcafebabe 0x0badf00d Address for exec_string()

Add_bin() Add_bash()

à add_bin() à magic == 0xdeadbeef à add_bash() à magic1 == 0xcafebabe à magic2 == 0x0badf00d à exec_string() à Spawn shell

Execution Path

Exec_string() Finally, call exec_string()

slide-30
SLIDE 30

Page § 30

slide-31
SLIDE 31

Page § 31

rop2.c

Since the binary is not big enough to give us a decent number of ROP gadgets, we will cheat a bit and compile the binary as a statically linked ELF. This should include library code in the final executable and bulk up the size of the binary.

slide-32
SLIDE 32

Page § 32

rop2.c

Since the binary is not big enough to give us a decent number of ROP gadgets, we will cheat a bit and compile the binary as a statically linked ELF. This should include library code in the final executable and bulk up the size of the binary.

slide-33
SLIDE 33

Page § 33

Linux Syscalls

§ Linux system calls or syscalls are interfaces between the user space application and the Linux kernel. § Functionality performed by the Linux kernel can be invoked by placing parameters into the right registers and passing control to the interrupt vector 0x80 using the int 0x80 opcode. Typically, this is not done by the program directly but by calling glibc wrappers.

fwrite() write() interrupt 0x80 sys_write() Kernel Application C Run Time Library API (Windows) Kernel ./program libc.a libc.so libc.a libc.so ./vlinuxz

slide-34
SLIDE 34

Page § 34

Linux System Call

http://syscalls.kernelgrok.com

slide-35
SLIDE 35

Page § 35

Linux System Call

§ Typically, we invoke this function in the following manner to spawn shells.

– execve("/bin/sh", {0}, {0})

slide-36
SLIDE 36

Page § 36

Linux System Call

§ f we take a look at the syscall reference, we can see that some parameters are expected in the eax, ebx, ecx, and edx registers.

– eax - holds the number of the syscall to be called – ebx - a pointer to the string containing the file name to be executed – ecx - a pointer to the array of string pointers representing argv – edx - a pointer to the array of string pointers representing envp

§ For our purposes, the value that each of the registers should contain are: eax = 0xb ebx = "/bin/sh" ecx = memory address -> 0 edx = memory address -> 0

slide-37
SLIDE 37

Page § 37