130
An Introduction to Buffer Overflow Exploits Bart Coppens

An Introduction to Buffer Overflow Exploits Bart Coppens

Embed Size (px)

Citation preview

An Introduction toBuffer Overflow Exploits

Bart Coppens

General Note

This slide deck is based on a set of presentations I gave, so take note that:• I tend to use lots of figures and give lots of additional detail by

explaining those figures, rather than adding text. Slides without my (over)enthousiastic explanations lose a lot of that

• I also gave some very quick demo’s, you’ll miss those too• There were some hands-on excercises (including a real-life one

based on a proftpd vulnerability from 2010), but I haven’t cleaned those up yet

• I had some ‘zen’ slides consisting of CC-licensed pictures of cute puppies, kittens, etc. to make the audience feel less brain-dead, but they made this merged presentation’s file size a bit too large

Exploits 1:Basic Buffer Overflows & Shellcode

Bart Coppens

We’ll be abusing vulnerabilities in code

A kind of vulnerability The attack code we’llbe executing

Structure

• Basic exploits– Intro to buffer-overflows, exploits & shellcode– No protections, just like the good old days of the

mid-‘90s (executable stacks, no ASLR, …)• Advanced exploits– Protections against buffer-overflow-based exploits

(non-executable stacks, ASLR, …)– How to circumvent these (ROP, …)

Part 1: Basic Exploitsx86-64 assembly crash course

A look at buffers are implemented in assembly

Buffer overflows

How to execute the attack code

Normal program behavior

xor %rax,%raxretq

callq function

int function() { return 0;}

…int i = function();… movq %rax, …

Normal program behavior

rsp

xor %rax,%raxretq

callq function

movq %rax, …

Higher addresses

Stack frame of main

Normal program behavior

Stack frame of main

rsp Return address to main

xor %rax,%raxretq

callq function

movq %rax, …

Higher addresses

Normal program behavior

xor %rax,%raxretq

callq function

movq %rax, …

rsp

Higher addresses

Stack frame of main

Local variables and the stack

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

int silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

function(%rdi, %rsi, %rdx)

Local variables and the stack

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

int silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

function(%rdi, %rsi, %rdx)

Local variables and the stack

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

int silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

function(%rdi, %rsi, %rdx)

Local variables and the stack

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

int silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

function(%rdi, %rsi, %rdx)

0x64 bytes

Local variables and the stack

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

int silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

rsp Return address to main

rsp

buffer[0]

buffer[99]

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

Return address to main

0x64 bytes

rsp

rdi sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

Return address to main

0x64 bytes

Return address etc

rdi

rsp

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

Return address to main

0x64 bytes

Return address etc

rdi

rsp

… sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

H e l l

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

Return address to main

0x64 bytesrdi

rsp … sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

H e l l

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

Return address to main

0x64 bytesrdi

rsp … sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

H e l l

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

Return address to main

rdi

rsp

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

Return address to main

rdi

rsp

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(50, "Hello\n");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

Return address to main

0x64 bytesrdi

rsp …

buffer[100]

buffer[99]

buffer[107]

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

H e l l

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "Hello…ABCDEFGH");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

Return address to main

0x64 bytesrdi

rsp …

buffer[100]

buffer[99]

buffer[107]

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

H e l l

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "Hello…ABCDEFGH");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

B C D E F G

0x64 bytesrdi

rsp …

buffer[100]

buffer[99]

buffer[107]A H

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

H e l l

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "Hello…ABCDEFGH");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

rsp B C D E F G

rdi

A H

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "Hello…ABCDEFGH");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

rsp B C D E F G

rdi

A H

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "Hello…ABCDEFGH");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

B C D E F G

rdi

rsp

A H

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…ABCDEFGH");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

B C D E F G

rdi

rsp

A H

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…ABCDEFGH");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

B C D E F G

rdi

A H

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

0x123

rsp

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

0 0 0 0 1 2

rdi

0 3

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

0x123

rsp

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

rsp 0 0 0 0 1 2

rdi

0 3

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

0x123

Local variables and the stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack frame of main…

function(%rdi, %rsi, %rdx)

rsp 0 0 0 0 1 2

rdi

0 3

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

0x123

Demo

Sorry, here was a live demo that starts from showing how certain inputs crash a program and analysing that in gdb, to writing & executing very simple shell code. Maybe one day I’ll make screenshots + captions

Exploits part 2Buffer Overflows:

Mitigations & Advanced Exploits

Bart Coppens

Overview

• Recap• Non-executable stack & ROP• Function pointers• Address Space Layout Randomization• Stack reading• Hands-on!

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

return address

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

buffer

0x123

rsp

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

0 0 0 0 1 20 3

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

0x123

rsp

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

0 0 0 0 1 20 3

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

0x123

rsp

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

0x123

rsp

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

0x123

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

0 0 0 0 1 20 3

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

rsp

0x12F

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

0 0 0 0 1 20 3

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

0x12F

rsp

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

0 0 0 0 1 20 3

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

0x12F

rsp

(garbage instructions)

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

0 0 0 0 1 20 3

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

nopnopnopmovq $0, %rax…

rsp NOP slide/sled

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

nopnopnopmovq $0, %rax…

NOP slide/sled

rsp

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

nopnopnopmovq $0, %rax…

NOP slide/sled

rsp

Executable stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

nopnopnopmovq $0, %rax…

NOP slide/sled

rsp

Non-Executable Stackint silly_function(int len, char* src) { char buffer[100]; memcpy(buffer, src, len); return 0;}

int main() { return silly_function(108, "\x48\xc7…230100…");}

adresses

Stack of ‘main’…

function(%rdi, %rsi, %rdx)

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

rsp

Stack memory mappedas non-executable!

Non-Executable Stack

adresses

Stack of ‘main’…

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

movq $0, %rax…syscall

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

4KR,W

rsp

Non-Executable Stack

adresses

Stack of ‘main’…

0 0 0 0 1 20 3

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

4KR,W

Return-to-libc

adresses

Stack of ‘main’…

0 0 0 0 1 20 3

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

4KR,W

Return-to-libc

adresses

Stack of ‘main’…

address of exit

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

4KR,W

Return-to-libc

adresses

Stack of ‘main’…

address of system

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>xor %rax,%raxadd $0x64, %rspretq

rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

4KR,W

Return-to-libc

adresses

Stack of ‘main’…

address of systemesp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

32 bit

4KR,W

…xor %eax,%eaxadd $0x64, %espret

Return-to-libc

adresses

Stack of ‘main’…

address of system

esp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

32 bit

garbage (‘return addr.’)

argument 1

argument 2

argument 3

4KR,W

…xor %eax,%eaxadd $0x64, %espret

overflown buffer

Return-to-libc

adresses

Stack of ‘main’…

address of systemesp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

32 bit

garbage (‘return addr.’)

argument 1

argument 2

argument 3

4KR,W

…xor %eax,%eaxadd $0x64, %espret

overflown buffer

Return-to-libc

adresses

Stack of ‘main’…

address of system

esp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

32 bit

garbage (‘return addr.’)

argument 1

argument 2

argument 3

4KR,W

…xor %eax,%eaxadd $0x64, %espret

overflown buffer

Return-to-libc

adresses

Stack of ‘main’…

address of system

esp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

32 bit

garbage (‘return addr.’)

argument 1

argument 2

argument 3

4KR,W

…xor %eax,%eaxadd $0x64, %espret

overflown buffer

Return-to-libc

adresses

Stack of ‘main’…

address of system

esp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

32 bit

garbage (‘return addr.’)

ptr. to “/bin/sh”

argument 2

argument 3

4KR,W

…xor %eax,%eaxadd $0x64, %espret

overflown buffer

Return-to-libc

adresses

Stack of ‘main’…

address of system

esp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

32 bit

garbage (‘return addr.’)

ptr. to “/bin/sh”

argument 2

argument 3

4KR,W

…xor %eax,%eaxadd $0x64, %espret

overflown buffer

can be used to executea second function!

Return-to-libc

adresses

Stack of ‘main’…

address of system

rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

garbage (‘return addr.’)

ptr. to “/bin/sh”

argument 2

argument 3

4KR,W

…xor %rax,%raxadd $0x64, %rspret

overflown bufferArguments in registers!

fun(%rdi,%rsi,%rdx)

Return-to-libc

adresses

Stack of ‘main’…

rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

4KR,W

xor %rax,%raxadd $0x64, %rspret

overflown bufferArguments in registers!

fun(%rdi,%rsi,%rdx)

Return-Oriented Programming

adresses

Stack of ‘main’…

rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

4KR,W

…pop %rdiret…xor %rax,%raxadd $0x64, %rspret

overflown bufferArguments in registers!

fun(%rdi,%rsi,%rdx)

gadget

Return-Oriented Programming

adresses

Stack of ‘main’…

&(pop-rdi; ret)rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

ptr. to “/bin/sh”

address of system

4KR,W

…pop %rdiret…xor %rax,%raxadd $0x64, %rspret

overflown bufferArguments in registers!

fun(%rdi,%rsi,%rdx)

gadget

Return-Oriented Programming

adresses

Stack of ‘main’…

&(pop-rdi; ret)

rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

ptr. to “/bin/sh”

address of system

4KR,W

…pop %rdiret…xor %rax,%raxadd $0x64, %rspret

overflown bufferArguments in registers!

fun(%rdi,%rsi,%rdx)

gadget

Return-Oriented Programming

adresses

Stack of ‘main’…

&(pop-rdi; ret)

rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

ptr. to “/bin/sh”

address of system

4KR,W

…pop %rdiret…xor %rax,%raxadd $0x64, %rspret

overflown bufferArguments in registers!

fun(%rdi,%rsi,%rdx)

gadget“/bin/sh”

Return-Oriented Programming

adresses

Stack of ‘main’…

&(pop-rdi; ret)

rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

ptr. to “/bin/sh”

address of system

4KR,W

…pop %rdiret…xor %rax,%raxadd $0x64, %rspret

overflown bufferArguments in registers!

fun(%rdi,%rsi,%rdx)

gadget“/bin/sh”

Return-Oriented Programming

adresses

Stack of ‘main’…

&(pop-rdi; ret)

rsp

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

ptr. to “/bin/sh”

address of system

4KR,W

…pop %rdiret…xor %rax,%raxadd $0x64, %rspret

overflown bufferArguments in registers!

fun(%rdi,%rsi,%rdx)

gadget“/bin/sh”

Return-Oriented Programming

adresses

&(pop-rdi; ret)

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

0x20

4KR,W

…pop %rdiret…xor %rax,%raxadd $0x64, %rspret

overflown bufferArguments in registers!

fun(%rdi,%rsi,%rdx)

gadget

Return-Oriented Programming

adresses

&(pop-rdi; ret)

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

0x20&(pop rsi;pop

rdx;ret)

0x23

0xFF73

4KR,W

…pop %rdiret…xor %rax,%raxadd $0x64, %rspret

overflown bufferArguments in registers!

fun(%rdi,%rsi,%rdx)

gadget

chai

ning

gad

gets

Return-Oriented Programming

adresses

&(pop-rdi; ret)

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

0x20&(pop rsi;pop

rdx;ret)

0x23

0xFF73

4KR,W

overflown buffer

chai

ning

gad

gets

0x81 0xfa 0x5c 0xc3 0x00 0x00

Return-Oriented Programming

adresses

&(pop-rdi; ret)

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

0x20&(pop rsi;pop

rdx;ret)

0x23

0xFF73

4KR,W

overflown buffer

chai

ning

gad

gets

0x81 0xfa 0x5c 0xc3 0x00 0x00

cmp $0xc35c, %edx

Return-Oriented Programming

adresses

&(pop-rdi; ret)

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

0x20&(pop rsi;pop

rdx;ret)

0x23

0xFF73

4KR,W

overflown buffer

chai

ning

gad

gets

0x81 0xfa 0x5c 0xc3 0x00 0x00

cmp $0xc35c, %edx

pop %rsp

Return-Oriented Programming

adresses

&(pop-rdi; ret)

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

0x20&(pop rsi;pop

rdx;ret)

0x23

0xFF73

4KR,W

overflown buffer

chai

ning

gad

gets

0x81 0xfa 0x5c 0xc3 0x00 0x00

cmp $0xc35c, %edx

ret

Return-Oriented Programming

adresses

&(pop-rdi; ret)

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

0x20&(pop rsi;pop

rdx;ret)

0x23

0xFF73

4KR,W

overflown buffer

chai

ning

gad

gets

0x81 0xfa 0x5c 0xc3 0x00 0x00

cmp $0xc35c, %edx

pop %rsp; ret

Return-Oriented Programming

adresses

&(pop-rdi; ret)

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

0x20&(pop rsi;pop

rdx;ret)

0x23

0xFF73

4KR,W

overflown buffer

chai

ning

gad

gets

• Pop-gadgets• Write-anywhere gadgets (mov %rdi, (%rsi);

ret)• Turing-complete set of gadgets for complex

shellcode (eventually calling libc/kernel)• Sometimes it can be a simple stager:

• Write shellcode in RW memory (read)

Return-Oriented Programming

adresses

&(pop-rdi; ret)

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

0x20&(pop rsi;pop

rdx;ret)

0x23

0xFF73

4KR,W

overflown buffer

chai

ning

gad

gets

• Pop-gadgets• Write-anywhere gadgets (mov %rdi, (%rsi);

ret)• Turing-complete set of gadgets for complex

shellcode (eventually calling libc/kernel)• Sometimes it can be a simple stager:

• Write shellcode in RW memory (read)• Make page executable (mprotect)

(not possible with PaX)

Return-Oriented Programming

adresses

&(pop-rdi; ret)

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

0x20&(pop rsi;pop

rdx;ret)

0x23

0xFF73

4KR,X

overflown buffer

chai

ning

gad

gets

• Pop-gadgets• Write-anywhere gadgets (mov %rdi, (%rsi);

ret)• Turing-complete set of gadgets for complex

shellcode (eventually calling libc/kernel)• Sometimes it can be a simple stager:

• Write shellcode in RW memory (read)• Make page executable (mprotect)

(not possible with PaX)• ‘Return’ to the (executable) shellcode

Return-Oriented Programming

adresses

&(pop-rdi; ret)

proftpd libc stack

0 0x7ff…

4KR,X

4KR,X

4KR,X

4KR,X

4KR,W

4KR,W

4KR,X

exit, read, write,system, mprotect, …

64 bit

0x20&(pop rsi;pop

rdx;ret)

0x23

0xFF73

4KR,X

overflown buffer

chai

ning

gad

gets

• Pop-gadgets• Write-anywhere gadgets (mov %rdi, (%rsi);

ret)• Turing-complete set of gadgets for complex

shellcode (eventually calling libc/kernel)• Sometimes it can be a simple stager:

• Write shellcode in RW memory (read)• Make page executable (mprotect)

(not possible with PaX)• ‘Return’ to the (executable) shellcode

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…

pos

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

system

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

systemisCute

isCuddly

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

systemisCute

isCuddlyfake vtable

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

pop …retisCute

isCuddlyfake vtable

local varsret addr. main

rsp

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

pop …retisCute

isCuddlyfake vtable

ret. addr calllocal vars

ret addr. main

rsp

Not under our control!No ROP possible?

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

pop …retisCute

isCuddlyfake vtable

ret. addr calllocal vars

ret addr. main

rsp

normalROP

chain…

Some bufferrdi

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

mov %rdi, %rspretisCute

isCuddlyfake vtable

ret. addr calllocal vars

ret addr. main

rsp

normalROP

chain…

Some bufferrdi

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

mov %rdi, %rspretisCute

isCuddlyfake vtable

ret. addr calllocal vars

ret addr. main

rsp

normalROP

chain…

Some bufferrdi

rsp

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

mov %rdi, %rspretisCute

isCuddlyfake vtable

ret. addr calllocal vars

ret addr. main…

normalROP

chain…

Some bufferrdi

rsp

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

mov %rdi, %rspretisCute

isCuddlyfake vtable

ret. addr calllocal vars

ret addr. main…

normalROP

chain…

Some bufferrdi

rsp

Overwriting function pointersstruct Animal {

virtual bool isCute();virtual bool isCuddly();Position pos;

};Animal* a = …;a->isCuddly();…movq (…), %raxmovq 0x8(%rax), %raxcallq *%rax

vtable

pos

isCuteisCuddly

Dog::isCute

Labrador::isCuddly

xchg %rdi, %rspretisCute

isCuddlyfake vtable

ret. addr calllocal vars

ret addr. main…

normalROP

chain…

Some bufferrdi

rsp

Function pointers to libraries

proftpd libc stack

exit

+0x78230

Function pointers to libraries

proftpd libc stack

exit

+0xA8230

Function pointers to libraries

Pillars of Eternity libc stacklibGL libm

+ ???

NVidia? Intel? AMD?

Function pointers to libraries

proftpd libc stack

exit

+???

Function pointers to libraries

libc stack

exit

proftpd

code

data

call exit

Function pointers to libraries

libc stack

exit

proftpd

code

data

exit@PLT:

call exit@PLT

PLT

Function pointers to libraries

libc stack

exit

proftpd

code

data

exit@PLT:jmp GOT[exitid]

call exit@PLT

GO

TPL

T

symbol resolver stub

Function pointers to libraries

libc stack

exit

proftpd

code

data

exit@PLT:jmp GOT[exitid]

call exit@PLT

GO

TPL

T

symbol resolver stub

Function pointers to libraries

libc stack

exit

proftpd

code

data

exit@PLT:jmp GOT[exitid]

call exit@PLT

GO

TPL

T

symbol resolver stub

all function pointers in the Global Offset Tablecan be overwritten, next time application callsexit, attack code is executed

Address Space Layout Randomization

proftpd libc stack

adresses

Stack of ‘main’…

address of exitrsp

Address Space Layout Randomization

proftpd libc stack

adresses

Stack of ‘main’…

address of exitrsp

Address Space Layout Randomization

proftpd libc stack

adresses

Stack of ‘main’…

address of exitrsp

Randomize on each program start:• Load address of libraries• Stack base• Heap base

Address Space Layout Randomization

proftpd libc stack

32 bit

page offset…

>=4 bits 12 bits<=16 bitsBrute-forcable

64 bit

page offsetcanonical address

16 bits 12 bits>=28 bitsBrute forcing harder

Address Space Layout Randomization

proftpd libc stack

adresses

Stack of ‘main’…

address of exitrsp

Address Space Layout Randomization

proftpd libc stack

Stack of ‘main’…

gadgets in proftpdrsp

write@PLTAt fixed address!

Address Space Layout Randomization

proftpd libc stack

Stack of ‘main’…

gadgets in proftpdrsp

Only possible with Position Independent Executable (PIE)

Stack canary/cookie

return address

0x64 bytes

buffer …

buffer[99]

buffer[107]

H e l l

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>add $0x64, %rspretq

Stack Smash Protector / Cookies

return address

0x64 bytes

buffer …H e l l

stack cookie/canary

sub $0x64, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>add $0x64, %rspretq

Stack Smash Protector / Cookies

return address

0x64 bytes

buffer …H e l l

stack cookie/canary

sub $0x6C, %rspmovq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>add $0x6C, %rspretq

Stack Smash Protector / Cookies

return address

0x64 bytes

buffer …H e l l

sub $0x6C, %rspmov %fs:0x28,%raxmov %rax,0x64(%rsp)movq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>add $0x6C, %rspretqstack cookie/canary

Per-process value initialized by loaderSegment-relative addressing hard to leak value

Stack Smash Protector / Cookies

return address

0x64 bytes

buffer …H e l l

sub $0x6C, %rspmov %fs:0x28,%raxmov %rax,0x64(%rsp)movq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>mov 0x64(%rsp),%raxxor %fs:0x28,%raxjne … stack_chk_failadd $0x6C, %rspretq

stack cookie/canary

Per-process value initialized by loaderSegment-relative addressing hard to leak value

Stack Smash Protector / Cookies

return address

0x64 bytes

buffer …H e l l

sub $0x6C, %rspmov %fs:0x28,%raxmov %rax,0x64(%rsp)movq %rdi, %rdxmovq %rsp, %rdicallq <memcpy>mov 0x64(%rsp),%raxxor %fs:0x28,%raxjne … stack_chk_failadd $0x6C, %rspretq

stack cookie/canary

Per-process value initialized by loaderSegment-relative addressing hard to leak value

saved rbx, …

local variables

(argument copies)

Information leakage

Unknown to attacker:• Stack/code addresses• CookieLeak information back to attacker first:• Leak pointer data, use tweaked exploit based on data

– Read outside array bounds– Format string vulnerabilities (not that common anymore?)– Serialization– Timing side channels

• In scripting languages: create exploit directly in the script• Bruteforcing (if possible)• Generalized stack reading…

Generalized Stack Reading

proftpd libc stack

Client

Waiting for clients…

connect

return address

rsp cookie

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

Waiting for clients…accept() connectionfork()connect

proftpd libc stack

return address

rsp cookieClone of the parent process:Same addresses, same cookie!

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

proftpd libc stack

return address

buffercookie

O v e r f l

Waiting for clients…

buffer = “Overflow”

send(buffer)Connection+Server ok?

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

proftpd libc stack

return address

buffercookie

O v e r f l0

Waiting for clients…

buffer = “Overflow”cookie_guess = [0x00]send(buffer + cookie_guess)Connection+Server ok?

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

Waiting for clients…

buffer = “Overflow”cookie_guess = [0x00]send(buffer + cookie_guess)Connection+Server ok?

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

connect

proftpd libc stack

return address

buffercookie

O v e r f l1

Waiting for clients…

buffer = “Overflow”cookie_guess = [0x01]send(buffer + cookie_guess)Connection+Server ok?

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

proftpd libc stack

return address

buffercookie

O v e r f l2

Waiting for clients…

buffer = “Overflow”cookie_guess = [0x02]send(buffer + cookie_guess)Connection+Server ok!

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

proftpd libc stack

return address

buffercookie

O v e r f l2

Waiting for clients…

buffer = “Overflow”cookie_guess = [0x02, 0x00]send(buffer + cookie_guess)Connection+Server ok?

0

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

connect

proftpd libc stack

return address

buffercookie

O v e r f l2

Waiting for clients…

buffer = “Overflow”cookie_guess = [0x02, 0x01]send(buffer + cookie_guess)Connection+Server ok?

1

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

connect

proftpd libc stack

return address

buffer…

O v e r f l2

Waiting for clients…

buffer = “Overflow”cookie_guess = [0x02, 0x01, 0x42, …, 0x09]send(buffer + cookie_guess)Connection+Server ok?

1 9

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

connect

proftpd libc stack

return address

buffer…

O v e r f l2

Waiting for clients…

buffer = “Overflow”cookie = [0x02, 0x01, 0x42, …, 0x09] identified cookiesend(buffer + cookie)Connection+Server ok?

1 9

Saved rbx, etc.

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

connect

proftpd libc stack

return address

buffer…

O v e r f l2

Waiting for clients…

buffer = “Overflow”cookie = [0x02, 0x01, 0x42, …, 0x09]local_stack_guess = [0x00]send(buffer + cookie + local_stack_guess)Connection+Server ok?

1 9

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

connect

proftpd libc stack

return address

buffer…

O v e r f l2

Waiting for clients…

buffer = “Overflow”cookie = [0x02, 0x01, 0x42, …, 0x09]local_stack = [0x00, 0x00, …]return_address_guess = [0x00]send(buffer + cookie + local_stack + return_address_guess)Connection+Server ok?

1 9

0

Generalized Stack Reading

proftpd libc stack

return address

rsp cookie

Client

connect

proftpd libc stack

return address

buffer…

O v e r f l2

Waiting for clients…

buffer = “Overflow”cookie = [0x02, 0x01, 0x42, …, 0x09]local_stack = [0x00, 0x00, …]return_address = [0x7f, 0x3c, …]send(buffer + cookie + local_stack + return_address)Connection+Server ok?

1 9

0

Load address known! ROP chains!

Other exploitation techniques

• Heap spraying• JIT spraying• Double free/use after free/etc• Heap spray, heap grooming/feng shui• Races• The same, but in the kernel• The sky is the limit…• Have a look at googleprojectzero.blogspot.com