资源加载器中的不安全重定位修正

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

为什么资源重定位很重要

许多传统游戏引擎(Granny 3D、Gamebryo 等)通过以下方式加载复杂资源:

  1. 解析头部和节表。
  2. 为每个节分配一个堆缓冲区。
  3. 构建一个 SectionArray 来存储每个节的基指针。
  4. 应用重定位表,以便节数据中嵌入的指针被修补到正确的目标节和偏移量。

当重定位处理程序盲目信任由攻击者控制的元数据时,每个重定位都可能变成任意读/写原语。在 Anno 1404: Venice 中,granny2.dll 提供了以下辅助函数:

`GrannyGRNFixUp_0` (已删减) ```c int *__cdecl GrannyGRNFixUp_0(DWORD RelocationCount, Relocation *PointerFixupArray, int *SectionArray, char *destination) { while (RelocationCount--) { int target_base = SectionArray[PointerFixupArray->SectionNumber]; // unchecked index int *patch_site = (int *)(destination + PointerFixupArray->SectionOffset); // unchecked offset *patch_site = target_base ; if (target_base) *patch_site = target_base + PointerFixupArray->Offset; ++PointerFixupArray; } return SectionArray; } ```

SectionNumber 从不进行范围检查,SectionOffset 也不会针对当前节大小进行验证。构造带有负偏移或超大索引的重定位项可以让你走出你控制的节,并覆盖分配器元数据,例如节指针数组本身。

Stage 1 – Writing backwards into loader metadata

目标是让 section 0 的重定位表覆盖 SectionContentArray 的条目(它镜像 SectionArray,并存放在第一个节缓冲区之前)。由于 Granny 的自定义分配器在前端添加了 0x1F 字节,而 NT heap 又添加了 0x10 字节的头与对齐,攻击者可以预先计算第一个节(destination)起始位置到节指针数组的距离。

在测试的构建中,让加载器分配一个大小恰好为 0x4000 字节GrannyFile 结构,会使节指针数组落在第一个节缓冲区之前。解决

0x20 (header) + 0x20 (section descriptors)
+ n * 1 (section types) + n * 1 (flags)
+ n * 4 (pointer table) = 0x4000

产生 n = 2720 个 section。一个具有 SectionOffset = -0x3FF00x4000 - 0x20 - 0x20 + 0x30)的重定位条目现在解析为 SectionContentArray[1],尽管目标 section 认为它是在修补内部指针。

Stage 2 – Deterministic heap layout on Windows 10

Windows 10 NT Heap 会将大小 ≤ RtlpLargestLfhBlock (0x4000) 的分配路由到随机化的 LFH,而更大的分配则由确定性的后端分配器处理。通过将 GrannyFile 元数据略微提高到该阈值之上(使用 2720 sections 的技巧)并预加载多个恶意 .gr2 资源,你可以做到:

  • Allocation #1(元数据 + section 指针数组)落入一个 >0x4000 的后端 chunk。
  • Allocation #2(section 0 内容)紧接在 allocation #1 之后。
  • Allocation #3(section 1 内容)紧接在 allocation #2 之后,为后续重定位提供可预测的目标。

Process Monitor 证实资源是按需流式加载的,所以反复请求精心制作的单位/建筑就足以在不触及可执行镜像的情况下“预热”堆布局。

Stage 3 – Converting the primitive into RCE

  1. Corrupt SectionContentArray[1]. Section 0 的重定位表使用 -0x3FF0 偏移覆盖它。将其指向任何你可控的可写区域(例如,后面的 section 数据)。
  2. Recycle the corrupted pointer. Section 1 的重定位表现在将 SectionNumber = 1 视为你注入的指针。处理程序会将 SectionArray[1] + Offset 写入 destination + SectionOffset,这为每个重定位条目提供了任意的 4 字节写入。
  3. Hit reliable dispatchers. 在 Anno 1404 中,目标选择是 granny2.dll 的 allocator 回调(无 ASLR,DEP 被禁用)。覆盖 granny2.dll 在下一次 Malloc/Free 调用中使用的函数指针会立即将执行跳转到从被特洛伊化的资源加载的受控代码。

因为 granny2.dll 和注入的 .gr2 缓冲区在 ASLR/DEP 被禁用时都驻留在稳定地址,攻击就简化为构建一个小的 ROP 链或原始 shellcode 并将回调指向它。

Practical checklist

  • 查找维护 SectionArray / 重定位表的资源加载器。
  • 对比重定位处理程序,寻找对索引/偏移缺乏边界检查的情况。
  • 测量游戏的分配器封装和底层 OS heap 添加的分配器头以精确计算向后偏移。
  • 强制确定性放置的方法:
    • 通过膨胀元数据(许多空 section)直到分配大小 > RtlpLargestLfhBlock
    • 反复加载恶意资源以填充后端空洞。
  • 使用两阶段重定位表(第一阶段重新定向 SectionArray,第二阶段喷写写入)并覆盖将在正常渲染期间触发的函数指针(allocator 回调、虚表、动画分发器等)。

一旦你获得任意文件写入(例如通过多人保存传输中的路径遍历),用精心制作的 .gr2 重新打包 RDA 归档可以为你提供一个干净的投递向量,远程客户端会自动解压缩它。

References

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks