house of lore
1. 核心原理:Small Bin 的分配机制
在 glibc 内存管理中,Small Bin 是一个双向链表,遵循 FIFO(先进先出) 机制。
当程序请求一个 Small Bin 大小的内存时,malloc 会从链表的尾部(bk 指针指向的方向)摘出一个 chunk 分配给用户。
正常的 Small Bin 链表结构和卸载(Unlink)过程如下:
最后一个空闲 chunk 称为
victim。bck = victim->bk(获取victim的前一个 chunk)。安全检查:
if (__glibc_unlikely(bck->fd != victim))- 这句话的意思是:
victim的前一个 chunk 的fd指针,必须指回victim自己。
- 这句话的意思是:
检查通过后,执行卸载:
bin->bk = bck; bck->fd = bin;
2. 战术布局:如何绕过 bck->fd != victim 检查?
正如你提供的代码片段,House of Lore 的精髓就在于如何在攻击目标的内存处(如你的 buf1)伪造两个假的 chunk(Fake Chunk),来完美欺骗这个 if 检查。
假设你想控制的目标地址是 Fake_Chunk1(即你提到的 buf1),你需要提前在内存中布置好两个伪造的结构体:
伪造链表布局
**Fake_Chunk1 (
buf1)**:它的bk指针必须指向另一个你可以控制的干净内存 **Fake_Chunk2**。Fake_Chunk2:它的
fd指针必须**指回Fake_Chunk1**。
攻击发生时的篡改
当你通过漏洞(例如 Heap Overflow 或 Use-After-Free)篡改了已经在 Small Bin 中的真实 chunk(victim)的 bk 指针,将其修改为指向 Fake_Chunk1 时,链表变成了这样:
Small Bin 头部 $\leftrightarrow$ victim $\rightarrow$ Fake_Chunk1 $\rightarrow$ Fake_Chunk2
绕过检查的数学逻辑
当 victim 被申请走后,下一次分配的目标将变成 Fake_Chunk1。此时:
victim变成了当前的Fake_Chunk1。触发代码
bck = victim->bk;$\rightarrow$ 此时bck实际指向 **Fake_Chunk2**。触发安全检查:
if (bck->fd != victim)$\rightarrow$ 即检查Fake_Chunk2->fd != Fake_Chunk1。因为我们提前在
Fake_Chunk2->fd写入了Fake_Chunk1的地址,条件不成立(相等),完美绕过检查!


