ROP (to be updated)

Return-Oriented Programming (ROP)

1. Tools

2. How it works

In ROP, we exploit instructions from libraries with fixed addresses (eg. libc) with a return statement at the end (eg. ret). These portions of code (known as "gadgets") are chained together to accomplish a sequence of tasks. For example, loading function arguments that eventually leads to remote-code execution (RCE).

Tools such as ROPgadgetarrow-up-right can be used to simplify the process of looking for these "gadgets"

2.1 Example (x64)

Given a binary with the following conditions:

  1. Partial ASLR

  • Dynamic/changing stack-pointer address

  • Static/constant libc library address

  1. Stack buffer overflow vulnerability

  • Overwrittes address that are eventually stored to a set of known registers which includes the return address (eg. RIP(x64))

With these conditions in mind, we are able to chain together a series of "gadgets" to eventually call the system() function with controlled arguments

...

  1. Overwrite stack portions that corresponds to the rdi, rsi, rdx, etc. registers (depending on how many arguments to pass)

  2. Overwrite the RIP register with known addresses within the libc library

  3. The register used to store the final return address in the ROP "gadget" should be loaded with the address of the function next in the ROP

  4. In conclusion, a changing SP value does not matter, as long as the libc library address is constant, and we are able to finely control the values of appropriate registers

  5. ...

2.2 Example (x86)

...easier than x64 since function arguments are passed on the stack, alongside the current stack pointer (SP). Hence the actual address of SP does not need to be known, as offsets are simply used.

...

2.3 Example (MIPS)

...

2.4 Key points

Even with a binary running on a system that employs partial ASLR (sp randomized, but libc, etc. libraries constant), the following key points can still lead to a success with ROP:

  1. Knowledge of relative offsets from a buffer (that we are able to control an overflow) to the stack pointer

  • An exploit will still be able to control portions of the stack even without knowledge of the actual stack pointer address

  1. Base library (eg. libc) address + relative offsets of functions within that library

  • This makes the exploit deterministic, as it its able to locate the exact instructions for each execution

Last updated