The ROP tool can be used to build stacks pretty trivially. Let’s create a fake binary which has some symbols which might have been useful.
Creating a ROP object which looks up symbols in the binary is pretty straightforward.
With the ROP object, you can manually add stack frames.
Inspecting the ROP stack is easy, and laid out in an easy-to-read manner.
The ROP module is also aware of how to make function calls with standard Linux ABIs.
Let’s assume we have a trivial binary that just reads some data onto the stack, and returns.
And perhaps a nice “write” function.
And a way to exit cleanly.
The raw data from the ROP stack is available via str .
For amd64 binaries, the registers are loaded off the stack. Pwntools can do basic reasoning about simple “pop; pop; add; ret”-style gadgets, and satisfy requirements so that everything “just works”.
In some cases, control of the desired register is not available. However, if you have control of the stack, EAX, and can find a int 0x80 gadget, you can use sigreturn.
Even better, this happens automagically.
Our example binary will read some data onto the stack, and not do anything else interesting.
Let’s create a ROP object and invoke the call.
Class which simplifies the generation of ROP-chains.
base (int) – Stack address where the first byte of the ROP chain lies, if known.
badchars (str) – Characters which should not appear in ROP gadget addresses.
Construct the ROP chain into a list of elements which can be passed to flat().
base (int) – The base address to build the rop-chain from. Defaults to base.
description (dict) – Optional output argument, which will gets a mapping of address: description for each address on the stack, starting at base.
resolvable (str,int) – Value which can be looked up via ‘resolve’, or is already an integer.
arguments (list) – List of arguments which can be passed to pack(). Alternately, if a base address is set, arbitrarily nested structures of strings or integers can be provided.
Returns a gadget with the exact sequence of instructions specified in the instructions argument.
Generates padding to be inserted into the ROP stack.
Adds a raw integer or string to the ROP chain.
If your architecture requires aligned values, then make sure that any given string is aligned!
data (int/str) – The raw value to put onto the rop chain.
Search for a gadget which matches the specified criteria.
move (int) – Minimum number of bytes by which the stack pointer is adjusted.
regs (list) – Minimum list of registers which are popped off the stack.
order (str) – Either the string ‘size’ or ‘regs’. Decides how to order multiple gadgets the fulfill the requirements.
The search will try to minimize the number of bytes popped more than requested, the number of registers touched besides the requested and the address.
If order == 'size', then gadgets are compared lexicographically by (total_moves, total_regs, addr), otherwise by (total_regs, total_moves, addr).
Iterate through all gadgets which move the stack pointer by at least move bytes, and which allow you to set all registers in regs.
Returns an list of addresses/values which will set the specified register context.
A list of tuples, ordering the stack.
Each tuple is in the form of (value, name) where value is either a gadget address or literal value to go on the stack, and name is either a string name or other item which can be “unresolved”.
This is basically an implementation of the Set Cover Problem, which is NP-hard. This means that we will take polynomial time N**2, where N is the number of gadgets. We can reduce runtime by discarding useless and inferior gadgets ahead of time.
String containing the symbol name for the address, disassembly for a gadget (if there’s one at that address), or an empty string.
Stack address where the first byte of the ROP chain lies, if known.