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. Software exploitation : ROP
    Julien Bachmann
    @milkmix_

    View full-size slide

  2. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  5. pwn | recaps
    • Sample program

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  10. 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

    View full-size slide

  11. 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

    View full-size slide

  12. 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

    View full-size slide

  13. 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

    View full-size slide

  14. 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

    View full-size slide

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

    View full-size slide

  16. pwn | tips
    • Check that your shellcode is working

    View full-size slide

  17. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  21. 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

    View full-size slide

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

    View full-size slide

  23. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  27. 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)

    View full-size slide

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

    View full-size slide

  29. 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

    View full-size slide

  30. 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

    View full-size slide

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

    View full-size slide

  32. rop | cisc
    • Validation with Capstone

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  38. 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

    View full-size slide

  39. 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

    View full-size slide

  40. 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

    View full-size slide

  41. 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

    View full-size slide

  42. 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

    View full-size slide

  43. 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

    View full-size slide

  44. 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

    View full-size slide

  45. 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

    View full-size slide

  46. 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

    View full-size slide

  47. 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

    View full-size slide

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

    View full-size slide

  49. 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

    View full-size slide

  50. • Step 1 : find the overflow
    rop | practice

    View full-size slide

  51. • Step 2 : find the offset
    rop | practice

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  58. • 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

    View full-size slide

  59. • 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

    View full-size slide

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

    View full-size slide

  61. • 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

    View full-size slide

  62. • 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

    View full-size slide

  63. rop | bringing data in

    View full-size slide

  64. • 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

    View full-size slide

  65. 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

    View full-size slide

  66. 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

    View full-size slide

  67. • 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  70. • 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

    View full-size slide

  71. • 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

    View full-size slide

  72. • 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

    View full-size slide

  73. • 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

    View full-size slide

  74. • 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

    View full-size slide

  75. • 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

    View full-size slide

  76. • 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

    View full-size slide

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

    View full-size slide

  78. • 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

    View full-size slide

  79. • 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

    View full-size slide

  80. 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

    View full-size slide

  81. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  85. aslr | without

    View full-size slide

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

    View full-size slide

  87. • 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…

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  90. aslr | checks

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  94. • 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

    View full-size slide

  95. • 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

    View full-size slide

  96. system:


    printf:

    strcpy:

    @???
    libc
    0xfffc3240
    aslr | disclosure

    View full-size slide

  97. • 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

    View full-size slide

  98. • 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

    View full-size slide

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

    View full-size slide

  100. • 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

    View full-size slide

  101. • 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

    View full-size slide

  102. • 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

    View full-size slide

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

    View full-size slide

  104. aslr | dump got

    View full-size slide

  105. aslr | dump got

    View full-size slide

  106. • 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

    View full-size slide

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

    View full-size slide

  108. • 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

    View full-size slide

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

    View full-size slide

  110. • 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

    View full-size slide

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

    View full-size slide