glibc-2.31版本利用
glibc-2.29~2.31
fastbin_double_free
需要构造:前一个释放堆块 old,与当前释放堆块 p 有 old != p。
fastbin double free
的 poc 利用如下:
1 |
|
申请出九个堆块。
释放掉七个堆块,填满 tcache bin。
再释放 p、q 两个堆块,由于 tcache bin 满了,进入到 fastbin 中
fastbin_double_free 利用总结
效果:实现任意地址写
- 释放七个堆块填满 tcache bin。
- 再释放两个堆块进入 fastbin,按照 p-q-p 的顺序释放,即可形成 double free。
tcache_double_free
poc如下:
1 |
|
2.29以后的版本,在释放堆块的 bk 位置将会填上 tcache 的地址作为一个 key,如果 key == tcache 则说明堆块已释放。
将这个key值改掉即可与之前版本一般,直接再次释放该堆块形成 double free。
tcache_double_free 利用总结
效果:实现任意地址写
- 释放一个堆块。
- 修改堆块 bk 位置上的 key。
- 再次释放该堆块。
tcache_poisoning
在 glibc-2.31 中,tcache count 的数量不能小于 0,否则将无法分配堆块。
poc如下:
1 |
|
申请出两个堆块,然后再将其释放,顺序为 b -> a。
修改 b 的 fd 指针指向要修改的内容,然后只需要将堆块分配即可。
tcache_poisoning 利用总结
效果:实现任意地址写
- 释放堆块 b -> a
- 修改 b 的指针指向想要分配堆块的地址
相比与之前版本可以让 count 为负值,构造链表尾部的堆块;glibc-2.31需要在前一个堆块开始构造,绕过 count 的限制,
tcache_stashing_unlink
libc-2.29开始,出现了一种叫 stash 的机制,基本原理就是当调用 _int_malloc 时,如果从 smallbin 或者 fastbin 中取出 chunk之后,对应大小的 tcache 没有满,就会把剩下的 bin 放入 tcache 中
poc如下:
1 |
|
目标地址0x555555558050,值为0。
释放六个大小为0x60的堆块进入 tcache bin 里面。
申请两个堆块,一个大于tcache[max],另一个防止合并。
释放大堆块进入到 unsorted bin 中,再申请一个计算好的堆块,让大堆块进行分割,剩下的大小与之前申请的堆块大小一致,再申请一个更大的堆块,让这个堆块进入到 small bin 中。
做一遍类似的操作,但是这次阻止合并堆块的大小要大于定好的堆块大小,防止 small chunk 进行分配。
一样的操作,再让一个堆块进入到同样size序列的 small bin 中。
修改后进入 small bin 的那个堆块的 bk 指针为 目标地址 - 0x10。
最后使用 calloc 申请一个同等 size 的堆块,即可在目标地址上写入一个大数。
tcache_stashing_unlink利用总结
效果:往任意地址里写入一个 0x7f 头的大数,unsorted bin attack 的替代手法。
- 选定一个 n = size,释放六个大小为 n 的堆块进入到 tcache bin
- 精心准备让一个堆块进入到 unsorted bin 中,同时使得这个堆块的 size 变为 n,再让其进入到 small bin 中。
- 再重复构造一个同样 size 为 n 的堆块进入 small bin 后,修改该堆块的 bk 指针为 目标地址-0x10
- 使用 calloc 申请一个 size 为 n 的堆块
注:被修改 bk 指针的堆块,fd 是不能被改变的,所以需要获取到堆地址
tcache_stashing_unlink+
poc如下:
1 |
|
目标地址为0x555555558060,值为0。
在 victim[1] 写入 victim 的地址。
释放五个size为0x60的堆块进入tcache bin中。
跟 tcache_stashing_unlink 中的一样的做法,让一个size也为0x60的堆块进入到small bin中。
再制造一个size为0x60的堆块进入到smallbin中。
把后进入smallbin的堆块bk修改为&victim-0x10,fd保持不变。
再使用calloc申请size为0x60的堆块,此时victim也将被放入到tcache中。
此时可以把victim申请出来,获得任意写的能力。
tcache_stashing_unlink+利用总结
将一个任意地址当做堆块放入到 tcache 中。
- 选定一个 n = size,释放五个大小为 n 的堆块进入到 tcache bin
- 精心准备让一个堆块进入到 unsorted bin 中,同时修改这个堆块的 size 变为 n,再让其进入到 small bin 中。
- 再重复构造一个同样 size 为 n 的堆块进入 small bin 后,修改该堆块的 bk 指针为 &target - 0x10
- 在 &target + 8 的位置要存放有任意一个可写的地址,满足检查。
- 使用 calloc 申请一个 size 为 n 的堆块
- 此时 target 将被放入 tcache 中。
注:被修改 bk 指针的堆块,fd 是不能被改变的,所以需要获取到堆地址。
tcache stash unlink attack++
这个方法与tcache_stashing_unlink+几乎相同。
poc如下:
1 |
|
该手法就是第一种和第二种的叠加手法,就不细说了,直接总结手法。
tcache_stashing_unlink++利用总结
将一个任意地址当做堆块放入到 tcache 中,同时可以往一个任意地址写入一个 libc 地址。
- 选定一个 n = size,释放五个大小为 n 的堆块进入到 tcache bin;
- 精心准备让一个堆块进入到 unsorted bin 中,同时使得这个堆块的 size 变为 n,再让其进入到 small bin 中;
- 再重复构造一个同样 size 为 n 的堆块进入 small bin 后,修改该堆块的 bk 指针为 &target1 - 0x10;
- 在 &target1 + 8 的位置填写 &target2 - 0x10;
- 使用 calloc 申请一个 size 为 n 的堆块;
- 此时 target1 将被放入 tcache 中,同时对 target2 写入一个 libc 地址。
注:被修改 bk 指针的堆块,fd 是不能被改变的,所以需要获取到堆地址。
house_of_botcake
poc:
1 |
|
释放 7 个 0x100 的堆块填满 tcache。
再释放两个同样为 0x100 的堆块,这两个堆块会进行合并。
申请一个 0x100 的堆块,空出一个 tcache bin。
然后利用 UAF 再次释放合并进入到 unsorted bin 的堆块,造成了存在一个堆块即在 tcache 里,又在 unsorted bin 里。这里的堆块不能选择释放头部,因为那样会变成让 0x220 的堆块进入到 tcache。
申请一个大于 0x100 的堆块,绕开 tcache,而获得到了 unsorted bin 里的堆块,但是这个堆块可以覆盖存在于 tcache 里的堆块,最终造成可以地址分配堆块,任意地址写。
house_of_botcake利用总结
前提:拥有 UAF
- 释放七个 size 满足进入 unsorted bin 的堆块填满 tcache,再释放两个同样 size 的堆块 a b (a前,b后)进入到 unsorted bin
- 申请回一个 tcache,然后利用 UAF 释放堆块 b
- 申请一个大于 size 的堆块,此时可以通过该堆块完成对 b 堆块的覆盖,并且 b 堆块仍然在 tcache 里。
- 本文作者:ShouCheng
- 本文链接:http://shoucheng3.github.io/2022/03/14/2022-03-14-glibc-2.31%E7%89%88%E6%9C%AC%E5%88%A9%E7%94%A8/index.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!