fastbin double free原理
Fastbin Double Free 是指 fastbin 的 chunk 可以被多次释放,因此可以在 fastbin 链表中存在多次。这样导致的后果是多次分配可以从 fastbin 链表中取出同一个堆块,相当于多个指针指向同一个堆块,结合堆块的数据内容可以实现类似于类型混淆 (type confused) 的效果。(即可以构造假的chunk实现任意地址写)
Fastbin Double Free 能够成功利用主要有两部分的原因
- fastbin 的堆块被释放后 next_chunk 的 pre_inuse 位不会被清空
- fastbin 在执行 free 的时候仅验证了 main_arena 直接指向的块,即链表指针头部的块。对于链表后面的块,并没有进行验证。例如,现在有chunk1和chunk2,如果我们在 chunk1 释放后,再释放 chunk2 ,这样 main_arena 就指向 chunk2 而不是 chunk1 了,此时我们再去释放 chunk1 就不再会被检测到。
例题-1 samsara
直接拖进ida进行分析
void __fastcall main(__int64 a1, char **a2, char **a3)
{
int v3; // ebx
int v4; // [rsp+Ch] [rbp-44h]
int v5; // [rsp+10h] [rbp-40h]
__gid_t rgid; // [rsp+14h] [rbp-3Ch]
__int64 v7; // [rsp+18h] [rbp-38h]
__int64 v8; // [rsp+20h] [rbp-30h]
__int64 v9; // [rsp+28h] [rbp-28h]
__int64 v10; // [rsp+30h] [rbp-20h]
unsigned __int64 v11; // [rsp+38h] [rbp-18h]
v11 = __readfsqword(0x28u);
setvbuf(stdout, 0LL, 2, 0LL);
rgid = getegid();
setresgid(rgid, rgid, rgid);
v8 = 0LL;
puts("After defeating the Demon Dragon, you turned yourself into the Demon Dragon...");
while ( 2 )
{
v10 = 0LL;
sub_A50();
//===============菜单函数==============//
// puts("1. Capture a human"); //
//puts("2. Eat a human"); //
//puts("3. Cook a human"); //
//puts("4. Find your lair"); //
//puts("5. Move to another kingdom"); //
//puts("6. Commit suicide"); //
//====================================//
_isoc99_scanf("%d", &v4);
switch ( (unsigned int)off_F70 )
{
case 1u:
if ( dword_20202C >= 7 ) //最多只可以抓7个人
{
puts("You can't capture more people.");
}
else
{
v3 = dword_20202C;
qword_202040[v3] = malloc(8uLL);//为每个人malloc一块空间,将返回的指针存入qword_202040数组中
++dword_20202C;
puts("Captured.");
}
continue;
case 2u:
puts("Index:");
_isoc99_scanf("%d", &v5);
//free掉对应的chunk块,但这里要注意,free掉对应的chunk块之后并没有将指针置NULL。这就是本题漏洞所在
free(qword_202040[v5]);
puts("Eaten.");
continue;
case 3u:
puts("Index:");
_isoc99_scanf("%d", &v5);
puts("Ingredient:");
//编辑对应的堆块内容
_isoc99_scanf("%llu", &v10);
*(_QWORD *)qword_202040[v5] = v10;
puts("Cooked.");
continue;
case 4u:
//打印v7变量的地址
printf("Your lair is at: %pn", &v7);
continue;
case 5u:
//为v7变量赋值
puts("Which kingdom?");
_isoc99_scanf("%llu", &v9);
v7 = v9;
puts("Moved.");
continue;
case