# pwn 学习笔记(12)–Chunk Extend and Overlapping
chunk extend 是堆漏洞的一种常见利用手法,通过 extend 可以实现 chunk overlapping(块重叠) 的效果。这种利用方法需要以下的时机和条件:
- 程序中存在基于堆的漏洞
- 漏洞可以控制 chunk header 中的数据
# 1、对 inuse 的 fastbin 进行 extend:
1 2 3 4 5 6 7 8 9 10 11 12 13
| int main(void) { void *ptr,*ptr1;
ptr=malloc(0x10); malloc(0x10);
*(long long *)((long long)ptr-0x8)=0x41;
free(ptr); ptr1=malloc(0x30); return 0; }
|
首先进行两次 malloc,之后看看 heap 的状态:
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
| In file: /mnt/hgfs/sharedict/ChunkExtend/extend.c 3 void *ptr,*ptr1; 4 5 ptr=malloc(0x10);//分配第一个0x10的chunk 6 malloc(0x10);//分配第二个0x10的chunk 7 ► 8 *(long long *)((long long)ptr-0x8)=0x41;// 修改第一个块的size域 9 10 free(ptr); 11 ptr1=malloc(0x30);// 实现 extend,控制了第二个块的内容 12 return 0; 13 } ─────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────── 00:0000│ rsp 0x7fffffffde30 —▸ 0x555555758010 ◂— 0x0 01:0008│ 0x7fffffffde38 ◂— 0x0 02:0010│ rbp 0x7fffffffde40 —▸ 0x5555555546e0 (__libc_csu_init) ◂— push r15 03:0018│ 0x7fffffffde48 —▸ 0x7ffff7a2d840 (__libc_start_main+240) ◂— mov edi, eax 04:0020│ 0x7fffffffde50 ◂— 0x1 05:0028│ 0x7fffffffde58 —▸ 0x7fffffffdf28 —▸ 0x7fffffffe2ac ◂— '/mnt/hgfs/sharedict/ChunkExtend/test' 06:0030│ 0x7fffffffde60 ◂— 0x1f7ffcca0 07:0038│ 0x7fffffffde68 —▸ 0x55555555468a (main) ◂— push rbp ───────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────── ► f 0 0x5555555546aa main+32 f 1 0x7ffff7a2d840 __libc_start_main+240 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0x21
Allocated chunk | PREV_INUSE Addr: 0x555555758020 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x555555758040 Size: 0x20fc1
pwndbg> bins fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty
|
有地址的话,就去读一下两个堆的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000021 <======Chunk1 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000021 <======Chunk2 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000020fc1 <======Top Chunk 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000000 0x0000000000000000 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000000 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
下一步开始释放,看一看修改 chunk1 的 size 域大小:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0x41
Top chunk | PREV_INUSE Addr: 0x555555758040 Size: 0x20fc1
pwndbg> bins fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty
|
发现 chunk2 被修改后增大了的 chunk1 给那占了,heap 里就只有一个 Chunk 了,看看内存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000041 <======原Chunk1 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000021 <======原Chunk2 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000020fc1 <======Top Chunk 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000000 0x0000000000000000 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000000 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
除去 chunk1 的 size 域变化了以外,似乎没有其他变化,但是,逻辑上来说,现在的堆里只有一个 chunk 了,之后 free 掉 chunk1 看看:
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
| pwndbg> heap Free chunk (fastbins) | PREV_INUSE Addr: 0x555555758000 Size: 0x41 fd: 0x00
Top chunk | PREV_INUSE Addr: 0x555555758040 Size: 0x20fc1
pwndbg> bins fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x555555758000 ◂— 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty
|
之后读取下内存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000041 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000021 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000020fc1 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000000 0x0000000000000000 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000000 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
下一步是重头戏,试想,如果原 chunk1 的 size 域没有真正变化,那么我们进行 malloc 一个 0x30 大小的堆块的时候,就不会分配到这个地址上,而是从 Top Chunk 里拆分,那么事实上是怎么样的呢?实践出真知,看一下吧:
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
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0x41
Top chunk | PREV_INUSE Addr: 0x555555758040 Size: 0x20fc1
pwndbg> bins fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000041 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000021 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000020fc1 <======Top Chunk 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000000 0x0000000000000000 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000000 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
显然,Top Chunk 并未被拆分,这里确定了,似乎 malloc (0x30) 得到的堆块是原 Chunk1 的地址,这里说明了,这里的原 chunk1 因为 size 域被修改了之后成为了一个新的更大的堆块,这里也就造成了所谓的堆重叠了,chunk1 因为修改了 size 域后,生成的那个新的 chunk 和 chunk2 部分重叠了,这也就导致了,有的对原 chunk1 的修改可以修改到 chunk2 的地方,如果 chunk2 保留了指针,那就可以对 chunk2 进行伪造,可以结合类似 off by one 和 UAF 形成很多种利用方式。
# 2、对 inuse 的 smallbin 进行 extend:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
int main() { void *ptr,*ptr1;
ptr=malloc(0x80); malloc(0x10); malloc(0x10);
*(long *)((long)ptr-0x8)=0xb1; free(ptr); ptr1=malloc(0xa0); }
|
首先进行三次分配,其中,第三次分配是防止 extend 后,chunk 与 topchunk 进行合并,无需关注。先看看经过三次 malloc 之后的堆空间是啥样的:
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
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0x91
Allocated chunk | PREV_INUSE Addr: 0x555555758090 Size: 0x21
Allocated chunk | PREV_INUSE Addr: 0x5555557580b0 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x5555557580d0 Size: 0x20f31
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty pwndbg> x/40gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000091 <======Chunk1 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000000 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000000 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000000 0x0000000000000021 <======Chunk2 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000021 <======Chunk3 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000020f31 <======Top Chunk 0x5555557580e0: 0x0000000000000000 0x0000000000000000 0x5555557580f0: 0x0000000000000000 0x0000000000000000 0x555555758100: 0x0000000000000000 0x0000000000000000 0x555555758110: 0x0000000000000000 0x0000000000000000 0x555555758120: 0x0000000000000000 0x0000000000000000 0x555555758130: 0x0000000000000000 0x0000000000000000
|
估摸一下,chunk1 的大小似乎有点大,导致 free 掉的 chunk1 并不会进入 fastbin,而是进入 smallbin,那么修改了 size 域后,原本三个 chunk 在 gdb 里的 heap 指令下依旧少了一个:
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
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0xb1
Allocated chunk | PREV_INUSE Addr: 0x5555557580b0 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x5555557580d0 Size: 0x20f31
pwndbg> bins fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty pwndbg> x/40gx 0x555555758000 0x555555758000: 0x0000000000000000 0x00000000000000b1 <======Chunk1 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000000 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000000 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000000 0x0000000000000021 <======Chunk2 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000021 <======Chunk3 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000020f31 <======Top Chunk 0x5555557580e0: 0x0000000000000000 0x0000000000000000 0x5555557580f0: 0x0000000000000000 0x0000000000000000 0x555555758100: 0x0000000000000000 0x0000000000000000 0x555555758110: 0x0000000000000000 0x0000000000000000 0x555555758120: 0x0000000000000000 0x0000000000000000 0x555555758130: 0x0000000000000000 0x0000000000000000
|
下一步,free 掉 chunk1:
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
| pwndbg> heap Free chunk (unsortedbin) | PREV_INUSE Addr: 0x555555758000 Size: 0xb1 fd: 0x7ffff7dd1b78 bk: 0x7ffff7dd1b78
Allocated chunk Addr: 0x5555557580b0 Size: 0x20
Top chunk | PREV_INUSE Addr: 0x5555557580d0 Size: 0x20f31
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x555555758000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555758000 smallbins empty largebins empty pwndbg> x/40gx 0x555555758000 0x555555758000: 0x0000000000000000 0x00000000000000b1 <======Chunk1 0x555555758010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x555555758020: 0x0000000000000000 0x0000000000000000 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000000 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000000 0x0000000000000021 <======Chunk2 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x00000000000000b0 0x0000000000000020 <======Chunk3 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000020f31 <======Top Chunk 0x5555557580e0: 0x0000000000000000 0x0000000000000000 0x5555557580f0: 0x0000000000000000 0x0000000000000000 0x555555758100: 0x0000000000000000 0x0000000000000000 0x555555758110: 0x0000000000000000 0x0000000000000000 0x555555758120: 0x0000000000000000 0x0000000000000000 0x555555758130: 0x0000000000000000 0x0000000000000000
|
这里发现了一个点需要注意,就是 free 掉 size 域修改了之后的那个 chunk1 之后,chunk3 的 size 域的最低为,也就是 p 位,变成了 0,这也就说明,chunk1 没有放在 fastbin 里,上面也看到了,被放在了 unsortedbin 里。
那么为啥会被放入 unsortedbin 内而不是 smallbin 呢?估计有一下几种可能:
- 当一个较大的 chunk 被分割成两半后,如果剩下的部分大于 MINSIZE,就会被放到 unsortedbin 中。
- 释放一个不属于 fastbin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 就会被放到 unsorted bin 中,当第二次分配的时候,没有在 unsortedbin 中找到合适的,才会被放入到其对应的 bin 中。
之后进行分配,分配 0xa0 大小的堆块,就会发现,原 chunk1 的地址依旧拿去用了:
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
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0xb1
Allocated chunk | PREV_INUSE Addr: 0x5555557580b0 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x5555557580d0 Size: 0x20f31
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty pwndbg> x/40gx 0x555555758000 0x555555758000: 0x0000000000000000 0x00000000000000b1 0x555555758010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x555555758020: 0x0000000000000000 0x0000000000000000 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000000 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000000 0x0000000000000021 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x00000000000000b0 0x0000000000000021 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000020f31 0x5555557580e0: 0x0000000000000000 0x0000000000000000 0x5555557580f0: 0x0000000000000000 0x0000000000000000 0x555555758100: 0x0000000000000000 0x0000000000000000 0x555555758110: 0x0000000000000000 0x0000000000000000 0x555555758120: 0x0000000000000000 0x0000000000000000 0x555555758130: 0x0000000000000000 0x0000000000000000
|
# 3、对 free 的 smallbin 进行 extend:
1 2 3 4 5 6 7 8 9 10 11 12 13
| int main() { void *ptr,*ptr1;
ptr=malloc(0x80); malloc(0x10);
free(ptr);
*(long *)((long)ptr-0x8)=0xb1; ptr1=malloc(0xa0); }
|
首先是两次 malloc:
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
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0x91
Allocated chunk | PREV_INUSE Addr: 0x555555758090 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x5555557580b0 Size: 0x20f51
pwndbg> bins fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000091 <======Chunk1 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000000 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000000 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000000 0x0000000000000021 <======Chunk2 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000020f51 <======Top Chunk 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
之后直接 free 掉 chunk1:
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
| pwndbg> heap Free chunk (unsortedbin) | PREV_INUSE Addr: 0x555555758000 Size: 0x91 fd: 0x7ffff7dd1b78 bk: 0x7ffff7dd1b78
Allocated chunk Addr: 0x555555758090 Size: 0x20
Top chunk | PREV_INUSE Addr: 0x5555557580b0 Size: 0x20f51
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x555555758000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555758000 smallbins empty largebins empty pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000091 <======Chunk1 0x555555758010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x555555758020: 0x0000000000000000 0x0000000000000000 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000000 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000090 0x0000000000000020 <======Chunk2 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000020f51 <======Top Chunk 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
这里还是能看出来存在两个 chunk 的,当修改了 size 域大小后:
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
| pwndbg> heap Free chunk (unsortedbin) | PREV_INUSE Addr: 0x555555758000 Size: 0xb1 fd: 0x7ffff7dd1b78 bk: 0x7ffff7dd1b78
Top chunk | PREV_INUSE Addr: 0x5555557580b0 Size: 0x20f51
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x555555758000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555758000 smallbins empty largebins empty pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x00000000000000b1 0x555555758010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x555555758020: 0x0000000000000000 0x0000000000000000 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000000 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000090 0x0000000000000020 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000020f51 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
原本的三个 chunk 变成了两个,并且 chunk2 还是 allocated 状态,重叠之后,chunk1 是 free 状态,所以整个 chunk 依旧是 free 状态。之后 malloc (0xa0) 试试:
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
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0xb1
Top chunk | PREV_INUSE Addr: 0x5555557580b0 Size: 0x20f51
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x00000000000000b1 0x555555758010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x555555758020: 0x0000000000000000 0x0000000000000000 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000000 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000090 0x0000000000000020 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000020f51 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
# 4、extend 前向 overlapping:
1 2 3 4 5 6 7 8 9 10 11 12 13
| int main() { void *ptr,*ptr1;
ptr=malloc(0x10); malloc(0x10); malloc(0x10); malloc(0x10); *(long *)((long)ptr-0x8)=0x61; free(ptr); ptr1=malloc(0x50); }
|
还是老样子,进行 4 次 malloc,看下 heap 和 bin 以及 chunk 的内容:
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
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0x21
Allocated chunk | PREV_INUSE Addr: 0x555555758020 Size: 0x21
Allocated chunk | PREV_INUSE Addr: 0x555555758040 Size: 0x21
Allocated chunk | PREV_INUSE Addr: 0x555555758060 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x555555758080 Size: 0x20f81
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000021 <======Chunk1 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000021 <======Chunk2 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000021 <======Chunk3 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000021 <======Chunk4 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000020f81 <======Top Chunk 0x555555758090: 0x0000000000000000 0x0000000000000000 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000000 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
之后修改 size 域:
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
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0x61
Allocated chunk | PREV_INUSE Addr: 0x555555758060 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x555555758080 Size: 0x20f81
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000061 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000021 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000021 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000021 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000020f81 0x555555758090: 0x0000000000000000 0x0000000000000000 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000000 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
之后 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0x61
Allocated chunk | PREV_INUSE Addr: 0x555555758060 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x555555758080 Size: 0x20f81
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000061 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000021 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000021 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000021 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000020f81 0x555555758090: 0x0000000000000000 0x0000000000000000 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000000 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
之后重新 malloc:
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
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0x61
Allocated chunk | PREV_INUSE Addr: 0x555555758060 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x555555758080 Size: 0x20f81
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty pwndbg> x/30gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000061 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000021 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000021 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000021 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000020f81 0x555555758090: 0x0000000000000000 0x0000000000000000 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000000 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000000 0x5555557580e0: 0x0000000000000000 0x0000000000000000
|
# 5、通过 extend 前向 overlapping:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int main(void) { void *ptr1,*ptr2,*ptr3,*ptr4; ptr1=malloc(128); ptr2=malloc(0x10); ptr3=malloc(0x10); ptr4=malloc(128); malloc(0x10); free(ptr1); *(int *)((long long)ptr4-0x8)=0x90; *(int *)((long long)ptr4-0x10)=0xd0; free(ptr4); malloc(0x150); }
|
经过五次 malloc 之后:
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
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0x91
Allocated chunk | PREV_INUSE Addr: 0x555555758090 Size: 0x21
Allocated chunk | PREV_INUSE Addr: 0x5555557580b0 Size: 0x21
Allocated chunk | PREV_INUSE Addr: 0x5555557580d0 Size: 0x91
Allocated chunk | PREV_INUSE Addr: 0x555555758160 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x555555758180 Size: 0x20e81
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty pwndbg> x/54gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000091 0x555555758010: 0x0000000000000000 0x0000000000000000 0x555555758020: 0x0000000000000000 0x0000000000000000 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000000 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000000 0x0000000000000021 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000021 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000091 0x5555557580e0: 0x0000000000000000 0x0000000000000000 0x5555557580f0: 0x0000000000000000 0x0000000000000000 0x555555758100: 0x0000000000000000 0x0000000000000000 0x555555758110: 0x0000000000000000 0x0000000000000000 0x555555758120: 0x0000000000000000 0x0000000000000000 0x555555758130: 0x0000000000000000 0x0000000000000000 0x555555758140: 0x0000000000000000 0x0000000000000000 0x555555758150: 0x0000000000000000 0x0000000000000000 0x555555758160: 0x0000000000000000 0x0000000000000021 0x555555758170: 0x0000000000000000 0x0000000000000000 0x555555758180: 0x0000000000000000 0x0000000000020e81 0x555555758190: 0x0000000000000000 0x0000000000000000 0x5555557581a0: 0x0000000000000000 0x0000000000000000
|
free 了 chunk1 之后,chunk2 的 p 位已经变成 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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| pwndbg> heap Free chunk (unsortedbin) | PREV_INUSE Addr: 0x555555758000 Size: 0x91 fd: 0x7ffff7dd1b78 bk: 0x7ffff7dd1b78
Allocated chunk Addr: 0x555555758090 Size: 0x20
Allocated chunk | PREV_INUSE Addr: 0x5555557580b0 Size: 0x21
Allocated chunk | PREV_INUSE Addr: 0x5555557580d0 Size: 0x91
Allocated chunk | PREV_INUSE Addr: 0x555555758160 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x555555758180 Size: 0x20e81
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x555555758000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555758000 smallbins empty largebins empty pwndbg> x/54gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000091 <======Chunk1 0x555555758010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x555555758020: 0x0000000000000000 0x0000000000000000 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000000 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000090 0x0000000000000020 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000021 <======Chunk2 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x0000000000000000 0x0000000000000091 <======Chunk3 0x5555557580e0: 0x0000000000000000 0x0000000000000000 0x5555557580f0: 0x0000000000000000 0x0000000000000000 0x555555758100: 0x0000000000000000 0x0000000000000000 0x555555758110: 0x0000000000000000 0x0000000000000000 0x555555758120: 0x0000000000000000 0x0000000000000000 0x555555758130: 0x0000000000000000 0x0000000000000000 0x555555758140: 0x0000000000000000 0x0000000000000000 0x555555758150: 0x0000000000000000 0x0000000000000000 0x555555758160: 0x0000000000000000 0x0000000000000021 <======Chunk4 0x555555758170: 0x0000000000000000 0x0000000000000000 0x555555758180: 0x0000000000000000 0x0000000000020e81 <======Top Chunk 0x555555758190: 0x0000000000000000 0x0000000000000000 0x5555557581a0: 0x0000000000000000 0x0000000000000000
|
之后修改了 chunk3 的 pre_inuse,也就是 size 的最低为 P 位为 0,然后修改 pre_size 位为 0xd8,
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
| pwndbg> heap Free chunk (unsortedbin) | PREV_INUSE Addr: 0x555555758000 Size: 0x91 fd: 0x7ffff7dd1b78 bk: 0x7ffff7dd1b78
Allocated chunk Addr: 0x555555758090 Size: 0x20
Allocated chunk | PREV_INUSE Addr: 0x5555557580b0 Size: 0x21
Allocated chunk Addr: 0x5555557580d0 Size: 0x90
Allocated chunk | PREV_INUSE Addr: 0x555555758160 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x555555758180 Size: 0x20e81
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x555555758000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555758000 smallbins empty largebins empty pwndbg> x/54gx 0x555555758000 0x555555758000: 0x0000000000000000 0x0000000000000091 <======Chunk1 0x555555758010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x555555758020: 0x0000000000000000 0x0000000000000000 0x555555758030: 0x0000000000000000 0x0000000000000000 0x555555758040: 0x0000000000000000 0x0000000000000000 0x555555758050: 0x0000000000000000 0x0000000000000000 0x555555758060: 0x0000000000000000 0x0000000000000000 0x555555758070: 0x0000000000000000 0x0000000000000000 0x555555758080: 0x0000000000000000 0x0000000000000000 0x555555758090: 0x0000000000000090 0x0000000000000020 0x5555557580a0: 0x0000000000000000 0x0000000000000000 0x5555557580b0: 0x0000000000000000 0x0000000000000021 <======Chunk2 0x5555557580c0: 0x0000000000000000 0x0000000000000000 0x5555557580d0: 0x00000000000000d0 0x0000000000000090 <======Chunk3 0x5555557580e0: 0x0000000000000000 0x0000000000000000 0x5555557580f0: 0x0000000000000000 0x0000000000000000 0x555555758100: 0x0000000000000000 0x0000000000000000 0x555555758110: 0x0000000000000000 0x0000000000000000 0x555555758120: 0x0000000000000000 0x0000000000000000 0x555555758130: 0x0000000000000000 0x0000000000000000 0x555555758140: 0x0000000000000000 0x0000000000000000 0x555555758150: 0x0000000000000000 0x0000000000000000 0x555555758160: 0x0000000000000000 0x0000000000000021 <======Chunk4 0x555555758170: 0x0000000000000000 0x0000000000000000 0x555555758180: 0x0000000000000000 0x0000000000020e81 <======Top Chunk 0x555555758190: 0x0000000000000000 0x0000000000000000 0x5555557581a0: 0x0000000000000000 0x0000000000000000
|
可以看出来,chunk3 的 pre_size 域的大小刚好能够包含到完 chunk1 和 chunk2。之后 free 掉了 chunk3:
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
| pwndbg> heap Free chunk (unsortedbin) | PREV_INUSE Addr: 0x555555758000 Size: 0x161 fd: 0x7ffff7dd1b78 bk: 0x7ffff7dd1b78
Allocated chunk Addr: 0x555555758160 Size: 0x20
Top chunk | PREV_INUSE Addr: 0x555555758180 Size: 0x20e81
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x555555758000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555758000 smallbins empty largebins empty
|
会发现,前面的三个 chunk 都被合并成了一个,这里主要是因为 unlink 的原因,导致了 chunk3 和前面的两个(主要是 pre_size 指定的大小范围内的)chunk 发生了合并。之后再进行 malloc,会分配走新的那个 chunk1:
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
| pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x555555758000 Size: 0x161
Allocated chunk | PREV_INUSE Addr: 0x555555758160 Size: 0x21
Top chunk | PREV_INUSE Addr: 0x555555758180 Size: 0x20e81
pwndbg> bin fastbins 0x20: 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty
|