Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Advanced exploitation on Linux: ROP and infoleaks

Advanced exploitation on Linux: ROP and infoleaks

workshop given during hack.lu 2016 conference
exercices can be found on https://github.com/0xmilkmix/training/tree/master/hacklu

Julien Bachmann

October 18, 2016
Tweet

More Decks by Julien Bachmann

Other Decks in Programming

Transcript

  1. 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
  2. pwn | recaps • Buffer overflow basics • out-of-bound writes

    • rewrite saved instructions pointer • redirect process control flow • execute shellcode
  3. pwn | recaps • Testing • $ ./bof_01 foobar ?

    • $ ./bof_01 AAAAAAAAAAAAAAA ? • $ ./bof_01 `python -c ‘print “A”` ?
  4. pwn | recaps • Stack state at the beginning of

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

    ... &input %eip %ebp AAAA AAAA AAAA %ebp ...
  6. pwn | recaps • If input is more than 128

    bytes ... AAAA AAAA AAAA AAAA AAAA AAAA %ebp ... return address argument
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. pwn | tips • To get a coredump once the

    process crash • # echo "core" > /proc/sys/kernel/core_pattern • $ ulimit -c unlimited
  13. 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
  14. rop | intro • What do you need to be

    able to execute your shellcode ?
  15. rop | nx • Execution rights ! • memory pages

    have access rights • defined in the Page Table Entries • check Intel Developer Manuals
  16. rop | nx • History • first implementations in August

    2004 were software only • ExecShield • W^X • PAX • introduced by Intel in Pentium 4 series • NX bit
  17. 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
  18. rop | nx • Bypass • we cannot add data

    in the process and then execute it • so let’s use what is already present ! • ret2libc • rop
  19. 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
  20. rop | nx | ret2libc • Concept • forge a

    stack as the standard execution would • stdcall convention • rewrite execution pointer with function address
  21. rop | nx | ret2libc • Examples • execute command

    line using system • execute process using exec*
  22. rop | nx | ret2libc • ret2libc!system @“/bin/sh” @system AAAA

    AAAA AAAA AAAA AAAA ... %ebp return address argument &input align
  23. 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)
  24. rop | famous quote • Dino Dai Zovi • “preventing

    the introduction of malicious code is not enough to prevent the execution of malicious computations”
  25. 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
  26. 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
  27. rop | cisc B8 89 41 08 C3 mov eax,

    0xc3084189 mov dword ptr [ecx+8], ecx ret
  28. rop | example • usage examples • write 4 (controlled)

    bytes at a controlled address • call function • chain functions calls
  29. rop | example pop eax ret pop ecx ret mov

    [ecx], eax ret + + = write 4 bytes
  30. rop | chain • In practice • find the gadgets

    you need • forge a stack containing their addresses : ROP chain • redirect execution flow to your ROP chain
  31. rop | find them all • Finding gadgets • Write

    your own tools • elfesteem / pefile / capstone • idapython • Existing tools • ropeme, ropper, ropgagdet, rp++, …
  32. rop | example • Taking our previous example mov dword

    ptr [ecx], eax 0x08049668 0xffffdee8
  33. 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 …
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. 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
  42. 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
  43. rop | pivots • Examples • mov esp, eax ;

    ret • xchg esp, eax ; ret • add esp, #value ; ret
  44. 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
  45. • Step 4 : write functionality in assembly language .section

    .text mov eax, 1 mov ebx, 0x42424242 int 0x80 rop | practice
  46. • Step 5 : requirements • syscall • eax =

    0x1 • ebx = 0x42424242 rop | practice
  47. • Step 6 : define needed instructions • int 0x80

    • xor eax, eax • inc eax • pop ebx rop | practice
  48. • 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
  49. • 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
  50. • First idea : use space that is already here

    and writable rop | bringing data in
  51. • 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
  52. • 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
  53. • 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
  54. 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
  55. 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
  56. • 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
  57. • End of read @read AAAA AAAA AAAA ... %esp

    0x1 @rbuffer 1024 @ebuffer .section .text read: ... ret eip @system rop | chaining calls
  58. • Problem • we don’t have the correct arguments •

    what would help ? • hint: think gadgets… rop | chaining calls
  59. • 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
  60. • 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
  61. • 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
  62. • 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
  63. • 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
  64. • 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
  65. • 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
  66. • Useful chains • protect / read / shellcode •

    dup2 / system • … rop | chaining calls
  67. • 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
  68. • 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
  69. 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
  70. 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
  71. aslr | intro • What do you need if you

    want to call a function ?
  72. • Function address ! • before, code and sections were

    loaded at the same address every time • cat /proc/self/maps aslr | intro
  73. • Concept • Address Space Layout Randomisation • prevent attacker

    from using known addresses • ex: return to libc aslr | intro
  74. • Changes • stack address • heap address • libraries

    addresses • main binary address aslr | what is modified
  75. • 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…
  76. • Requirements • not all binaries (including libraries) are affected

    by ASLR • need to be compiled as Position Independant {Executable, Code} • -pie -fPIE • -fPIC aslr | requirements
  77. • ASLR compatible • list binary headers using readelf •

    EXEC : not compatible • DYN : compatible • when in peda use checksec command aslr | checks
  78. • Other subtleties • 1 : Conservative randomization • stack,

    heap, libraries, pie, vdso, mmap() • 2 : full randomization • 1 + memory managed by brk aslr | configuration
  79. • Methods • brute-force • memory disclosure • binary or

    any loaded library not compiled with support for PIE aslr | bypass
  80. • 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
  81. • 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
  82. • 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
  83. • 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
  84. • Variant • highly dependant on the vulnerability you are

    exploiting • if able to read /proc/self/maps, extract addresses aslr | disclosure
  85. • 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
  86. • 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
  87. • 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
  88. • GOT • table is specific for each binary •

    but : entries can be retrieved using objdump or radare2 • objdump -D ./binary | grep \@plt\>: aslr | dump got
  89. • 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
  90. • Details • leaked_address = <value> • libc_base = leaked_address

    - offset_leaked_from_base • needed_address = libc_base + offset_needed_from_base aslr | calculate
  91. • 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
  92. • Example of such gadgets • mov eax, [ebx] ;

    ret • add eax, [ecx + 0x8042de4c] ; ret • … don’t forget to adjust value in ecx aslr | got gadgets
  93. • 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
  94. conclusion | outro • Other techniques exists • JOP :

    Jump Oriented Programming • SROP : Signal Return Oriented Programming