前置知识
四个不同类型chunk区别
fast chunk 大小在32字节~128字节(0x20~0x80)的chunk称为“fast chunk”
small chunk 小于1024字节(0x400)
large chunk 大于等于1024字节(0x400)
unsorted bin 当释放较小或较大的chunk的时候,如果系统没有将它们添加到对应的bins中,系统就将这些chunk添加到unsorted bin中
First_Fit UAF
利用原理
在分配内存时,malloc 会先到 unsorted bin(或者fastbins) 中查找适合的被 free 的 chunk,如果没有,就会把 unsorted bin 中的所有 chunk 分别放入到所属的 bins 中,然后再去这些 bins 里去找合适的 chunk。可以看到第三次 malloc 的地址和第一次相同,即 malloc 找到了第一次 free 掉的 chunk,并把它重新分配。
利用代码
1 |
|
具体分析
malloc后,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
37pwndbg> x/10x 0x555555559290
0x555555559290: 0x00000000 0x00000000 0x00000521 0x00000000
0x5555555592a0: 0x00000000 0x00000000 0x00000000 0x00000000
0x5555555592b0: 0x00000000 0x00000000
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x555555559000
Size: 0x291
Allocated chunk | PREV_INUSE
Addr: 0x555555559290
Size: 0x521
Allocated chunk | PREV_INUSE
Addr: 0x5555555597b0
Size: 0x261
Top chunk | PREV_INUSE
Addr: 0x555555559a10
Size: 0x205f1
pwndbg> bins
tcachebins
empty
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
emptyfree后chunk被放到了unsorted bin中,且chunk上放入了fd/bk,
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
41pwndbg> bins
tcachebins
empty
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x555555559290 —▸ 0x7ffff7fb1be0 (main_arena+96) ◂— 0x555555559290
smallbins
empty
largebins
empty
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x555555559000
Size: 0x291
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x555555559290
Size: 0x521
fd: 0x7ffff7fb1be0
bk: 0x7ffff7fb1be0
Allocated chunk
Addr: 0x5555555597b0
Size: 0x260
Top chunk | PREV_INUSE
Addr: 0x555555559a10
Size: 0x205f1
pwndbg> x/10gx 0x555555559290
0x555555559290: 0x0000000000000000 0x0000000000000521
0x5555555592a0: 0x00007ffff7fb1be0 0x00007ffff7fb1be0
0x5555555592b0: 0x0000000000000000 0x0000000000000000
0x5555555592c0: 0x0000000000000000 0x0000000000000000
0x5555555592d0: 0x0000000000000000 0x0000000000000000再次malloc后
1 | pwndbg> heap |
Fastbin_Dup.c DOUBLE-FREE
利用代码
1 |
|
具体分析
3次free后,出现double free
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15pwndbg> bins
fastbins
0x20: 0x55555555c000 —▸ 0x55555555c020 ◂— 0x55555555c000
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty3次malloc后,a和d指向同一个地址,如果d的值可控即等于往任意地址写数据
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
30pwndbg>
bins
fastbins 0x20: 0x55555555c020 —▸ 0x55555555c000 ◂— 0x55555555c020 0x30: 0x0 0x40: 0x0 empty
largebins
empty
pwndbg> heap
Free chunk (fastbins) | PREV_INUSE
Addr: 0x55555555c000
Size: 0x21
fd: 0x55555555c020
Free chunk (fastbins) | PREV_INUSE
Addr: 0x55555555c020
Size: 0x21
fd: 0x55555555c000
Allocated chunk | PREV_INUSE
Addr: 0x55555555c040
Size: 0x21
Top chunk | PREV_INUSE
Addr: 0x55555555c060
Size: 0x20fa1
1st malloc(8): 0x55555555c010
2nd malloc(8): 0x55555555c030
3rd malloc(8): 0x55555555c010
malloc(8): 0x7fffffffe008
Fastbin_Dup_Into_Stack UAF利用
具体代码
1 |
|
具体分析
a被free两次以后
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
28pwndbg> bins
fastbins
0x20: 0x55555555b000 —▸ 0x55555555b020 ◂— 0x55555555b000
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> x/10gx 0x55555555b020
0x55555555b020: 0x0000000000000000 0x0000000000000021
0x55555555b030: 0x000055555555b000 0x0000000000000000
0x55555555b040: 0x0000000000000000 0x0000000000000021
0x55555555b050: 0x0000000000000000 0x0000000000000000
0x55555555b060: 0x0000000000000000 0x0000000000020fa1
pwndbg> x/10gx 0x55555555b000
0x55555555b000: 0x0000000000000000 0x0000000000000021
0x55555555b010: 0x000055555555b020 0x0000000000000000
0x55555555b020: 0x0000000000000000 0x0000000000000021
0x55555555b030: 0x000055555555b000 0x0000000000000000
0x55555555b040: 0x0000000000000000 0x0000000000000021执行d = (unsigned long long) (((char)&stack_var) - sizeof(d));后因为d与a指向一个地址,因此可以篡改freechunk里面的fd
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
28pwndbg> bins
fastbins
0x20: 0x55555555b000 —▸ 0x55555555b020 ◂— 0x55555555b000
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> x/10gx 0x55555555b000
0x55555555b000: 0x0000000000000000 0x0000000000000021
0x55555555b010: 0x00007fffffffdff8 0x0000000000000000
0x55555555b020: 0x0000000000000000 0x0000000000000021
0x55555555b030: 0x000055555555b000 0x0000000000000000
0x55555555b040: 0x0000000000000000 0x0000000000000021
pwndbg> x/10gx 0x55555555b020
0x55555555b020: 0x0000000000000000 0x0000000000000021
0x55555555b030: 0x000055555555b000 0x0000000000000000
0x55555555b040: 0x0000000000000000 0x0000000000000021
0x55555555b050: 0x0000000000000000 0x0000000000000000
0x55555555b060: 0x0000000000000000 0x0000000000020fa1
Fastbin_Dup_Consolidate
todo
为什么malloc之后,large chunk被分配到了small bin中?
利用代码
1 |
|
具体分析
p1被free两次以后
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x55555555b000 ◂— 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
emptymalloc(0x400)后,原来的fastbin被分配到了smallbin.因为0✖400属于large chunk 会调用malloc_consolidate()合并fastbins中的chunk,并将这些空闲的chunk加入unsorted bin中,之后unsorted bin中的chunk按照大小被放回small bins/large bins中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
0x50: 0x55555555b000 —▸ 0x7ffff7dd4bb8 (main_arena+152) ◂— 0x55555555b000
largebins
empty再次free p1 ,可以看到p1同时出现在fast bins和small bins中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x55555555b000 ◂— 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
0x50 [corrupted]
FD: 0x55555555b000 ◂— 0x0
BK: 0x55555555b000 —▸ 0x7ffff7dd4bb8 (main_arena+152) ◂— 0x55555555b000
largebins
empty
Now p1 is in unsorted bin and fast bin. So we'will get it twice: 0x55555555b010 0x55555555b010
Unsafe_Unlink
利用场景
最常见的利用场景是我们有一个可以溢出漏洞和一个全局指针。
利用代码
1 |
|
具体分析
设置chunk0_ptr[2]和chunk0_ptr[3]后的chunk(实际情况应该是利用漏洞来覆盖,这里直接通过指针来操作)
1
2
3
4
5
6
7
8
9
10
11
12pwndbg> x/30gx 0x55555555b000
0x55555555b000: 0x0000000000000000 0x0000000000000091
0x55555555b010: 0x0000000000000000 0x0000000000000000
0x55555555b020: 0x0000555555558018 0x0000555555558020
0x55555555b030: 0x0000000000000000 0x0000000000000000
0x55555555b040: 0x0000000000000000 0x0000000000000000
0x55555555b050: 0x0000000000000000 0x0000000000000000
0x55555555b060: 0x0000000000000000 0x0000000000000000
0x55555555b070: 0x0000000000000000 0x0000000000000000
0x55555555b080: 0x0000000000000000 0x0000000000000000
0x55555555b090: 0x0000000000000000 0x0000000000000091
0x55555555b0a0: 0x0000000000000000 0x0000000000000000chunk1_hdr[0] = malloc_size;chunk1_hdr[1] &= ~1;我们把chunk1_hdr伪造成空闲chunk,即把chunk of size的 inuse位设置成0,把size of previous chunk设置成80(90-10),程序会根据presize来寻找要合并的chunk的头部,这样在free时会让程序错误认为chunk0的开始位置为我们的伪造的chunk位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18pwndbg> x/30gx 0x55555555b000
0x55555555b000: 0x0000000000000000 0x0000000000000091
0x55555555b010: 0x0000000000000000 0x0000000000000000
0x55555555b020: 0x0000555555558018 0x0000555555558020
0x55555555b030: 0x0000000000000000 0x0000000000000000
0x55555555b040: 0x0000000000000000 0x0000000000000000
0x55555555b050: 0x0000000000000000 0x0000000000000000
0x55555555b060: 0x0000000000000000 0x0000000000000000
0x55555555b070: 0x0000000000000000 0x0000000000000000
0x55555555b080: 0x0000000000000000 0x0000000000000000
0x55555555b090: 0x0000000000000080 0x0000000000000090
pwndbg> x/10x 0x0000555555558010
0x555555558010: 0x0000000000000000 0x0000000000000000
0x555555558020 <stderr@@GLIBC_2.2.5>: 0x00007ffff7dd5540 0x0000000000000000
0x555555558030 <chunk0_ptr>: 0x000055555555b010 0x00020000002c0030
0x555555558040: 0x0000000800000000 0x0000000011c90000
0x555555558050: 0x0000000004420000 0x0000000000000000free chunk1_ptr 时,因为在free一个非fastbin大小的chunk时,会对前后的chunk进行检测,如果前后的chunk存在被free的状态,则会进行合并。合并之前自然也需要用unlink将其从链表上取下来。因此chunk0被unlink,导致bk->fd =fd(bk=0x0000555555558020,bk->fd=bk+0x10=0x0000555555558030,fd=0x0000555555558018)所以0x0000555555558030被设置成了0x0000555555558018
1 |
|
- chunk0_ptr[3] = (uint64_t) victim_string;fprintf(stderr, “Original value: %s\n”,victim_string);这时候chunk0_ptr为0x555555558018,chunk0_ptr[3]为0x555555558030,经过这步操作后全局变量chunk0_ptr里面的指针有被修改为0x00007fffffffe030
1 | pwndbg> p chunk0_ptr |
chunk0_ptr[0] = 0x4141414142424242LL;fprintf(stderr, “New Value: %s\n”,victim_string);
1
2pwndbg> x/10s 0x00007fffffffe030
0x7fffffffe030: "BBBBAAAA"libc2.26版本。则需要把tacahe填充满才行
House_of_Spirit
利用代码
1 |
|