Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Return-oriented programming
Sebastian Neuser
Hackspace Siegen
May 8, 2014
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
1 IntroductionWhat is return-oriented programming?Before we begin...ExamplesHistory
2 Return-oriented programming in a nutshellx86 crash courseStack buffer overflowGadgets
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
3 DemonstrationROPgadget – a ROP compilerStupid vulnerable programShowtime!
4 CountermeasuresASLR and PIEStack canaries and shadow stacksCFI and ROPdefender
5 Conclusion
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
1 IntroductionWhat is return-oriented programming?Before we begin...ExamplesHistory
2 Return-oriented programming in a nutshell
3 Demonstration
4 Countermeasures
5 Conclusion
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
What is return-oriented programming?
Buffer overflow vulnerabilities
simple example:
• fixed size character buffer
• program reads a string from the keyboard and copies it to thebuffer without bounds checking
• number of input characters > buffer size ; buffer overflow
• variables on the stack are overwritten – possibly including thecurrent function’s return address
• best case scenario: SIGSEGV
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
What is return-oriented programming?
Return-oriented programming
• generalization of return-to-libc exploitation
• attacker uses buffer overflow-vulnerability or something similarto inject return addresses into the stack
• return-to-libc-exploits chain together calls to libraryfunctions (libc in most cases)
• return-oriented exploits jump a few instructions before afunction’s ret to perform small operations
By carefully chaining together such jumps, an attacker can performarbitrary computations!
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
What is return-oriented programming?
Why care?
• 45% of all recorded security vulnerabilities in Ubuntu:; buffer overflow vulnerabilities
• buffer overflow exploits have been implemented in numerousmalicious programs across different platforms
• Return-oriented programming:• probably the most advanced buffer overflow exploitation
technique so far• developed and refined over decades
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Before we begin...
Terms of service
• Although I don’t intend to, unfortunately I tend to• become overzealous,• talk too fast and• speak with a slur.
; Please insult me, if I do!
• By sitting here and listening to the talk, you agree that• you will not use the knowledge provided here to harm anyone,• I am not responsible for anything you break while messing
around with the techniques I present,• vim is the name of the one true editor,• proprietary software is inherently evil.
• Feel free to ask questions at any time.
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Before we begin...
Stack diagrams
Stack diagrams are depicted from the stack’s top to bottom:
pointers addresses values
stack top 0xbf8c73c0:
0xbf8c73c4:
0xbf8c73c8:
0x1337c0de
0xdeadc0de
0xdeadbeef
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Before we begin...
Platform
Examples and demo compiled and tested with
• gcc version 4.7.2
• gdb version 7.4.1
• 32 bit Debian GNU/Linux 7.1; instruction set architecture: IA-32
• Intel Core 2 Duo P7450
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Examples
Computer worms
• The Morris worm aka. ”Great Worm”• utilized a buffer overflow-vulnerability in the fingerd program
on Unix systems• rendered infected systems unusable within 90 minutes
• The Slammer worm• used buffer overflow-vulnerabilities in Microsoft’s ”SQL Server
2000” and ”Desktop Engine 2000”• infected roughly 75000 servers in approximately 30 minutes• caused network overloads on a great scale
• The Sasser worm• exploited a vulnerability in Microsoft’s LSASS• caused systems to shut down
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
History
Timeline of buffer overflow exploits
1988 Morris worm
1996 Aleph One: ”Smashing The Stack For Fun And Profit”
1997 Solar Designer: return-to-libc basics
1998 Solar Designer: security patch for the Linux kernel
2000 PaX: Implementation of W⊕X2001 Nergal: function chaining with return-to-libc
2007 Hovav Shacham: ”Return-into-libc without function calls”; return-oriented programming
since more and more proof, that return-oriented programming is areal threat
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
1 Introduction
2 Return-oriented programming in a nutshellx86 crash courseStack buffer overflowGadgets
3 Demonstration
4 Countermeasures
5 Conclusion
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
Register set
%eax holds the return value of a function call.
%ebx holds a pointer to some data.
%ecx is used for counters in string- and loop instructions.
%edx holds a I/O pointers.
%esi is the source pointer in some instructions.
%edi is the destination pointer in some instructions.
%ebp is the stack frame- or base pointer.
%esp is the stack pointer.
%eip is the instruction pointer.
%eflags is the status and control register.
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
Instruction set
mov %esp, %ebp Copies the stack pointer %esp to the basepointer %ebp.
push %ebp Updates the stack pointer %esp and writesthe value of %ebp to the new top of the stack.
pop %ebp Reads the value at the top of the stack – thememory location that %esp points to, writesit into %ebp and discards the value from thestack by adjusting %esp.
call func Pushes the return address, which is the ad-dress of the next instruction (%eip+5) ontothe stack and jumps to the instruction la-beled by ”func:”.
ret Pops the return address from the top of thestack and writes it into %eip.
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
The stack
• data section in a process’ address space
• contains local variables and buffers
• arguments to function calls and return addresses are alsoimplemented using the stack
• x86 -family of CPUs:• stack grows from higher to lower memory addresses• memory is addressed byte-wise
; push decrements %esp by 4, pop increments %esp by 4
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
Function calls – cdecl
• parameters are pushed to the stack in reverse order
• call pushes the address of the next instruction onto the stack
• function prologue (enter):• save the base pointer %ebp• copy %esp to %ebp for base pointer addressing• decrement %esp to allocate stack memory for local variables
• function epilogue (leave):• discard local variables by copying %ebp to %esp• restore %ebp by popping it from the stack
• ret pops the return address off the stack and jumps to it
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
Function calls – stack diagram
%esp
%ebp
0xbf8c73d0:
0xbf8c73d4:
local var 0
saved %ebp
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
Function calls – stack diagram
%esp
%ebp
0xbf8c73cc:
0xbf8c73d0:
0xbf8c73d4:
parameter 2
local var 0
saved %ebp
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
Function calls – stack diagram
%esp
%ebp
0xbf8c73c8:
0xbf8c73cc:
0xbf8c73d0:
0xbf8c73d4:
parameter 1
parameter 2
local var 0
saved %ebp
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
Function calls – stack diagram
%esp
%ebp
0xbf8c73c4:
0xbf8c73c8:
0xbf8c73cc:
0xbf8c73d0:
0xbf8c73d4:
parameter 0
parameter 1
parameter 2
local var 0
saved %ebp
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
Function calls – stack diagram
%esp
%ebp
0xbf8c73c0:
0xbf8c73c4:
0xbf8c73c8:
0xbf8c73cc:
0xbf8c73d0:
0xbf8c73d4:
return addr
parameter 0
parameter 1
parameter 2
local var 0
saved %ebp
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
Function calls – stack diagram
%esp
%ebp
0xbf8c73bc:
0xbf8c73c0:
0xbf8c73c4:
0xbf8c73c8:
0xbf8c73cc:
0xbf8c73d0:
0xbf8c73d4:
saved %ebp
return addr
parameter 0
parameter 1
parameter 2
local var 0
saved %ebp
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
Function calls – stack diagram
%esp,%ebp 0xbf8c73bc:
0xbf8c73c0:
0xbf8c73c4:
0xbf8c73c8:
0xbf8c73cc:
0xbf8c73d0:
0xbf8c73d4:
saved %ebp
return addr
parameter 0
parameter 1
parameter 2
local var 0
saved %ebp
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
x86 crash course
Function calls – stack diagram
%esp
%ebp
0xbf8c73b4:
0xbf8c73b8:
0xbf8c73bc:
0xbf8c73c0:
0xbf8c73c4:
0xbf8c73c8:
0xbf8c73cc:
0xbf8c73d0:
0xbf8c73d4:
local var 1
local var 0
saved %ebp
return addr
parameter 0
parameter 1
parameter 2
local var 0
saved %ebp
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stack buffer overflow
Before...
%esp
%ebp
0xbffff8b4:
0xbffff8b8:
0xbffff8bc:...
0xbffff93c:
0xbffff940:
0xbffff944:
buffer[0]
buffer[1]
. . .
local var 1
local var 0
saved %ebp
return addr
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stack buffer overflow
Meanwhile...
%esp
%ebp
0xbffff8b4:
0xbffff8b8:
0xbffff8bc:...
0xbffff93c:
0xbffff940:
0xbffff944:
buffer[0]
buffer[1]
. . .
local var 1
local var 0
saved %ebp
return addr
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stack buffer overflow
Meanwhile...
%esp
%ebp
0xbffff8b4:
0xbffff8b8:
0xbffff8bc:...
0xbffff93c:
0xbffff940:
0xbffff944:
buffer[0]
buffer[1]
. . .
local var 1
local var 0
saved %ebp
return addr
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stack buffer overflow
Meanwhile...
%esp
%ebp
0xbffff8b4:
0xbffff8b8:
0xbffff8bc:...
0xbffff93c:
0xbffff940:
0xbffff944:
buffer[0]
buffer[1]
. . .
local var 1
local var 0
saved %ebp
return addr
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stack buffer overflow
Meanwhile...
%esp
%ebp
0xbffff8b4:
0xbffff8b8:
0xbffff8bc:...
0xbffff93c:
0xbffff940:
0xbffff944:
buffer[0]
buffer[1]
. . .
local var 1
local var 0
saved %ebp
return addr
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stack buffer overflow
Boom!
%esp
%ebp
0xbffff8b4:
0xbffff8b8:
0xbffff8bc:...
0xbffff93c:
0xbffff940:
0xbffff944:
buffer[0]
buffer[1]
. . .
local var 1
local var 0
saved %ebp
return addr
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Gadgets
What is a gadget?
• attacker searches for short instruction sequences that performsmall tasks and end with ret
; for example poping some values into registers
• gadget: combination of one or more addresses of shortinstruction sequences and the values that they should pop offthe stack
• payload : chain of gadgets
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Gadgets
A very simple gadget
ret addr
. . .
{prev gadg}
0x0000002a
{next gadg}. . .
pop %eax
ret
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
1 Introduction
2 Return-oriented programming in a nutshell
3 DemonstrationROPgadget – a ROP compilerStupid vulnerable programShowtime!
4 Countermeasures
5 Conclusion
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
ROPgadget – a ROP compiler
ROPgadget
• finds and lists gadgets that are available in a specified binary
• constructs shellcode, a payload that opens a network socketor user-specified opcodes
• prints out python commands that can be embedded in apayload generation script
• searches and prints out addresses of instructions/opcodes andstrings in a binary
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stupid vulnerable program
log.h
1 //// io.c ////
2
3 // Appends the buffer to the log-file specified by the path
4 void append_log(char* buffer, char* path);
5
6 // Reads an input string to the buffer until EOF is read
7 void read_string_till_eof(char* buffer);
8
9
10
11 //// util.c ////
12
13 // Checks the program arguments
14 void check_args(int count, char* vector[]);
15
16 // Returns a string that describes the current timestamp
17 char* get_time_string(void);
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stupid vulnerable program
log.c
1 #include <string.h>
2 #include "log.h"
3
4 int main(int argc, char* argv[])
5 {
6 check_args(argc, argv);
7
8 char buffer[512];
9 char logfile_path[32];
10
11 strcpy(logfile_path, argv[1]);
12 if (!strcasestr(logfile_path, ".log"))
13 strcat(logfile_path, ".log");
14
15 read_string_till_eof(buffer);
16 append_log(buffer, logfile_path);
17 return 0;
18 }
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stupid vulnerable program
io.c
1 #include <stdio.h>
2 #include "log.h"
3
4 void append_log(char* buffer, char* path)
5 {
6 FILE* fp = fopen(path, "a");
7 fprintf(fp, "%s: %s\n", get_time_string(), buffer);
8 fclose(fp);
9 }
10
11 void read_string_till_eof(char* buffer)
12 {
13 int c;
14 while ((c=getchar()) && c != EOF) {
15 *buffer++ = c;
16 }
17 printf("\n");
18 }
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stupid vulnerable program
util.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <time.h>
5
6 void check_args(int count, char* vector[])
7 {
8 if (count != 2) {
9 printf("Usage: log <log file>\n");
10 exit(0);
11 }
12 }
13
14 char* get_time_string(void)
15 {
16 time_t timestamp = time(NULL);
17 char* time_string = ctime(×tamp);
18 time_string[strlen(time_string)-1] = ’\0’;
19 return time_string;
20 }
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Showtime!
The fun part...
”For a moment, nothing happened.Then, after a second or so, nothing continued to happen.”
- Douglas Adams, The Hitchhiker’s Guide to the Galaxy
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
1 Introduction
2 Return-oriented programming in a nutshell
3 Demonstration
4 CountermeasuresASLR and PIEStack canaries and shadow stacksCFI and ROPdefender
5 Conclusion
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
ASLR and PIE
ASLR and PIE
• Address Space Layout Randomization
• Position Independent Executable
• take effect at load and link time during program startup
• in the PaX implementation, the addresses of the followingsegments are randomized:
• .text-segment of the binary (; executable code)• dynamically linked libraries• the stack• the heap
• libraries in themselves are not randomized; randomization can be overcome by brute-force attacksand/or through information leakage
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stack canaries and shadow stacks
Stack canaries – Explanation
• canary word: word between local variables of a function andthe return address
• during function prologue: canary word is placed on the stackand backed up in a different location
• during function epilogue: canary word is verified throughcomparison with the stored value
• word has changed (; the canary is dead §); program is terminated with a warning message
• Example: StackGuard
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stack canaries and shadow stacks
Stack canaries – Diagram
%esp
%ebp
0xbf9358bc:...
0xbf935924:
0xbf935928:
0xbf93592c:
buffer
. . .
canary
saved %ebp
return addr
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Stack canaries and shadow stacks
Shadow stacks
• TRUSS : maintains shadow stack, which stores returnaddresses
• function prologue: modified to push the correct return addressonto the shadow stack
• epilogue: compares return addresses
• mismatch ; program termination and error signal
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
CFI and ROPdefender
Control Flow Integrity
• control flow graph maps all function calls
• function prologues and epilogues are modified at runtime
• targets of call and ret instructions are correlated with theanticipated control flow in the graph
• opcodes do not match ; program is aborted
• significant computational overhead with a factor typically inthe range of [1.5, 3.5]
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
CFI and ROPdefender
ROPdefender
• ROPdefender also maintains a shadow stack
• capable of detecting unintended instruction sequences
• return address of every call instruction is pushed onto theshadow stack
• every ret instruction: comparison of the destination addressto the top of the shadow stack
• program is aborted if the addresses do not match
• computational overhead similar to CFI
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
1 Introduction
2 Return-oriented programming in a nutshell
3 Demonstration
4 Countermeasures
5 Conclusion
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Summary
• long evolution from direct code injection to ROP
• applicable to many popular architectures
• quite complex technique
• relatively recent ; few effective countermeasures
• frameworks for automation of payload generation
• ; serious threat!
• But: It’s fun! ©
Return-oriented programming Sebastian Neuser
Introduction Return-oriented programming in a nutshell Demonstration Countermeasures Conclusion
Thanks for your attention.
Questions?
Return-oriented programming Sebastian Neuser