PWN堆house-of-rabbit
-
house-of-rabbit利用就被称为fastbin_dup_consolidate利用。 -
house of rabbit是对malloc_consolidate的利用。因此,不一定要按照原作者的思路来,他的思路需要满足的条件太多了。 -
参考博客:[House Of Rabbit-原理 | Pwn进你的心](https://ywhkkx.github.io/2022/03/12/House Of Rabbit-原理/)
前置知识
malloc_consolidate函数
- 在
malloc中有一个函数,这个函数是一个特别的版本的free和合并,之前我们在malloc流程分析的时候会看到有free和合并,这个操作就是通过malloc_consolidate这个函数来实现的。consolidate在英文中就有合并的意思。

- 我们就来介绍一下这个函数的具体过程:
malloc_consolidate首先会从存储堆块大小更小的fastbin逐一遍历里面的chunk,每遍历到一个chunk,就会处理这个chunk- 如果这个chunk的
prev_inuse位为0就会进行后向合并 - 如果这个chunk的相邻高地址chunk是
top_chunk,它就会和top_chunk合并 - 如果这个chunk的相邻高地址chunk是空闲的,该chunk就会进行前向合并
chunk如果没有与top chunk相邻就会使用头插法将被处理的chunk放入unsorted bin中- 如果
chunk的size不在smallbin的范围内就先会设置fd_nextsize和bk_nextsize为NULL
- 如果这个chunk的
相关代码
- 首先执行
consolidate最重要的就是malloc_consolidate这个函数,主要就看malloc_consolidate主要的作用和malloc、free中何时调用malloc_consolidate这个函数
相关宏定义
1 | // 告诉malloc之后要整理fastbin |
malloc_consolidate
1 | /* |
- 接下来介绍触发
malloc_consolidate这个函数的五个地方
触发点1
_int_malloc_触发malloc__consolidate
1 | /* |
触发点2
_int_malloc中使用malloc_consolidate(top chunk)
1 | use_top: |
触发点3
_int_free中malloc_consolidate
1 | /* |
触发点4
malloc_trim
1 | /* |
触发点5
_int_mallnfo
1 | static void |
触发点6
mallopt函数
1 | int |
触发malloc_consolidate函数
- 现在我们来探究一下何时何时会触发这个函数。这里我参考的是实验部分的注释,实验部分的注释已经讲得很明白了,什么时候会触发
malloc_consolidate函数。 - 这里我们就通过几个小而简短的代码,来看看如何触发
malloc_consolidate函数。
1 | 1. _int_malloc: 一个处于large sized范围的chunk正在被分配 |
触发方式一(申请large sized大小)
-
其实申请
smallbin范围大小的堆块也能触发malloc_consolidate但是这个触发机制还有点迷,就不先介绍了。 -
当我们申请一个堆块,该堆块的大小处于
large bin管理的堆块大小范围内,malloc_consolidate函数就会被触发。 -
示例代码1,当释放的堆块和
top_chunk相邻的时候:- 申请
0x400大小,也就是在large bin范围中大小的堆块,就会触发malloc_consolidate - 将
fast_bin中的堆块都取出来,相邻堆块的合并,并且放入unsorted_bin中 - 在这里由于
unsorted_bin与top_chunk相邻,所以unsorted_bin就会与top_chunk合并 - 之后就是直接申请
0x400堆块的大小
- 申请
1 |
|



- 示例代码2,当所处
fast_bin中的堆块不与top_chunk相邻:- 申请
0x400大小的堆块时,触发malloc_consolidate。 - 将处于
fastbin中堆块取出,放入unsorted_bin中 - 然后发现
unsorted_bin中的堆块不能满足0x400大小的申请,就把unsorted_bin中的堆块放入small_bin中,之后程序还是会从top_chunk切割下来一块内存
- 申请
1 |
|


- 示例代码3,
malloc_consolidate会fastbin中相邻的堆块,使得组成更大的一个堆块:
1 |
|


- 示例代码4,只要是相邻的即使不在同一个
fastbin也是直接合并。
1 |
|


- 示例代码5,物理地址不相邻的无法合并,各自放入
small_bin中
1 |
|


实验一
- 该实验也是来自github项目中的
how2heap,在how2heap中,这个实验的文件名叫做fastbin_dup_consolidate.c - 注意:
house_of_rabbit这个利用方式很多,主要就是利用malloc_consolidate,至于伪造堆块的方式,可以在做题中进行归纳。 - 该实验的漏洞利用过程其实不太明显,但是能比较清晰的告诉我们如果触发
malloc_consolidate
源码(英文)
源码
1 |
|
源码(中文)
- 还是老样子,把这个代码翻译一遍
1 |
|
调试
- 接下来我们跟着实验的代码去动调走一走。我们先使用
calloc这个函数申请了0x40大小的堆块

- 然后我们会将这个堆块释放,这个堆块释放后并不会马上与
Top chunk合并,还是会先放入fastbin中。

- 然后我们再申请一个处于
large bin范围的大小,这里我们选择申请0x400大小的堆块,这时malloc为了减小系统调用的次数,malloc这个函数就会将fastbin中的空闲堆块进行处理。如果处理的堆块与top_chunk相邻该堆块就会与top chunk合并,然后我们所申请的0x400大小堆块的地址就是上图中的fastbin中的地址

- 此时
p1指针还没有被置0,这时我们就还可以对p1进行释放,这时我们就可以看到,当我们释放p1这个指针的时候就会使得我们所申请的0x400大小的堆块释放后与top_chunk合并,这时top_chunk的地址就变成了我们原来申请的堆块的地址

- 之后我们再申请
0x400大小的堆块,这样我们的p3指针和p4指针就指向了同一个堆块。

- 这个实验的利用方式是通过
UAF漏洞来进行利用的,而在CTF_wiki对house-of-rabbit其实有两种利用方式,第一种其实就是利用UAF漏洞去修改fd指针。 - 而第二种可以通过
UAF或者堆溢出的漏洞去修改size位,从而构造出堆叠。
利用方式
house of rabbit主要就是实现堆叠和劫持fd指针。接下来我们举两个实例程序来深入了解一下house of rabbit的这个漏洞利用。
利用方式一
- 修改size位,从而构造堆叠。
1 |
|
- 先来直接调试一下,程序先申请了这样的一个堆块

- 然后再释放堆块

- 此时我们就可以利用堆溢出这个漏洞修改已经在fastbin中堆块的
size位

- 此时我们就构造出了一个堆叠,假如我们通过溢出,修改
size位为0xc1这样中间那块0x20大小的堆块也会被堆叠进去,此时其实就能够构造出UAF漏洞了。

利用方式二
- 修改
fd指针
1 |
|
- 先申请两个堆块

- 然后伪造堆块


- 申请一个
large bin大小的堆块

- 此时我们就能申请到伪造的堆块。

house_of_rabbit_level_1
- 接下来我们就来写一题。
- 这题的题目来源:pwn_hitbctf2018_mutepig
level1_分析1
- 拿到附件我们就先来
check一下这些保护机制。发现开启了如下的保护机制。 got表可以修改,然后PIE没有开启。

- 接下来我们先来静态分析一下这个程序的具体运行逻辑。先来查看
main函数,main函数的运行逻辑如下(我们先根据程序的大致逻辑,修改了函数名称):- 首先
main函数会先进行输入输出初始化即调用init_()函数 - 调用完
init_()函数后就会调用gift()这个函数。(之后具体查看一下,就明白为什么我会重命名为gift函数) - 之后就是进入一个菜单的循环,循环实现的是
增、删、改这三个功能
- 首先

- 我们现在来查看一下
gift这个函数,这个函数会执行system("cat banner.txt"),这就相当于我们有system这个函数了,我们就节省了泄露libc地址这一步。

- 之后我们来查看一下
add()这个函数,这个函数的执行逻辑大概可以分成两个部分- 第一个部分就是让用户输入选项,输入
1、2、3三个选项的其中一个就会申请相应大小的堆块,这里如果输入13337就会申请一个非常大的堆块(只能申请一次)。 - 当申请失败的时候程序就会直接返回
- 之后用户可以向刚申请的堆块写入
0x7字节的数据,第0x8个字节会变成空字节。 - 之后再对
ptr这个指针数组进行遍历操作,将我们刚申请的堆块放入ptr这个指针数组空闲的位置中,在放入之前还会检查数组是否越界。
- 第一个部分就是让用户输入选项,输入

- 然后我们再查看
edit这个选项- 可以向用户指定的堆块重新写入
0x8字节,实际写入0x7字节,最后一个字节会置0 - 然后还会像全局变量
str读入48个字节,即读入0x30字节。
- 可以向用户指定的堆块重新写入

- 之后我们查看
delete这个函数,这个函数实现的功能就为释放用户指定的堆块。注意:这里存在UAF漏洞,也就是说我们可以修改堆块的fd指针

level_1分析2
- 接下来我们就先写好
exp中与程序的交互部分。这时我们发现这个程序没有文字说明,就是纯交互。 exp中交互的部分如下:
1 | from pwn import * |
- 接下来我们就来动态调试,一边动态调试,一边寻找打法。我们发现我们在调用
add函数的时候选择0x3419这个会触发malloc_consolidate此时我们处于fastbin中的堆块就会直接被放入small_bin

- 由于我们堆块申请的是
0xFFFFFFFFFFFFFF70,我们要去查看一下我们真实申请的堆块地址具体是多少,但是查看bss段内存我们发现分配0xFFFFFFFFFFFFFF70大小的堆块时,malloc分配失败,所以我们这个选项的作用其实就是用来触发malloc_consolidate。 - 也有可能是类似于触发
house of force,因为我们的选项3也可以触发malloc_consolidate



- 此时我们需要从
case 1和case 2中入手,以及题目所给的bss段中的这个位置入手

- 由于这题存在
UAF而且只能修改fd指针,所以我们肯定就是从fd指针入手。
level_1_exp
house_of_rabbit_level_2
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 iyheart的博客!

