On the return-to-libc post, we described the process of injecting a system call with parameters via environment variables to start a new process. But this requires to execute another program (which maybe no available on the target).
Instead of calling system we can call other instructions from somewhere in the memory. But it would be difficult to find instructions in the memory which does exactly what we want. The idea of ROP is to use only instructions at the end of functions before a return (=Gadgets) and combine them via manipulation of the return addresses to execute arbitrary code.
Helper functions for ROP
The following Windows system calls can be used to construct a ROP chain.
VirtualProtect()
We want to use VirtualProtect() before our shellcode to disable DEP for the memory where we have injected it. To do this, we start our execution at the overwritten EIP by calling a series of gadgets which calculate the current memory addresses and arguments for the VirtualProtect() syscall, call it and return to our shellcode.
- We overwrite the buffer with an overflow
- We overwrite the RIP’s address with an address where we have a gadget which saves the current stack pointer. We will use it as our reference point for all other instructions.
- Then we call a gadget which jumps to our next gadget after the following block of reserved spaces for the VirtualProtect() call and arguments. Note that these memory space is initialy only overwritten, but not with the final values (we don’t know yet).
- The next gadget calculates the start address of our shellcode (which comes later in the stack) and stores it in a register.
- The next gadget stored this calculated value to the memory placeholder position for it.
- Now, three / six other gadgets follow which calculate and store the other arguments. After all these gadget ran, all arguments from our placeholder memory are set with the valid values.
- Now we set with a last gadget the return address for VirtualProtect() and then jump to it.
- VirtualProtect() is executed and returns to our provided return address, where…
- our shellcode is.
General notes
- Sometimes you cannot find a perfect gadget which does one instruction and has a ret directly after it. Then, try to find gadgets which have instructions before the ret which don’t harm you. For example, if there is a pop instruction before the ret instruction, you could add a dummy value to the stack before so that an additional pop would not destroy the stack order you overwrote.

Leave a Reply
You must be logged in to post a comment.