House of Corrosion
攻击原理
fastbin的管理数组 fastbinsY 如下
当我们通过类似large bin attack或者unsorted bin attack等攻击手段将globa_max_fast改为0x7f的libc地址时,这时理论上很大size的堆块被释放时都会被放入到fast bin当中去,而fastbin的堆块被放入时,会计算其下标,这时候就会出现数组越界;所以只要我们计算好我们的size,就能通过释放非正常fast chunk去覆盖我们想要覆盖的位置。
然后 我们可以使用以下公式来计算出目标溢出位置,对应的需要构造的堆块 SIZE,其中的 delta 指的是溢出位置到 fastbinsY 首地址的差值。
1 | chunk size = (delta * 2) + 0x20 |
参考wjh师傅的文章,有两种利用手段
malloc
利用思路
- 首先改写global_max_fast为大值
- 然后释放一个size可以溢出到我们想要的位置
- 然后利用UAF漏洞,改写第二步被我们释放的堆块的fd指针为我们想要的地址
- malloc,size同第二步释放的堆块一致
这里的可以利用的原因是:在 malloc 的时候会把 fastbinsY 的链表头部取出,并且把其 fd 位置的内容作为链表头部写入到 fastbinsY 数组中,而在这个过程中没有对可控堆块的 fd 位置的内容的合法性做检查
free
这个没看懂,先放放
写(这里直接复制粘贴wjh师傅的博客)
感觉这个才是主要用的
写的思路与泄露的类似,就是利用在 free 后此 SIZE 的链表头部指针会变成被 free 的堆块指针。利用这个思路可以在 fastbinsY 之后写入堆块指针。
这个思路只能写入可控的堆块指针,而不是可控内容,但是相对于之前的方法,这个方法不要求主程序可以申请很大 SIZE 的堆块。
写入位置的选择就很多样了,只需要抓住一点,我们可以写入一个可控的堆块指针。而使用 Unsorted Bin Attack 或 Tcache Stashing Unlink Attack 能够写入的内容都是在 LIBC 上,属于不可控的位置,通过这个打 global_max_fast 的思路,就可以把不可控地址的写入转换为可控地址的写入,这给我们提供一种利用思想。
- 在程序中有通过 exit 来退出循环,在这种情况下,我们就可以通过写 _IO_list_all 再配合不同版本 GLIBC 在 IO File 的攻击思想或考虑用 House of banana,最后 get shell。
- 2.23 版本:对 vtable 的位置没有检测,可以直接在任意可控位置伪造一个 vtable,具体的利用思路可以参考 Angel Boy 的 House of orange 的打法。
- 2.27 版本:在 _IO_str_finsih 和 _IO_str_overflow 中有对函数指针的直接调用,可以通过调试找到对应位置并修改为 system。
- 2.28 - 2.33 版本:这部分版本把函数指针的调用改为了直接的 malloc 和 free 调用,这使得构造指针的思路不再有效,可以考虑用 House of pig 中的打法。
- 2.34 版本:这个版本把 __free_hook 和 __malloc_hook 都删除了,所以使得 house of pig 的打法也失效了,可以考虑使用 House OF Emma 来攻击。
覆写 Top Chunk 标志来触发 House OF Kiwi,House OF Kiwi 的利用条件有一部分在于触发在 assert 上,使用这个方法能够快速的让 Top Chunk 的 Size 变的 “不合法”,再次申请大于写入堆块的 Size 的堆块就能触发 assert。这里触发malloc_assert还可以通过large bin
结合 House of banana 来攻击
结合 House of husk 来攻击
在程序中没有 Show 函数,并且无法使用任意申请来打 stdout,可以考虑使用本方法来打 stdout,并且同时设置_flags、_IO_write_base、_IO_write_ptr、_IO_write_end 这四个位置写堆地址。
其中最需要注意的就是 _flags 的内容,由于写入的堆块地址可控的只有末三位,但是如果要通过 stdout 来 leak,需要在_flags 要求满足以下三个条件,其中条件 1 和 2 都可以通过构造来解决,而条件 3 只能通过堆地址的随机化来碰撞。
1
2
3_flags & _IO_MAGIC(0xFBAD0000) != 0
_flags & _IO_CURRENTLY_PUTTING(0x800) != 0
_flags & _IO_IS_APPENDING(0x1000) != 0在满足了_flags 的条件后,然后再调用能用到 IO 的函数,就可以泄露堆块上 _IO_write_base 至 _IO_write_ptr 这一段,所以至少需要两个不同位置的堆块来构成溢出,这部分区间的内容上如果恰好有 libc 地址则即可实现泄露 libc。
本方法的可行性主要在于这几个需要覆盖的地址都在 fastbinsY 之后,而且我们溢出过程中需要计算 SIZE 的关键变量是两个 libc 地址的差值 delta,在这个求差的过程中就把 libc 地址的随机化给抵消了,使得我们无需 leak 也可以做到写入多个地址。
这个攻击的思路目前应该还没有师傅提出过,这里的堆地址随机化爆破概率乘上利用部分覆盖爆破打 global_max_fast 的概率,应该是 1 / 32,实用性很强。
例题:VNCTF2022-HideOnHeap
1 | # encoding: utf-8 |
题目本身白给了double free,同时可以构造出UAF,主要就是没有IO函数,无法通过stdout来泄露。
- 本文标题:House of Corrosion
- 本文作者:LOLOLO
- 创建时间:2022-03-15 17:00:39
- 本文链接:https://lololo-pwn.github.io/2022/03/15/House-of-Corrosion/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!