Slide 1

Slide 1 text

Software exploitation : ROP Julien Bachmann @milkmix_

Slide 2

Slide 2 text

intro | me • Julien Bachmann / @milkmix_ • Cyber Security Researcher, Kudelski Security • Guest lecturer in Swiss universities on topics of software exploitation, incident response and malware reverse engineering • Previously • Pentester, incident responder

Slide 3

Slide 3 text

software exploitation | rop • Recaps • Intro to ROP • Bypassing ASLR

Slide 4

Slide 4 text

pwn | recaps • Buffer overflow basics • out-of-bound writes • rewrite saved instructions pointer • redirect process control flow • execute shellcode

Slide 5

Slide 5 text

pwn | recaps • Sample program

Slide 6

Slide 6 text

pwn | recaps • Testing • $ ./bof_01 foobar ? • $ ./bof_01 AAAAAAAAAAAAAAA ? • $ ./bof_01 `python -c ‘print “A”` ?

Slide 7

Slide 7 text

pwn | recaps • Stack state at the beginning of vulnerable() ... &input %eip %ebp buffer ... %ebp

Slide 8

Slide 8 text

pwn | recaps • Stack state after call to strcpy() ... &input %eip %ebp AAAA AAAA AAAA %ebp ...

Slide 9

Slide 9 text

pwn | recaps • If input is more than 128 bytes ... AAAA AAAA AAAA AAAA AAAA AAAA %ebp ... return address argument

Slide 10

Slide 10 text

pwn | recaps • Calling convention on Linux 32 bit • previous example was using stdcall convention • arguments pushed in reverse order on the stack • callee clean the stack at the end • spot it: ret imm16

Slide 11

Slide 11 text

pwn | recaps • Calling convention on Linux 32 bit • libc uses cdecl convention • arguments pushed in reverse order on the stack • caller clean the stack at the end • spot it: ret

Slide 12

Slide 12 text

pwn | tips • Buffer size calculation • In this example: get it by reversing the function • Toolbox • MSF pattern_{create, offset}.rb (or bundled in the following) • PEDA / GEF

Slide 13

Slide 13 text

pwn | tips • Note for 64 bit exploitation • Linux addressing is on 48 bits not 64 bits • Meaning maximum canonical address is 0x00007FFFFFFFFFFF • Meaning that you will not get `RIP=0x4141414141414141` but a CPU exception • Break on ret from vulnerable function and check pattern value pointed by RSP

Slide 14

Slide 14 text

pwn | tips • In order to start learning exploitation concepts disable the protections at first • Compilation • remove stack canaries • -fno-stack-protector • OS • disable ASLR system wide for first exercises • # echo 0 > /proc/sys/kernel/randomize_va_space

Slide 15

Slide 15 text

pwn | tips • To get a coredump once the process crash • # echo "core" > /proc/sys/kernel/core_pattern • $ ulimit -c unlimited

Slide 16

Slide 16 text

pwn | tips • Check that your shellcode is working

Slide 17

Slide 17 text

rop | intro • First example only works with all protections disabled • less likely to happen nowadays on modern systems • maybe if you are lucky or exploiting an embedded system • Protections on multiple layers • compilation • os • Only targeting execution prevention in this workshop

Slide 18

Slide 18 text

rop | intro • What do you need to be able to execute your shellcode ?

Slide 19

Slide 19 text

rop | nx • Execution rights ! • memory pages have access rights • defined in the Page Table Entries • check Intel Developer Manuals

Slide 20

Slide 20 text

rop | nx • History • first implementations in August 2004 were software only • ExecShield • W^X • PAX • introduced by Intel in Pentium 4 series • NX bit

Slide 21

Slide 21 text

rop | nx • Concept • memory pages should either contain data or code • rare cases where both can mix • ex: JIT compilers • still, stack and heap can be marked as non-executable most of the time

Slide 22

Slide 22 text

rop | nx • Bypass • we cannot add data in the process and then execute it • so let’s use what is already present ! • ret2libc • rop

Slide 23

Slide 23 text

rop | nx | ret2libc • ret2libc • context : stack is non-executable • libc code is obviously executable • instead of having a shellcode using syscalls, directly call libc functions

Slide 24

Slide 24 text

rop | nx | ret2libc • Concept • forge a stack as the standard execution would • stdcall convention • rewrite execution pointer with function address

Slide 25

Slide 25 text

rop | nx | ret2libc • Examples • execute command line using system • execute process using exec*

Slide 26

Slide 26 text

rop | nx | ret2libc • ret2libc!system @“/bin/sh” @system AAAA AAAA AAAA AAAA AAAA ... %ebp return address argument &input align

Slide 27

Slide 27 text

rop | for real • ret2libc next level • calling a function is fun • but can’t we also directly use instructions or call multiples ? • Return Oriented Programming (ROP)

Slide 28

Slide 28 text

rop | famous quote • Dino Dai Zovi • “preventing the introduction of malicious code is not enough to prevent the execution of malicious computations”

Slide 29

Slide 29 text

rop | go go gadgeto • Concept • chain the execution of simple instructions already in the memory to execute code • simple instructions are called gadgets and are ended by RET • pop eax ; ret • mov [ebx], ecx ; ret

Slide 30

Slide 30 text

rop | architecture specificities • Beware • specificity of CISC architecture (used by Intel processors) • a list of opcodes doesn’t have only one representation • possible to process them at various offsets • concept not applicable on RISC architectures (ARM, MIPS, …) • aligned on 2 bytes for Thumb mode and 4 bytes for standard

Slide 31

Slide 31 text

rop | cisc B8 89 41 08 C3 mov eax, 0xc3084189 mov dword ptr [ecx+8], ecx ret

Slide 32

Slide 32 text

rop | cisc • Validation with Capstone

Slide 33

Slide 33 text

rop | example • usage examples • write 4 (controlled) bytes at a controlled address • call function • chain functions calls

Slide 34

Slide 34 text

rop | example pop eax ret pop ecx ret mov [ecx], eax ret + + = write 4 bytes

Slide 35

Slide 35 text

rop | chain • In practice • find the gadgets you need • forge a stack containing their addresses : ROP chain • redirect execution flow to your ROP chain

Slide 36

Slide 36 text

rop | find them all • Finding gadgets • Write your own tools • elfesteem / pefile / capstone • idapython • Existing tools • ropeme, ropper, ropgagdet, rp++, …

Slide 37

Slide 37 text

rop | example • Taking our previous example mov dword ptr [ecx], eax 0x08049668 0xffffdee8

Slide 38

Slide 38 text

rop | example • Taking our previous example • gadget1 : pop eax ; ret • gadget2 : pop ecx ; ret • gadget3 : mov dword ptr [ecx], eax ; ret @gadget 1 AAAA AAAA AAAA ... %ebp return address 0xffffdee8 @gadget 2 0x08049668 @gadget 3 …

Slide 39

Slide 39 text

top | example • When vulnerable function returns • eax = ?? • ecx = ?? @gadget 1 AAAA AAAA AAAA ... esp 0xffffdee8 @gadget 2 0x08049668 @gadget 3 … eip .section .text ... mov eax, 42 ret

Slide 40

Slide 40 text

rop | example • After ret instruction • eax = ?? • ecx = ?? @gadget 1 AAAA AAAA AAAA ... esp 0xffffdee8 @gadget 2 0x08049668 @gadget 3 … eip .section .text ... pop eax ret

Slide 41

Slide 41 text

rop | example • After pop instruction • eax = 0xffffdee8 • ecx = ?? @gadget 1 AAAA AAAA AAAA ... esp 0xffffdee8 @gadget 2 0x08049668 @gadget 3 … eip .section .text ... pop eax ret

Slide 42

Slide 42 text

rop | example • After ret instruction • eax = 0xffffdee8 • ecx = ?? @gadget 1 AAAA AAAA AAAA ... esp 0xffffdee8 @gadget 2 0x08049668 @gadget 3 … eip .section .text ... pop ecx ret

Slide 43

Slide 43 text

rop | example • After pop instruction • eax = 0xffffdee8 • ecx = 0x08049668 @gadget 1 AAAA AAAA AAAA ... esp 0xffffdee8 @gadget 2 0x08049668 @gadget 3 … eip .section .text ... pop ecx ret

Slide 44

Slide 44 text

rop | example • After ret instruction • eax = 0xffffdee8 • ecx = 0x08049668 @gadget 1 AAAA AAAA AAAA ... esp 0xffffdee8 @gadget 2 0x08049668 @gadget 3 … eip .section .text ... mov dword ptr [ecx], eax ret

Slide 45

Slide 45 text

rop | more gadgets • What are useful gadgets ? • redirect execution to register • stack-pivot • set registers values • read at a memory address • write-what-where • init syscall number • syscall

Slide 46

Slide 46 text

rop | pivots • Stack pivoting • we only spoke about stack based buffer overflow • as such your controlled data is in the stack • other types of exploits might not be as convenient • ex: heap overflow

Slide 47

Slide 47 text

rop | pivots • Stack pivoting • ROP chain should be in the stack • need to change stack pointer register to point to user controlled data • beware: this zone might not be big enough for next calls to push • __kernel_vsyscall crashes usually

Slide 48

Slide 48 text

rop | pivots • Examples • mov esp, eax ; ret • xchg esp, eax ; ret • add esp, #value ; ret

Slide 49

Slide 49 text

rop | practice • Demonstration • lets use variation of previous sample • tp_simple • goal : exit with chosen value • take your VM and follow along • https://github.com/0xmilkmix/training/tree/master/hacklu

Slide 50

Slide 50 text

• Step 1 : find the overflow rop | practice

Slide 51

Slide 51 text

• Step 2 : find the offset rop | practice

Slide 52

Slide 52 text

• Step 3 : define payload • exit(0x42424242) rop | practice

Slide 53

Slide 53 text

• Step 4 : write functionality in assembly language .section .text mov eax, 1 mov ebx, 0x42424242 int 0x80 rop | practice

Slide 54

Slide 54 text

• Step 5 : requirements • syscall • eax = 0x1 • ebx = 0x42424242 rop | practice

Slide 55

Slide 55 text

• Step 6 : define needed instructions • int 0x80 • xor eax, eax • inc eax • pop ebx rop | practice

Slide 56

Slide 56 text

• Step 7 : locate gadgets • int 0x80 rop | practice

Slide 57

Slide 57 text

• Step 8 : write exploit • Open your shell ! rop | practice

Slide 58

Slide 58 text

• Useful when debugging • break at the end of the vulnerable function • use si (step into) to go through every instruction • use context to see stack and registers • run vulnerable program through strace to get error messages rop | practice

Slide 59

Slide 59 text

• You got it, ROP is about using the code that’s already present • Now what about the data ? • open(“./super_special_flag”) • address space might not contain super_special_flag rop | bringing data in

Slide 60

Slide 60 text

• First idea : use space that is already here and writable rop | bringing data in

Slide 61

Slide 61 text

• Specific sections • .bss or .data • Check that you have enough place for your data • Note: if you want to call functions such as mprotect remember alignment on page boundary rop | bringing data in

Slide 62

Slide 62 text

• Steps 1. use pop gadgets to set registers to destination and data 2. use mov gadget to write data 3. go back to step 1 rop | bringing data in

Slide 63

Slide 63 text

rop | bringing data in

Slide 64

Slide 64 text

• Write chain for the following call • write(1, “hack.lu”, 7) • on tp_rop • store hack.lu in .data • using only gadgets and not ret2libc technic • https://github.com/0xmilkmix/training/tree/master/hacklu rop | practice

Slide 65

Slide 65 text

rop | chaining calls • Sometimes you don’t want to pop a shell • Maybe you just want to call unlock_door on connected lock • Read content of a file • Bypass seccomp restrictions preventing exec* • Or simply stay out of the radars during an attack/defence CTF

Slide 66

Slide 66 text

rop | chaining calls • Calling multiple functions • remember that they are multiple calling conventions • on 32 bit Linux, libc is mostly using cdecl • which means that the caller has to clean the stack

Slide 67

Slide 67 text

• Calling multiple functions • like we saw in ret2libc part • read • system @read AAAA AAAA AAAA ... %ebp return address 0x1 @buffer 1024 @buffer read args system args @system rop | chaining calls

Slide 68

Slide 68 text

• End of read @read AAAA AAAA AAAA ... %esp 0x1 @rbuffer 1024 @ebuffer .section .text read: ... ret eip @system rop | chaining calls

Slide 69

Slide 69 text

• Problem • we don’t have the correct arguments • what would help ? • hint: think gadgets… rop | chaining calls

Slide 70

Slide 70 text

• Yes, something to clean the 3 entries we have in the stack ! • add esp, 0xc ; ret • pop reg1 ; pop reg2 ; pop reg3 ; ret rop | chaining calls

Slide 71

Slide 71 text

• Calling multiple functions • using a pop3ret • read • system @read AAAA … ... %ebp return address 0x1 @buffer 1024 @system @buffer read args system args @pop3ret align rop | chaining calls

Slide 72

Slide 72 text

• End of read @read AAAA … ... %esp 0x1 @buffer 1024 @system read args system args @pop3ret .section .text read: ... ret eip @buffer align rop | chaining calls

Slide 73

Slide 73 text

• Execution of pop3ret @read AAAA … ... %esp 0x1 @buffer 1024 @system system args @pop3ret .section .text …: pop eax pop ebx pop ecx ret eip @buffer align rop | chaining calls

Slide 74

Slide 74 text

• Execution of pop3ret @read AAAA … ... %esp 0x1 @buffer 1024 @system system args @pop3ret .section .text …: pop eax pop ebx pop ecx ret eip @buffer align rop | chaining calls

Slide 75

Slide 75 text

• Execution of pop3ret @read AAAA … ... %esp 0x1 @buffer 1024 @system system args @pop3ret .section .text …: pop eax pop ebx pop ecx ret eip @buffer align rop | chaining calls

Slide 76

Slide 76 text

• Execution of pop3ret @read AAAA … ... %esp 0x1 @buffer 1024 @system system args @pop3ret .section .text …: pop eax pop ebx pop ecx ret eip @buffer align rop | chaining calls

Slide 77

Slide 77 text

• Useful chains • protect / read / shellcode • dup2 / system • … rop | chaining calls

Slide 78

Slide 78 text

• When calling syscalls directly • no need to pop arguments afterwards since they are passed in registers • Same apply on 64 bit as ABI uses registers to pass parameters also for functions calls • rdi, rsi, rdx, r10, r9, r8 rop | syscalls and 64 bit

Slide 79

Slide 79 text

• Detection • ROP can be prevented by ASLR as we will see in a moment • detection techniques are based on CFI violations • Control Flow Integrity rop | prevention

Slide 80

Slide 80 text

rop | prevention • CFI concepts • uses various heuristics to detect rop chains • high ratio of ret instructions per instructions blocks • shadow stack that validate that ret is returning to instruction following the right call instruction

Slide 81

Slide 81 text

rop | prevention • CFI limitations • implementing a shadow stack degrade performance by at least 30% • as such most implementations are coarse grained • leaving holes that can be exploited • fine grained implementations in some academic r&d projects

Slide 82

Slide 82 text

aslr | intro • What do you need if you want to call a function ?

Slide 83

Slide 83 text

• Function address ! • before, code and sections were loaded at the same address every time • cat /proc/self/maps aslr | intro

Slide 84

Slide 84 text

• Concept • Address Space Layout Randomisation • prevent attacker from using known addresses • ex: return to libc aslr | intro

Slide 85

Slide 85 text

aslr | without

Slide 86

Slide 86 text

aslr | with

Slide 87

Slide 87 text

• Changes • stack address • heap address • libraries addresses • main binary address aslr | what is modified

Slide 88

Slide 88 text

• Wait, what ? • concept seems ineffective if binary loading address does not change • still possible to extract gadgets from it • well, some gadgets but not a panacea… • what went wrong? aslr | strange…

Slide 89

Slide 89 text

• Requirements • not all binaries (including libraries) are affected by ASLR • need to be compiled as Position Independant {Executable, Code} • -pie -fPIE • -fPIC aslr | requirements

Slide 90

Slide 90 text

• ASLR compatible • list binary headers using readelf • EXEC : not compatible • DYN : compatible • when in peda use checksec command aslr | checks

Slide 91

Slide 91 text

aslr | checks

Slide 92

Slide 92 text

• Other subtleties • three configurations for ASLR • /proc/sys/kernel/randomize_va_space • 0 : disabled aslr | configuration

Slide 93

Slide 93 text

• Other subtleties • 1 : Conservative randomization • stack, heap, libraries, pie, vdso, mmap() • 2 : full randomization • 1 + memory managed by brk aslr | configuration

Slide 94

Slide 94 text

• Methods • brute-force • memory disclosure • binary or any loaded library not compiled with support for PIE aslr | bypass

Slide 95

Slide 95 text

• When lazy or no other possibilities • set the libc base address to common base • brute-force the remaining 16 bit • only effective on 32 bit systems or if rebasing is built-into the binary • 64 bit Linux has 28 bit of entropy aslr | brute force

Slide 96

Slide 96 text

• When the binary is not compiled as position independent • as said, limited number of gadgets in it • libraries loading address are randomized • but… not the content of the library aslr | disclosure

Slide 97

Slide 97 text

system: … … printf: … strcpy: … @??? libc 0xfffc3240 aslr | disclosure

Slide 98

Slide 98 text

• Ok, but how to I find it my function ? • generate pattern that appears only once in the library • not present in other ones obviously • need a second vulnerability in the code • memory disclosure aslr | disclosure

Slide 99

Slide 99 text

• Usage • extract information using the disclosure • match it against known value • calculate offset to interesting functions you want to call • or process structure like the GOT aslr | disclosure

Slide 100

Slide 100 text

• Variant • highly dependant on the vulnerability you are exploiting • if able to read /proc/self/maps, extract addresses aslr | disclosure

Slide 101

Slide 101 text

• When the main binary is not compiled as position independent • all text section is loaded at fixed address • this also includes the GOT address aslr | non-pie

Slide 102

Slide 102 text

• GOT • Global Offset Table • used as a mapper to call functions for which loading address is unknown • pretty useful since PIC is mandatory on modern Linux distributions aslr | non-pie

Slide 103

Slide 103 text

• GOT • for each offset there is the address of the corresponding function • filed by the loader when executing the binary • unless lazy binding is used, in this case only once function already called aslr | non-pie

Slide 104

Slide 104 text

• GOT • table is specific for each binary • but : entries can be retrieved using objdump or radare2 • objdump -D ./binary | grep \@plt\>: aslr | dump got

Slide 105

Slide 105 text

aslr | dump got

Slide 106

Slide 106 text

aslr | dump got

Slide 107

Slide 107 text

• Idea • base address of the GOT is known or has been leaked • read at selected offset to retrieve current address of a function • open the libc binary and retrieve offset from this function • also extract offsets from the desired functions aslr | calculate

Slide 108

Slide 108 text

• Details • leaked_address = • libc_base = leaked_address - offset_leaked_from_base • needed_address = libc_base + offset_needed_from_base aslr | calculate

Slide 109

Slide 109 text

• Wait, how do I read the value ? • as said only a limited number of gadgets in the main binary • still possible to find memory read ones aslr | got gadgets

Slide 110

Slide 110 text

• Example of such gadgets • mov eax, [ebx] ; ret • add eax, [ecx + 0x8042de4c] ; ret • … don’t forget to adjust value in ecx aslr | got gadgets

Slide 111

Slide 111 text

• exploit tp_rop_msg • leak useful addresses • gain code execution • stored shellcode in .data • change page right • execute shellcode • https://github.com/0xmilkmix/training/tree/master/hacklu aslr | practice

Slide 112

Slide 112 text

conclusion | outro • Other techniques exists • JOP : Jump Oriented Programming • SROP : Signal Return Oriented Programming