CS 519419 Cyber Attacks Defense Returnoriented Programming 110118
CS 519/419 Cyber Attacks & Defense Return-oriented Programming 11/01/18
Defenses • Data Execution Prevention • Call existing functions in the program • Call library functions • Code-reuse attack • Stack Cookie • Information leak • Side-channel attack • Non-sequential overwrite • ASLR • Information leak (leak any address of stack or library)
Modern Defense in 2014 • Stack-cookie + DEP + ASLR • All enabled in Windows, Linux, Mac. OS, Android, i. OS, etc. . • But, ASLR was not enabled to program code • You can jump to the fixed location in the program’s code… • E. g. , 0 x 8048584… etc. • We have learned how we can bypass each of them • Let’s bypass them even if they are somewhat combined
DEP + ASLR • DEP-1, DEP-2, DEP-3 • Your exploit was returning to library functions such as • execve, system, read, printf, etc. • How did you get the address? • From gdb. Assuming the addresses are not randomized • What if such addresses are randomized by ASLR?
Two types of ASLR • Normal • We call this non-PIE (Position Independent Executable) • Your program’s code address will be always at the fixed location • i. e. , addresses that you see in gdb is the address on the execution • Library, heap, and stack are all randomized. • PIE (Position Independent Executable) • Your program’s code will also be randomized in each time of execution
Breaking DEP + ASLR • We will learn how we can break DEP+ASLR step by step • We will first tackle challenges that does not randomize the program’s code section • Yes, you can use those functions! • Then, can you easily get the shell from the program?
Getting a Privileged Shell • setregid(50500, 50500); • execve(“/bin/sh”, 0, 0); Really? • In case if the program contains those two functions, we can easily call them.
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 printf(stack) Print data in stack… read() read(3, stack, 100) %esp some_function() Open a. txt
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 printf(stack) Print data in stack… Return! read() read(3, stack, 100) %esp some_function() Open a. txt
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 printf(stack) Print data in stack… Return! Execute some_function() %esp read() read(3, stack, 100) some_function() Open a. txt
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 Head of some_function push %ebp mov %esp, %ebp sub $0 x 50, %esp printf(stack) Print data in stack… %esp read() read(3, stack, 100) some_function() Open a. txt
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 Head of some_function push %ebp mov %esp, %ebp sub $0 x 50, %esp printf(stack) Print data in stack… %esp read() read(3, stack, 100) some_function() Open a. txt
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 Head of some_function printf(stack) Print data in stack… push %ebp mov %esp, %ebp sub $0 x 50, %esp read() read(3, stack, 100) Saved_ebp %esp
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 Head of some_function printf(stack) Print data in stack… push %ebp mov %esp, %ebp sub $0 x 50, %esp read() read(3, stack, 100) Saved_ebp %esp
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 Head of some_function printf(stack) Print data in stack… push %ebp mov %esp, %ebp sub $0 x 50, %esp read() read(3, stack, 100) Saved_ebp %esp
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 Head of some_function printf(stack) Print data in stack… push %ebp mov %esp, %ebp sub $0 x 50, %esp read() read(3, stack, 100) Saved_ebp %esp
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 Head of some_function printf(stack) Print data in stack… push %ebp mov %esp, %ebp sub $0 x 50, %esp read() read(3, stack, 100) Saved_ebp %esp
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 End of some_function printf(stack) Print data in stack… leave ret read() read(3, stack, 100) Saved_ebp %esp
Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 End of some_function printf(stack) Print data in stack… leave ret read() read(3, stack, 100) Saved_ebp %esp
%ebp Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 End of some_function leave ret printf(stack) Print data in stack… %esp read() read(3, stack, 100) Saved_ebp
%ebp Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 End of some_function leave ret printf(stack) Print data in stack… %esp read() read(3, stack, 100) Saved_ebp
%ebp Chaining Function Calls in DEP-3 Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 End of some_function leave ret %esp Execute read(3, buffer, 100)! printf(stack) Print data in stack… read() read(3, stack, 100) Saved_ebp
Return Chain • From the return address, if you return to a function • Then after finishing the function’s execution • The processor will return to the next address… • some_function() • read() • printf() Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 printf(stack) Print data in stack… read() read(3, stack, 100) some_function() Open a. txt
ROP-1 (Return-oriented Programming) • We call this execution made by a chain of return as • Return-oriented Programming (ROP) • We can chain arbitrary number of functions • But wait, what about arguments? Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 printf(stack) Print data in stack… read() read(3, stack, 100) some_function() Open a. txt
ROP-1 (Return-oriented Programming) • We call this execution made by a chain of return as • Return-oriented Programming (ROP) • We can chain arbitrary number of functions • But wait, what about arguments? Read_ARG 3 size = 100 Read_ARG 2 Addr of buffer Read_ARG 1 fd = 3 printf(stack) Print data in stack… read() read(3, stack, 100) some_function() Open a. txt
ROP-1: Function Arguments. . YYYY • setregid(50500, 50500); • execve(“/bin/sh”, 0, 0); Setregid_ARG 2 50500 setregid_ARG 1 50500 • We can first set the return address as • setregid() • Then, set +8 and +12 as 50500 for its arguments • And then, we put execve at +4, to chain the call XXXX execve() setregid()
ROP-1: Function Arguments. . ZZZZ YYYY • setregid(50500, 50500); • execve(“/bin/sh”, 0, 0); • And then, we put execve at +4, to chain the call • Seems we call • execve(50500, YYYY, ZZZZ); • This will always fail because 50500 is not a valid address • So if you have some function arguments • You can’t chain multiple functions NO! Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX execve() setregid()
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” execve() Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX setregid() %esp
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • At return execve() Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX setregid() %esp
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • At return execve() • setregid(50500, 50500) Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX %esp setregid()
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • At return execve() • setregid(50500, 50500) Setregid_ARG 2 50500 • What if we run for XXXX? • pop %edi • pop %ebp • ret setregid_ARG 1 50500 XXXX %esp setregid()
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • pop %edi • pop %ebp • ret execve() Setregid_ARG 2 50500 %esp setregid_ARG 1 50500 XXXX setregid()
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • pop %edi • pop %ebp • ret execve() %esp Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX setregid()
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • pop %edi = 50500 • pop %ebp • ret execve() %esp Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX setregid()
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • pop %edi = 50500 • pop %ebp • ret execve() %esp Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX setregid()
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • pop %edi = 50500 • pop %ebp • ret execve() %esp Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX setregid()
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • pop %edi = 50500 • pop %ebp = 50500 • ret execve() %esp Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX setregid()
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • pop %edi = 50500 • pop %ebp = 50500 • ret execve() %esp Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX setregid()
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • pop %edi = 50500 • pop %ebp = 50500 • ret • execve(“/bin/sh”, 0, 0) %esp execve() Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX setregid()
ROP: We Can Chain Any # of Functions • Function with one arguments • [func] [pop-ret] [arg 1][arg 2] [next_function] • Function with two arguments • [func] [pop-ret] [arg 1][arg 2] [next_function] • Function with three arguments • [func] [pop-pop-ret] [arg 1][arg 2] [next_function] • Function with four arguments • [func] [pop-pop-ret] [arg 1][arg 2] [next_function]
ROP Gadgets • How can we find such a many pops? • From disassembly • Or from tool, ROPGadgets 1 pop 2 pops 3 pops
ROP-1 • setregid(50500, 50500); • execve(“/bin/sh”, 0, 0); 0 0 Addr “/bin/sh” execve() Setregid_ARG 2 50500 setregid_ARG 1 50500 POP-RET setregid()
ROP-2: 64 bit • ROP in 32 bit is easier than 64 bit because function gets arguments from the stack • In amd 64, arguments are passed by • • Registers! rdi rsi rdx Passing arguments via stack will not work! rcx r 8 r 9 0 0 Addr “/bin/sh” execve() Setregid_ARG 2 50500 setregid_ARG 1 50500 POP-RET setregid()
ROP-2: Setting Register Values • We can set register values using pop XXX
What Do You Want to Put for XXXX? 0 0 • Let’s take a look at the stack on the right Addr “/bin/sh” • pop %edi = 50500 • pop %ebp = 50500 • ret execve() %esp Setregid_ARG 2 50500 setregid_ARG 1 50500 XXXX setregid()
ROP-2: Setting Register Values • We can set register values using pop XXX • Arguments are at rdi, rsi, rdx, rcx… • Can we find? • • pop %rdi; ret; pop %rsi; ret; pop %rdx; ret; … • Yes
ROP-2: Setting Register Values
ROP-2: Passing Args in amd 64 setregid() • pop %rdi • ret • pop %rsi • pop %r 15 • ret XXXX Setregid_ARG 2 50500 pop %rsi; pop %r 15; ret %rsp setregid_ARG 1 50500 pop %rdi; ret;
ROP-2: Passing Args in amd 64 setregid() • pop %rdi • ret • pop %rsi • pop %r 15 • ret XXXX Setregid_ARG 2 50500 pop %rsi; pop %r 15; ret %rsp setregid_ARG 1 50500 pop %rdi; ret;
ROP-2: Passing Args in amd 64 setregid() • pop %rdi = 50500 • ret • pop %rsi • pop %r 15 • ret XXXX Setregid_ARG 2 50500 pop %rsi; pop %r 15; ret %rsp setregid_ARG 1 50500 pop %rdi; ret;
ROP-2: Passing Args in amd 64 setregid() • pop %rdi = 50500 • ret • pop %rsi • pop %r 15 • ret XXXX Setregid_ARG 2 50500 pop %rsi; pop %r 15; ret %rsp setregid_ARG 1 50500 pop %rdi; ret;
ROP-2: Passing Args in amd 64 setregid() • pop %rdi = 50500 • ret • pop %rsi • pop %r 15 • ret XXXX %rsp Setregid_ARG 2 50500 pop %rsi; pop %r 15; ret setregid_ARG 1 50500 pop %rdi; ret;
ROP-2: Passing Args in amd 64 setregid() • pop %rdi = 50500 • ret • pop %rsi • pop %r 15 • ret XXXX %rsp Setregid_ARG 2 50500 pop %rsi; pop %r 15; ret setregid_ARG 1 50500 pop %rdi; ret;
ROP-2: Passing Args in amd 64 setregid() • pop %rdi = 50500 • ret • pop %rsi = 50500 • pop %r 15 • ret XXXX %rsp Setregid_ARG 2 50500 pop %rsi; pop %r 15; ret setregid_ARG 1 50500 pop %rdi; ret;
ROP-2: Passing Args in amd 64 setregid() • pop %rdi = 50500 • ret • pop %rsi = 50500 • pop %r 15 • ret XXXX %rsp Setregid_ARG 2 50500 pop %rsi; pop %r 15; ret setregid_ARG 1 50500 pop %rdi; ret;
ROP-2: Passing Args in amd 64 setregid() • pop %rdi = 50500 • ret • pop %rsi = 50500 • pop %r 15 = XXXX • ret %rsp XXXX Setregid_ARG 2 50500 pop %rsi; pop %r 15; ret setregid_ARG 1 50500 pop %rdi; ret;
ROP-2: Passing Args in amd 64 setregid() • pop %rdi = 50500 • ret • pop %rsi = 50500 • pop %r 15 = XXXX • ret %rsp XXXX Setregid_ARG 2 50500 pop %rsi; pop %r 15; ret setregid_ARG 1 50500 pop %rdi; ret;
ROP-2: Passing Args in amd 64 %rsp • pop %rdi = 50500 • ret • pop %rsi = 50500 • pop %r 15 = XXXX • ret • setregid(50500, 50500) setregid() XXXX Setregid_ARG 2 50500 pop %rsi; pop %r 15; ret setregid_ARG 1 50500 pop %rdi; ret;
ROP-2: Execve? execve(); 0 pop %rdx, ret; XXXX 0 pop %rsi; pop %r 15; ret ADDR “/bin/sh” pop %rdi; ret; %rsp
ROP-2: Execve? execve(); 0 pop %rdx, ret; XXXX 0 pop %rsi; pop %r 15; ret ADDR “/bin/sh” %rsp pop %rdi; ret;
ROP-2: Execve? execve(); 0 • rdi = addr of “/bin/sh” pop %rdx, ret; XXXX 0 pop %rsi; pop %r 15; ret %rsp ADDR “/bin/sh” pop %rdi; ret;
ROP-2: Execve? execve(); 0 • rdi = addr of “/bin/sh” pop %rdx, ret; XXXX 0 %rsp pop %rsi; pop %r 15; ret ADDR “/bin/sh” pop %rdi; ret;
ROP-2: Execve? • rdi = addr of “/bin/sh” • rsi = 0 • r 15 = 0 // Don’t care execve(); 0 pop %rdx, ret; %rsp XXXX 0 pop %rsi; pop %r 15; ret ADDR “/bin/sh” pop %rdi; ret;
ROP-2: Execve? • rdi = addr of “/bin/sh” • rsi = 0 • r 15 = 0 // Don’t care execve(); 0 %rsp pop %rdx, ret; XXXX 0 pop %rsi; pop %r 15; ret ADDR “/bin/sh” pop %rdi; ret;
ROP-2: Execve? • rdi = addr of “/bin/sh” • rsi = 0 • r 15 = 0 // Don’t care • rdx = 0 execve(); %rsp 0 pop %rdx, ret; XXXX 0 pop %rsi; pop %r 15; ret ADDR “/bin/sh” pop %rdi; ret;
ROP-2: Execve? • rdi = addr of “/bin/sh” • rsi = 0 • r 15 = 0 // Don’t care • rdx = 0 • execve(“/bin/sh”, 0, 0) %rsp execve(); 0 pop %rdx, ret; XXXX 0 pop %rsi; pop %r 15; ret ADDR “/bin/sh” pop %rdi; ret;
ROP-2: Exploit execve(); 0 pop %rdx, ret; XXXX 0 pop %rsi; pop %r 15; ret ADDR “/bin/sh” pop %rdi; ret; setregid() XXXX 50500 pop %rsi; pop %r 15; ret 50500 pop %rdi; ret;
ROP-3 and ROP-4 • Task • Call open(), read(), write() (or printf) by building ROP chain • Very similar to DEP-3, but requires argument pops • Use tool • ROPGadget -- binary [program_name]
Assignment: Week-5 • ASLR: connect to vm-ctf 2. eecs. oregonstate. edu • Use the same credentials (id, private key, etc. ) • Challenges are in /home/labs/week 5 • Use setup 5 • Due: 11/27 2: 00 pm
- Slides: 69