最近了解到苹果系统库已经更新为 arm64e 架构了,主要是为了其安全性的考虑,本文来简单了解下这块内容。

1、gadgets

一般情况下,攻击者想要运行一些自定义的代码,是没法在系统中直接注入新的指令的(现在大多数系统的可执行文件都是代码段和数据段分离,代码段可读可执行,而数据段可读可写,所以攻击者无法直接编写可写可执行权限的攻击代码),而他们会去寻找 gadgets(指在那些已有的函数中,攻击者所需要收集的代码/指令片段,通常是以函数返回 ret 结尾的片段)。

这种攻击可以在不破坏程序控制流完整性的情况下,影响程序行为,可能会导致程序泄露敏感数据或攻击者提权。

1.1、ROP/JOP

在这类攻击当中,攻击者利用内存损坏漏洞(memory corruption) 把执行流转移到 gadgets(重定向间接跳转、redirect indirect branches),然后需要按照特定的顺序去执行这些 gadgets。

有两种分类:

  • ROP(return-oriented programming)。重定向 returns。
  • JOP(jump-oriented programming)。重定向 calls。

ARM 处理器使用 LR(链接寄存器) 来存储返回地址,通常是在进行分支函数调用(bl 指令) 时设置的。攻击者无法直接修改 LR 的值,但在嵌套的函数调用需要先把之前的函数调用的返回地址存放在栈上,然后更新新的函数调用的返回地址到 LR。在栈上,攻击者就有机会利用内存错误如栈溢出等,对返回地址进行修改,重定向到目标 gadgets。

1.2、ROP 简单案例

实际上,完成一次 ROP 攻击并没有那么简单,不过本文只采用最简单的案例来说明 ROP 的操作,先不考虑 ASLR(地址空间布局随机化,即每次启动把程序加载在不同的起始内存地址)、栈越界检测等保护。

这个简单的案例,并没有任何对输入的检查,所以我们可以直接写入很长的字符串溢出到栈区。

把我们所需要执行的 gadgets 地址写到栈上,就可以如我们所愿,控制执行流了。

2、PA(Pointer Authentication)

ARM 在 armv8.3-A(AArch64 extension) 规范中引入了 PA(Pointer Authentication、指针验签),作为 CPU 级别的举措,实现了安全保证。苹果在 arm64e 上实现了该功能,从官方定义来看,arm64e 是实现了 armv8.3 的 PA 功能的 ABI(application binary interface、应用二进制接口)。

软件防御的性能开销较大,而硬件辅助防御可以显著提高攻击检测的效率。

PA 使用指针的高位来存储 PAC(Pointer Authentication Code) 信息,该信息本质上是用指针值和一些上下文进行的加密签名。使用 PA 的可行性,在于尽管指针是 64 位的,但大多数系统用到的虚拟地址空间要小得多,导致指针中有很多未被使用的高位,那么我们可以用来存储 PAC 信息。

下面配图使用的是 LR 寄存器指针来进行说明,但实际上对于用于间接跳转的函数指针等都可以用上 PA 功能。

要实现该功能,是在 CPU 级别上,引入了多组特殊指令来对指针进行 PAC 的添加和验证,以及还原回原始指针,这样就防止了攻击者篡改指针的操作。比如下图对 LR 寄存器进行签名,然后在要离开函数时,再次验证 LR 寄存器是否能对应上,如果对应不上就会抛出错误。

1
2
3
4
5
6
...
       |-- 'PAC auth failed'
       v
pc:  0x8000000000400b04
lr:  0x0000000000400b04
...

程序中的指针可能由编译器初始化,但指针验签的 PAC 值只能在运行时设置,要基于指针值和当前上下文并加盐值来生成 PAC 信息。

2.1、PAC Forgery

PAC 密钥存储在特殊的硬件寄存器中,并且这些寄存器无法从用户模式访问。因此,内存泄漏漏洞无助于提取用于 PAC 生成的密钥。

虽然确实如此,但此描述专门适用于攻击用户空间程序,而不是攻击内核本身。具有内核内存访问读/写权限的攻击者可能会读取密钥并使用它们手动计算任意指针的身份验证代码。

绕过 PAC 的最简单方法就是伪造 PAC 指针,如果攻击者可以强制目标应用创建他们选择的新指针,则可以使用这些恶意指针来代替现有的好指针。一种可能的方法是通过在用户空间中执行相应的 PAC* 指令来为内核指针伪造 PAC。

这里有篇长文,描述了如何针对苹果 PA 进行绕过,但苹果很容易就能够修复这些漏洞:Examining Pointer Authentication on the iPhone XS

总的来说,PA 机制使得内存漏洞利用更加困难或者无效化,是非常有帮助的利器。

参考