CS 419579 Cyber Attacks Defense Advanced ROP 110719
CS 419/579 Cyber Attacks & Defense Advanced ROP 11/07/19
32 bit • Arguments on the stack • [func][pop-N-ret][arg 1][arg 2][arg 3][…] • Pop-N-ret is important • • Pop ret – can call functions with 1 arg Pop pop ret – can call functions with 2 args Pop pop ret – can call functions with 3 args Pop… ret –can call functions with N args. .
__libc_csu_init() • An initialization function of a program… • Call constructors, etc. Always exists in the program with default compilation setup. . Can call functions with 7 args You may regard add $0 xc, %esp as pop-pop
64 bit • Set argument first • • [pop rdi ret][arg 1] [pop rsi r 15 ret][arg 2][xxx] [pop rdx ret][arg 3] [pop rcx … ret][arg 4][xxx]… [pop r 8 … ret][arg 5][xxx]… [pop r 9 … ret][arg 6][xxx]… … • Then call func • [func]
ROP Restrictions in 64 bit • Found pop rdi • Can call functions with 1 arg • Found pop rdi and pop rsi • Can call. . with 2 args • Rdi rsi and rdx. . • 3 args • …
Pop %rdx I put this gadget for you!
Usual case NO POP RDX…
EXECVE() • 64 bit: execve(rdi = “xxxx”, rsi, rdx) • Requirements for rsi and rdx • argv and envp • 0 • There is no argument and environment variable at all • A pointer to • Array of string addresses (any valid memory address ends with 0 would be fine) • Ends with 0
EXECVE() • 64 bit: execve(rdi = “xxxx”, rsi, rdx) • Requirements for rsi and rdx • argv and envp • A pointer to • Array of string pointers • Ends with 0 • char **argv = {“arg 1”, “arg 2”, “arg 3”, 0} • char ** envp = {“PATH=. ”, “SHELL=/bin/bash”, 0}
EXECVE - TEST
EXECVE - TEST
EXECVE - TEST
EXECVE - TEST
EXECVE() • 64 bit: execve(rdi = “xxxx”, rsi, rdx) • Requirements for rsi and rdx • 0 • A pointer to 0 • A pointer that contains several pointers and ends with 0
How can we control rdx without pop rdx? • __libc_csu_init • Initializer for constructors in C program
ELF Execution Flow • __libc_start_main • Will call __libc_init_first -> __libc_init -> __libc_csu_init • __libc_csu_init • Call constructors in the program • Usually we do not have constructors at all but this function resides in the program’s address space • Then call main()
Controlling RDX via __libc_csu_init() Set rdx, rsi, rdi and call execve!
Controlling RDX Set r 13 = 0 -> this will make rdx = 0 Set r 14 = 0 -> this will make rsi = 0 Set r 15 = string -> this will make rdi = r 15 (lower 4 bytes) Callq *(%r 12, %rbx, 8) r 15 d -> edi; we first can set rdi as some string address, and then set r 15 as the same value; In this case, mov %r 15 d, %rdi will have no meaning…
Controlling RDX What is the meaning of callq *(%r 12, %rbx, 8)? ? ? SYNTAX: (a, b, c) = a[b*c] func_ptr = r 12[rbx * 8] func_ptr()
Controlling RDX callq *(%r 12, %rbx, 8) func_ptr = r 12[rbx * 8] func_ptr() Example: Set rbx = 0 -> r 12[0] Meaning: Getting the value from the address pointed by r 12.
Controlling RDX callq *(%r 12, %rbx, 8) func_ptr = r 12[rbx * 8] func_ptr() Example: Set rbx = 0 -> r 12[0] Meaning: Getting the value from the address pointed by r 12. Action: Set r 12 = execve?
Controlling RDX callq *(%r 12, %rbx, 8) func_ptr = r 12[rbx * 8] func_ptr() Example: Set rbx = 0 -> r 12[0] r 12 = 0 x 4004 d 0 (execve) Action: r 12[0] = *(0 x 4004 d 0) = 0 x 0 b 5 a 25 ff Jump to 0 xb 5 a 25 ff -> SIGSEGV
Callq *(%r 12, %rbx, 8) • We need to set %r 12 as • An address that contains the address of execve() • WHAT? Is there any memory block for this? ? • YES
Procedure Linkage Table (PLT) • A program calls printf • Before running the program • Shows printf@plt, at the code section (0 x 400 XXX) • After running the program • Shows printf at the libc section (0 x 7 fa 174 b 06 XXX)
What is PLT? • To call a function, a program need to know the address • The program does not know the address of libc functions (e. g. , printf) • The ELF format let the program use a fixed address to call library function • That’s PLT! • Then, how does it work?
Reverse Engineering PLT • Disassemble • Jump to the address stored at 0 x 601030 • *0 x 601030 indicates the value in that address (because of *) • Maybe you wish to set %r 12 to 0 x 601030 to call printf…
Reverse Engineering PLT • What is in 0 x 601030? • 0 x 7 fa 174 b 06800
PLT and Global Offset Table (GOT) • 0 x 4005 a 0 (printf@plt) serve as a link to the printf in the libc • Calling 0 x 4005 a 0 -> jump to *0 x 601030 -> jump to printf() • -> calling printf() • 0 x 601030 is called as Global Offset Table (GOT) of printf • Program calls PLT • PLT jumps to the address stored in GOT • GOT stores the address in libc
ELF, PLT, GOT The program Calls a function In PLT printf() strcpy() read() Program printf() Libc printf() … strcpy() … read() … GOT libc_printf libc_strcpy GOT stores libc addr libc_read PLT jumps to GOT
ELF, PLT, GOT The program Calls a function In PLT printf() strcpy() read() Program printf() Libc printf() … strcpy() … read() … _dl_dynamic_resolve GOT 7 fa 174 b 06800 _resolve GOT stores addr of _dl_dynamic_resolve PLT jumps to GOT
Global Offset Table • Stored in the data section (i. e. , 0 x 8049 XXX or 0 x 6010 XX) • Fixed even if under ASLR if program is not PIE • Stores the address of _dl_dynamic_resolve at first • Once calling the function, it will store the function address in the libc area
Finding GOT • Readelf -a
Controlling RDX Set rdx, rsi, rdi and call execve!
Controlling RDX Set r 13 = 0 -> this will make rdx = 0 Set r 14 = 0 -> this will make rsi = 0 Set r 15 = string -> this will make rdi = r 15 (lower 4 bytes) Callq *(%r 12, %rbx, 8) Set r 12 = GOT of execve r 15 d -> edi; we first can set rdi as some string address, and then set r 15 as the same value; In this case, mov %r 15 d, %rdi will have no meaning…
Controlling RDX callq *(%r 12, %rbx, 8) func_ptr = r 12[rbx * 8] func_ptr() Example: Set rbx = 0 -> r 12[0] r 12 = 0 x 601030 (GOT of execve) Action: r 12[0] = *(0 x 601030) = addr of execve
ROP-6 -64 • No pop %rdx • Use gadgets in __libc_csu_init to control rdi, rsi, and rdx via • r 13, r 14, and r 15 • Control r 12 and rbx to call execve() • Trick callq *(%r 12, %rbx, 8) • $ cat flag
ROP-5 -32 and ROP-5 -64 • Available Functions • • puts printf read prctl strcpy input_func main prctl • No open • No execve
ROP-5 -32/ROP-5 -64 Exploit Sketch • Leak GOT of printf • Find the GOT of printf • Use ROP chain to leak the address of printf in libc • printf(0 x 804 a 010) • printf(0 x 601020) • The printf call will give you an address!
ROP-5 -32/ROP-5 -64 Exploit Sketch • Recall ASLR-4 • If we know the address of printf() in libc, then we can calculate the address of execve() in libc! • How? • Calculate an offset = execve – printf from libc • execve = offset + printf • Call execve then!
ROP-5 -32/ROP-5 -64 Exploit Sketch • Leak addr of printf • Call printf(GOT of printf) • Convert that into an integer value in pwntools script • Apply offset to get the address of execve • Return to input_function • You can send your exploit to the program one more time • Call execve() • $ cat flag
- Slides: 40