Pointer Redirecting

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

String pointers

如果一个函数调用将使用位于 stack 上的字符串地址,就可以利用 buffer overflow 覆盖该地址,并放入二进制中一个指向不同字符串的地址

例如,如果某次对 system 的调用将使用一个字符串地址来执行命令,攻击者可以在栈中放入一个指向另一个字符串的地址,比如 export PATH=.:$PATH,并在当前目录创建一个名字为该新字符串首字母的脚本,二进制在调用时就会执行它。

在真实目标中,相比仅仅改变打印文本,repointing a stack string pointer 通常更有价值:

  • 将后续的 system/popen/execl* 参数重定向到内存中已存在的 "/bin/sh" 或攻击者可控的命令字符串。
  • 将后续的 read sink(例如 puts("%s", ptr)write(fd, ptr, len))重定向以 leak stack、heap 或 binary 数据。
  • 将后续的 write sink(例如 strcpy(dst, ...)memcpy(dst, src, len),或通过 ptr->field = value 的结构字段赋值)重定向,从而将栈溢出升级为 second-stage arbitrary write

审计时优先关注那些在 overflow 之后但在函数返回之前被使用的栈局部变量,例如 char *cmdchar *pathchar *bufFILE *fp,或临时请求/响应结构体内部的指针。这在不能安全覆盖返回地址(因为 canary)或仅需破坏附近指针就足够时尤其有用。

如果破坏仅限于 partial overwrite(例如因为 bug 在结尾追加了 0x00),尝试将指针重定向到:

  • 同一栈帧中的附近字符串
  • 同一模块 / non-PIE 镜像中的另一个对象
  • 一个其高位字节保持不变的可控区域

对于那种尾部 NUL 修改了现有 stack 指针而不是专用局部变量的与 ASLR 相关的情况,请查看 Ret2ret & Reo2pop

你可以在以下示例中看到一个实现:

Function pointers

与 string pointer 类似,但作用于函数;如果 stack 包含将被调用的函数地址,就可以修改它(例如指向 system)。

有用的目标不仅限于显式的回调变量如 void (*fp)()。在实践中,请寻找:

  • 存储在局部 struct 中并稍后传给 helper 函数的 callbacks
  • 在错误路径上调用的 destructor / cleanup handlers
  • 解析器调度表或 state-machine handlers,被复制到栈上
  • 稍后通过间接调用分发的局部 struct / object

在现代利用中,pointer redirection is often the last primitive available before touching the canary。一个关于 CVE-2024-20017(2024 年)的利用 writeup 展示了典型模式:溢出到达了位于栈 canary 之前的多个局部变量,攻击者破坏了一个 stack pointer 及其相关的 length/value,随后通过该指针的赋值变成了一个 arbitrary write,而无需通过被破坏的栈帧返回。

Pointer corruption to second-stage primitives

如果附近的指针随后被解引用用于存储(store),目标通常不是用第一次溢出直接跳转,而是升级原始能力

  1. 溢出局部缓冲区并破坏一个 pointer 以及任何相关的 length / integer / index
  2. 等待函数执行一次溢出后的解引用操作,例如 ptr->len = xmemcpy(ptr, src, n)*ptr = value
  3. 使用由此得到的 write-what-where 覆盖 GOT 槽、回调、配置指针或另一个间接调用点。

当以下情况时这是一种好选择:

  • bug 在 canary 处停止
  • 函数指针本身无法直接到达
  • 比起立即劫持控制流,更容易获得 4-byte 或 8-byte 的 data write

如果被破坏的指针随后被传给日志、打印或网络发送 helper,类似的思路也适用于 read primitives。

Modern AArch64 note: PAC / BTI

在当前 AArch64 目标上,经典的 saved return address overwrite 可能会失败,因为 epilogue 使用 PAC 对 x30 进行认证。在这些情况下,像被破坏的局部函数指针或回调指针这样的非返回劫持变得更有吸引力。

然而,如果启用了 BTI,被覆盖的间接调用目标仍然必须落在一个有效的 landing pad(通常是以 bti c 开头的函数入口,或者在启用 PAC 的代码中以 paciasp/pacibsp 开头的函数序言)。因此,在 AArch64 上重定向栈上的函数指针时,优先考虑:

  • 真实的函数入口,而不是函数中间的 gadget
  • 其序言已经满足 BTI 的目标
  • 在使用前间接调用指针不会被额外认证的目标

关于 AArch64 相关的 stack-overflow 上下文,请查看 ret2win-arm64

你可以在以下示例中看到一个实现:

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