极简,但是能快速上手
slub算法
这篇文章简洁直观,推荐
linux 内核 内存管理 slub算法 (一) 原理
感受slub堆漏洞
需要下载 https://github.com/De4dCr0w/green-dill ,使用其中的测试程序做实验
UAF
如果看完上面链接中有关slub中对象分配的方式,那上面这张图就可以这么看
- 从左到右是分配一个对象A
- 从右到左是释放一个对象A
在简化的情况下,可以把SLAB理解为glibc中的fastbin
- slub分配对象 <=> 从fastbin中取走一个bin
- slub释放对象 <=> 将bin放入fastbin中
当在kmalloc-XX中存在一个UAF对象时,由于SLUB对象的分配/释放类似于fastbin,那么只要在该UAF对象释放后,立即申请相同kmalloc-XX中的对象,便能持有该UAF对象
如下是green-dill中的测试程序,虽然不是UAF程序,但是可以通过简单的申请-释放-再申请来模拟一下
分配kmalloc-1024对象前
/ $ ./slub
1.malloc slub
2.free slub
3.show slub
4.edit slub
5.exit
>>
pwndbg> kcache kmalloc-1k
start: 0xffffffff8245d160 <slab_caches_to_rcu_destroy_work>
cpu #0 > 0xffff88801ee00000 | 0xffff88801ee23c40
<kmalloc-1k>:
kmem_cache : 0xffff88801e801500
oo : 131088
objects_count : 16
pages_count : 4
offset : 0
min_partial : 5
cpu_partial : 6
cache_cpu freelist:
->0xffff88801e215400 <<======================================
->0xffff88801e215800
->0xffff88801e215c00
->0xffff88801e216000
->0xffff88801e216400
->0xffff88801e216800
->0xffff88801e216c00
->0xffff88801e217000
->0xffff88801e217400
->0xffff88801e217800
->0xffff88801e217c00
->0x0 (freelist)
cache_cpu partial page -> 0x0
first cache_node addr : 0xffff88801e800d80
cache_node['partial']['next']: 0xffff88801e800d90
cache_node partial page -> 0x0
cache_node full page -> 0x0
分配kmalloc-1024对象后
/ $ ./slub
1.malloc slub
2.free slub
3.show slub
4.edit slub
5.exit
>> 1
size: 1000
kmalloc addr : 0xffff88801e215400 <<======================================
pwndbg> kcache kmalloc-1k
start: 0xffffffff8245d160 <slab_caches_to_rcu_destroy_work>
cpu #0 > 0xffff88801ee00000 | 0xffff88801ee23c40
<kmalloc-1k>:
kmem_cache : 0xffff88801e801500
oo : 131088
objects_count : 16
pages_count : 4
offset : 0
min_partial : 5
cpu_partial : 6
cache_cpu freelist:
->0xffff88801e215800
->0xffff88801e215c00
->0xffff88801e216000
->0xffff88801e216400
->0xffff88801e216800
->0xffff88801e216c00
->0xffff88801e217000
->0xffff88801e217400
->0xffff88801e217800
->0xffff88801e217c00
->0x0 (freelist)
cache_cpu partial page -> 0x0
first cache_node addr : 0xffff88801e800d80
cache_node['partial']['next']: 0xffff88801e800d90
cache_node partial page -> 0x0
cache_node full page -> 0x0
释放kmalloc-1024对象后
1.malloc slub
2.free slub
3.show slub
4.edit slub
5.exit
>> 2
delete index: 0
pwndbg> kcache kmalloc-1k
start: 0xffffffff8245d160 <slab_caches_to_rcu_destroy_work>
cpu #0 > 0xffff88801ee00000 | 0xffff88801ee23c40
<kmalloc-1k>:
kmem_cache : 0xffff88801e801500
oo : 131088
objects_count : 16
pages_count : 4
offset : 0
min_partial : 5
cpu_partial : 6
cache_cpu freelist:
->0xffff88801e215400 <<======================================
->0xffff88801e215800
->0xffff88801e215c00
->0xffff88801e216000
->0xffff88801e216400
->0xffff88801e216800
->0xffff88801e216c00
->0xffff88801e217000
->0xffff88801e217400
->0xffff88801e217800
->0xffff88801e217c00
->0x0 (freelist)
cache_cpu partial page -> 0x0
first cache_node addr : 0xffff88801e800d80
cache_node['partial']['next']: 0xffff88801e800d90
cache_node partial page -> 0x0
cache_node full page -> 0x0
再次分配kmalloc-1024对象
1.malloc slub
2.free slub
3.show slub
4.edit slub
5.exit
>> 1
size: 1000
kmalloc addr : 0xffff88801e215400 <<======================================
pwndbg> kcache kmalloc-1k
start: 0xffffffff8245d160 <slab_caches_to_rcu_destroy_work>
cpu #0 > 0xffff88801ee00000 | 0xffff88801ee23c40
<kmalloc-1k>:
kmem_cache : 0xffff88801e801500
oo : 131088
objects_count : 16
pages_count : 4
offset : 0
min_partial : 5
cpu_partial : 6
cache_cpu freelist:
->0xffff88801e215800
->0xffff88801e215c00
->0xffff88801e216000
->0xffff88801e216400
->0xffff88801e216800
->0xffff88801e216c00
->0xffff88801e217000
->0xffff88801e217400
->0xffff88801e217800
->0xffff88801e217c00
->0x0 (freelist)
cache_cpu partial page -> 0x0
first cache_node addr : 0xffff88801e800d80
cache_node['partial']['next']: 0xffff88801e800d90
cache_node partial page -> 0x0
cache_node full page -> 0x0
堆溢出 && 堆喷
在kmalloc-XX不停的申请/释放后,slab有可能是如上结构(也可能不是,反正就是不确定),空闲object对象和已分配的object对象可能是交替排布的。
有很大可能存在这样的场景:
- 某个存在堆溢出的object对象X(上溢,下溢)被分配,被分配到slab page A的空闲对象中
- 而想要通过堆喷提权的object对象Y被分配到slab page B的空闲对象中
如果object对象X是下溢
- 攻击者没有办法判断object对象Y是否分配到了object对象X往后的地址中
- 也没有办法判断object对象X和对象Y之间间隔了多少对象
这样堆溢出就很难利用。
因此需要通过堆喷(就是分配多个kmalloc-XX对象),先将这些间隔空闲对象和已分配对象的slab page消耗掉,使slab中的布局形成如下结构
或如下结构
这样,在分配堆溢出的对象和用户控制堆喷对象时,就有可能在很大概率上相邻,从而提高漏洞利用效率。