8.6 KiB
未排序 Bin 攻击
{% hint style="success" %}
学习并练习 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE)
学习并练习 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 电报群组 或 关注 我们的 Twitter 🐦 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR 来分享黑客技巧。
基本信息
有关未排序 bin 的详细信息,请查看此页面:
{% content-ref url="bins-and-memory-allocations.md" %} bins-and-memory-allocations.md {% endcontent-ref %}
未排序列表能够将地址写入到块的 bk
地址中的 unsorted_chunks (av)
。因此,如果攻击者能够修改未排序 bin 中块内的 bk
指针的地址,那么他就能够将该地址写入到任意地址,这有助于泄漏 Glibc 地址或绕过某些防御措施。
因此,基本上,这种攻击允许在任意地址设置一个大数。这个大数是一个地址,可以是堆地址或 Glibc 地址。一个典型的目标是**global_max_fast
**,以允许创建更大尺寸的快速 bin 块(从未排序 bin 攻击转变为快速 bin 攻击)。
{% hint style="success" %}
查看提供的示例 https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle,并使用 0x4000 和 0x5000 而不是 0x400 和 0x500 作为块大小(以避免 Tcache),可以看到现在触发了错误**malloc(): unsorted double linked list corrupted
**。
因此,这种未排序 bin 攻击现在(除其他检查外)还需要能够修复双重链接列表,以便绕过 victim->bk->fd == victim
或不是 victim->fd == av (arena)
,这意味着我们要写入的地址必须在其 fd
位置具有伪造块的地址,并且伪造块的 fd
指向 arena。
{% endhint %}
{% hint style="danger" %} 请注意,此攻击会破坏未排序 bin(因此也会破坏小块和大块)。因此,我们现在只能使用快速 bin 中的分配(更复杂的程序可能会进行其他分配并崩溃),要触发此攻击,我们必须分配相同大小的块,否则程序将崩溃。
请注意,覆盖 global_max_fast
可能有助于在这种情况下,相信快速 bin 将能够处理直到完成利用的所有其他分配。
{% endhint %}
来自 guyinatuxedo 的代码很好地解释了这一点,尽管如果您修改 malloc 分配的内存大小足够大,以避免 Tcache,您会发现先前提到的错误出现,阻止了这种技术:malloc(): unsorted double linked list corrupted
未排序 Bin 信息泄漏攻击
这实际上是一个非常基本的概念。未排序 bin 中的块将具有指针。未排序 bin 中的第一个块实际上将使 fd
和 bk
链接指向主 arena 的一部分(Glibc)。
因此,如果您能够将一个块放入未排序 bin 中并读取它(使用后释放),或者再次分配它而不覆盖至少 1 个指针,然后读取它,您就可以获得Glibc 信息泄漏。
在这个写作中使用的攻击中,滥用了一个 4 个块结构(A、B、C 和 D - D 仅用于防止与顶部块合并),因此在 B 中使用了一个空字节溢出,使 C 指示 B 未使用。此外,在 B 中修改了 prev_size
数据,使得大小不再是 B 的大小,而是 A+B。
然后释放了 C,并与 A+B 合并(但 B 仍在使用)。分配了一个大小为 A 的新块,然后将泄漏的 libc 地址写入 B,从中泄漏出去。
参考资料和其他示例
- https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap
- 目标是用大于 4869 的值覆盖全局变量,以便获取标志并且未启用 PIE。
- 可以生成任意大小的块,并且存在所需大小的堆溢出。
- 攻击开始创建 3 个块:chunk0 用于滥用溢出,chunk1 用于溢出,chunk2 用于防止顶部块合并前两个。
- 然后,释放了 chunk1,并且 chunk0 被溢出,使得 chunk1 的
bk
指针指向:bk = magic - 0x10
- 然后,分配了一个与 chunk1 大小相同的 chunk3,这将触发未排序 bin 攻击,并修改全局变量的值,从而可能获取标志。
- https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html
- 合并函数存在漏洞,因为如果传递的两个索引相同,它将对其进行重新分配,然后释放它,但返回一个可以使用的已释放区域的指针。
- 因此,创建了 2 个块:chunk0 将与自身合并,chunk1 用于防止与顶部块合并。然后,两次调用合并函数与 chunk0,这将导致使用后释放。
- 然后,调用
view
函数,索引为 2(使用后释放块的索引),这将泄漏一个 libc 地址。 - 由于二进制文件只允许 malloc 大于
global_max_fast
的大小,因此不会使用 fastbin,将使用未排序 bin 攻击来覆盖全局变量global_max_fast
。 - 然后,可以使用索引 2(使用后释放指针)调用编辑函数,并将
bk
指针覆盖为指向p64(global_max_fast-0x10)
。然后,创建一个新块将使用先前受损的释放地址(0x20)将触发未排序 bin 攻击,覆盖global_max_fast
为一个非常大的值,现在可以在快速 bin 中创建块。 - 现在执行快速 bin 攻击:
- 首先发现可以在
__free_hook
位置使用大小为 200 的快速 块: -
gef➤ p &__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
</strong>0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
* 如果我们成功在这个位置获得一个大小为0x200的快速块,就可以覆盖一个将被执行的函数指针
* 为此,创建一个大小为`0xfc`的新块,并使用该指针两次调用合并函数,这样我们就可以获得一个指向大小为`0xfc*2 = 0x1f8`的已释放块的指针。
* 然后,在这个块中调用编辑函数,修改这个快速块的**`fd`**地址,使其指向之前的**`__free_hook`**函数。
* 然后,创建一个大小为`0x1f8`的块,从快速块中检索之前无用的块,然后创建一个大小为`0x1f8`的块,以在**`__free_hook`**中获取一个快速块块,该块被覆盖为**`system`**函数的地址。
* 最后,释放一个包含字符串`/bin/sh\x00`的块,调用删除函数,触发指向带有`/bin/sh\x00`参数的`system`的**`__free_hook`**函数。
* **CTF** [**https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw19\_traveller/index.html**](https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw19\_traveller/index.html)
* 另一个滥用1字节溢出以合并未排序块并获取libc信息泄漏,然后执行快速块攻击以用单个地址覆盖malloc挂钩的示例
* [**Robot Factory. BlackHat MEA CTF 2022**](https://7rocky.github.io/en/ctf/other/blackhat-ctf/robot-factory/)
* 我们只能分配大于`0x100`的块大小。
* 使用未排序块攻击覆盖`global_max_fast`(由于ASLR,每16次有效,因为我们需要修改12位,但必须修改16位)。
* 快速块攻击以修改全局块数组。这提供了一个任意读/写原语,允许修改GOT并将某些函数指向`system`。