structure
large_bin 与 small_bin 相似,却又不完全相同。
一言以蔽之,large_bin 继承了 small_bin 的双链表结构,但在其基础上添加了一个双链表
,用于快速查找堆块。
同一个 large_bin 中存放的并不是单一 size 的 chunk,而是在某一范围
的chunk,详情可见下表:
size range
size index
[0x400 , 0x440) 64
[0x440 , 0x480) 65
[0x480 , 0x4C0) 66
[0x4C0 , 0x500) 67
[0x500 , 0x540) 68
等差 0x40 …
[0xC00 , 0xC40) 96
[0xC40 , 0xE00) 97
[0xE00 , 0x1000) 98
[0x1000 , 0x1200) 99
[0x1200 , 0x1400) 100
[0x1400 , 0x1600) 101
等差 0x200 …
[0x2800 , 0x2A00) 111
[0x2A00 , 0x3000) 112
[0x3000 , 0x4000) 113
[0x4000 , 0x5000) 114
等差 0x1000 …
[0x9000 , 0xA000) 119
[0xA000 , 0x10000) 120
[0x10000 , 0x18000) 121
[0x18000 , 0x20000) 122
[0x20000 , 0x28000) 123
[0x28000 , 0x40000) 124
[0x40000 , 0x80000) 125
[0x80000 , …. ) 126
largebin管理的是一个范围区间
的堆块,此时fd_nextsize
与bk_nextsize
就派上了用场。
example
现在假设我们有5个 large_chunk:0x420,0x420,0x410,0x400,0x400
他们都属于同一个 largebin 我们来看看它们在这个 bin 中的排布:
可以看到图中有蓝色红色两种线。
红色
就是我们 small_bin 中的双向链表指针,不必多说。
蓝色
是 largebin 中引入的一种新指针,它负责把不同 size 的 堆头
(如果有两个相同 size 的 chunk,那么先进入 large_bin 的作为堆头
,其他的 chunk 都只能接在其后
)。所有堆头通过 bk_nextsize
和 fd_nextsize
连接在一起,能够缩短寻找 chunk 的时间。
用结构体表示大概长这样:
struct large_chunk{
size_t prev_size;
size_t size;
(void*) fd;
(void*) bk;
(void*) fd_nextsize;
(void*) bk_nextsize;
}
unlink
https://mrh1s.top/archives/619#toc-head-9
unlink 有对于 fd、bk、fd_nextsize、bk_nextsize 的检测。当然,如果 large_chunk 不是堆头(即 fd_nextsize == bk_nextsize),则不会检测后两项。
malloc
https://mrh1s.top/archives/619#toc-head-14
首先会去 large_bin 中进行搜寻合适大小的 large_chunk,若没有合适目标,便会去 unsorted bin 进行寻找,最后会直接从 top_chunk 切割。
free
https://mrh1s.top/archives/619#toc-head-25
和 smallbin 的操作相同,会将 chunk 直接放入 unsorted bin,后续再放入各 large_bin 中,这个操作用到了 unlink 宏。
chunk 放入 large_bin 的方式如下:
- 如果堆头(相同 size 的 chunk 的头部)不存在,那么就作为堆头;
- 如果堆头存在,那么始终将 chunk 放在
堆头之后
,即FILO
原则。
attack
malloc fake_large_chunk
这个方法与 smallbin 进行 unlink 从而控制堆块之外的空间有异曲同工之妙。
首先我们申请一定的空间(大小合适即可,要求不高),在其中伪造 fake_chunk。
fd_nextsize
和 bk_nextsize
直接置零,这样可以避免 unlink 的 check。
然后,malloc
并 free
掉一个 large_chunk,这个 large_chunk 的大小应该大于刚刚伪造的 fake_chunk,记为 real_chunk
。
用某种方法触发 unsorted bin 的 chunk 回收机制
,使 large_chunk 掉入相应的 bin
接下来利用 UAF
漏洞修改 real_chunk->bk_nextsize
为 fake_chunk_addr
malloc(fake_chunk->size-0x10)
即可申请到该 fake_chunk
largebin attack
与 unsorted bin attack 类似,通过伪造指针,可以修改任意地址为当前堆块。
以下源码是 _int_malloc 执行时,将 large_chunk
放入 largebin
的部分,victim 被放入了两个双向链表中。
...//将largebin从unsorted bin中取下
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);
...
//否则这个chunk将会成为堆头,<code>bk_nextsize</code>和<code>fd_nextsize</code>将被置位
victim->fd_nextsize = fwd;
victim->bk_nextsize = fwd->bk_nextsize; //由于fwd->bk_nextsize可控,因此victim->bk_nextsize可控
fwd->bk_nextsize = victim;
victim->bk_nextsize->fd_nextsize = victim; //victim->bk_nextsize可控,因此实现了往任意地址写victim的能力
}
bck = fwd->bk; //由于fwd->bk可控,因此bck可控
...
mark_bin (av, victim_index);
//设置fd与bk完成插入
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;
bck->fd = victim; //bck可控,因此实现了往任意地址写victim的能力
...
}
注意以下两个语句,victim->bk_nextsize
全取自 fwd->bk_nextsize
,且未作任何检查,那么将 fwd->bk_nextsize
修改为 &target - 0x20
,就可以在 target 处写 victim 的地址
victim->bk_nextsize = fwd->bk_nextsize;
victim->bk_nextsize->fd_nextsize = victim;
同样,后面的链表也未进行检验操作,同样将 fwd->bk
修改为 &target - 0x10
,便可以在 target 处写 victim 的地址
victim->bk = bck;
bck->fd = victim;
Comments | NOTHING