1 of 11

Return Oriented Programming

Nathaniel Kerr

2 of 11

The Basics - What is ret?

  • The RIP register stores the address of the current instruction
  • When calling a function, the address to return to is pushed to the stack
    • call 0x10203040 is (kind of) an alias for push rip; mov rip, 0x10203040
  • When returning from a function, the top value of the stack is moved into the RIP register
    • ret is an alias for pop rip

3 of 11

The Basics - exploiting ret

  • If an attacker can overwrite the return address (such as by buffer overflow) they can control the flow of code execution - they can execute any code they know the address of
  • In the most basic case, the attacker has a win function they want to return to
  • In more advanced challenges, the attacker may have to chain together return addresses, return to code on the stack, or return to a function in libc

4 of 11

Using Gadgets

  • Sometimes the attacker may need to change the contents of one or more CPU registers, for example if they wanted to call a function with specific arguments
  • This can be accomplished with gadgets - small snippets of code which adjust register contents (usually from the stack), then return
  • Gadgets can also be chained together (example on the next slide)
  • To find gadgets easily, use the pwntools ROP module or ghidra

5 of 11

6 of 11

LIBC and the GOT

Using external functions

7 of 11

What and where is libc?

libc is the C standard library - it defines functions like printf(), fgets(), and strcpy()

ELFs do not include the entire function - libc (all of it) is loaded into memory at runtime and linked in with the PLT and GOT

8 of 11

PLT and GOT

  • The PLT (Procedure Linkage Table) and GOT (Global Offset Table) link libc functions into an ELF at runtime
    • The PLT handles the procedure of calling a function
    • The GOT stores the addresses of functions
  • To call a libc function, the PLT entry for the function is called, not the function itself
  • The PLT redirects code execution to the address stored in the GOT
    • If the address is not yet known, it is obtained from the dynamic linker and stored in the GOT - interestingly, this means that write permission is enabled for the GOT

9 of 11

Return to libc - Ret2libc

  • The attacker can return to a libc function by returning to the PLT entry of a function or directly to the function in libc
    • PLT addresses can be found if the position of the binary is known (such as if PIE is disabled)
    • Remember that all of libc is loaded into memory - if you know the address of one libc function you know the address of all of them
  • Ret2libc and ROP gadgets are often combined in order to be used most effectively

10 of 11

Mitigations

  • Position Independent Executables (PIE) and Address Space Layout Randomization (ASLR) - addresses of libc and the executable are randomized so return addresses are difficult to find
  • Stack canaries - stored on the stack just above the return address and compared to a global canary before returning - protects against changing the return address by buffer overflow
  • Intelligent compilation - compilers like GCC try to avoid creating ROP gadgets
  • Non-executable stack - prevents returning to the stack and executing code from the user input

11 of 11

Further reading