利用 ProxyCFI 掌控代码指针的力量
1. 常见软件漏洞情况
在当今的软件环境中,许多常用软件都存在着不同程度的安全漏洞,这些漏洞可能会被攻击者利用,从而导致严重的安全问题。以下是一些常见软件及其存在的漏洞:
-
MuPDF
:存在栈缓冲区溢出漏洞(CVE - 2014 - 2013),攻击者可以通过精心构造的 XPS 文档实现远程代码执行。在
xps_parse_color()
函数中,它会对用户通过 XPS 输入提供的数组执行未检查的
strcpy()
操作,将其复制到一个固定大小的缓冲区中。攻击者利用这个漏洞覆盖返回地址,然后跳转到 ROP 小工具。
-
bladeenc
:这是一个跨平台的 MP3 编码器,也可作为分布式 MP3 编码器/CDDB 服务器(如 abcde)的守护进程。它存在多个漏洞,可能导致 CFG 模仿攻击,这些攻击可以被远程利用(CVE - 2017 - 14648)。其命令行解析器使用未检查的
strcpy()
调用,将参数复制到一个 256 字节的缓冲区中。攻击者可以通过精心构造的命令行参数进行任意代码执行,通过破坏函数指针并跳转到合法目标集中的另一个函数来劫持控制流。
-
dnsmasq
:是一个为小型网络提供 DNS 服务的 DNS 转发器,包含在大多数 Linux 发行版中。2.78 之前的版本存在栈溢出漏洞(CVE - 2017 - 14493),远程攻击者可以发送精心构造的 DHCPv6 请求,从而劫持目标系统的控制流。在
dhcp6_maybe_relay()
函数中,对
memcpy()
的未检查使用导致了这个漏洞,攻击者可以利用该漏洞进行对象间溢出,以执行 ROP 攻击。
-
Gravity
:是一种用 C 语言编写的动态类型并发脚本语言。其运行时存在基于栈的缓冲区溢出漏洞(CVE - 2017 - 1000437),攻击者可以利用这个漏洞通过恶意的 Gravity 脚本覆盖返回地址,实现远程代码执行。在
operator_string_add()
函数中,可用于向固定大小的静态缓冲区末尾之后写入数据。
2. ProxyCFI 性能分析
为了评估 ProxyCFI 的性能,我们在配备 24 核和 32GB RAM 的 Intel Xeon Gold 6126 处理器上运行 Ubuntu 16.04 LTS Xenial Xerus 系统,并进行了 SPEC CPU 2006 基准性能分析实验。
-
性能开销
:对于计算密集型应用程序,简单实现的 ProxyCFI 会带来显著的性能开销,因为这些程序的平均雪橇深度较高。平均雪橇深度是指在进行直接分支之前,平均需要进行多少次指针代理测试。理想情况下,我们希望这个值接近 1,以降低 ProxyCFI 的性能开销。例如,对于大量使用函数调用的应用程序,如
perlbench
、
gobmk
和
sjeng
,未优化实现的性能下降更为明显,
perlbench
的平均返回雪橇深度为 27。
-
优化效果
:通过优化,平均雪橇深度和性能开销都会显著降低。例如,
perlbench
从基于配置文件的雪橇排序优化中受益匪浅。
h264ref
也因优化而显著受益,它大量使用通用函数指针,间接函数调用雪橇最多有 855 个条目,但只有两个是经常被调用的目标。
gcc
既大量使用函数调用(平均雪橇深度为 32),又使用通用函数指针(间接调用的平均雪橇深度为 26),函数克隆优化在
gcc
上的性能提升更为明显,因为其分支的概率分布下降得比其他应用程序慢。
-
网络应用性能
:对于面向网络的应用程序,由于其 I/O 绑定的性质,性能开销不明显。
redis - server
的平均性能开销为 0.25%,我们评估的所有面向网络的应用程序的平均开销为 0.93%。
| 应用程序 | 未优化性能开销(%) | 基于配置文件优化(%) | 基于配置文件和函数克隆优化(%) |
|---|---|---|---|
| perlbench | 65 | 57 | 44 |
| h264ref | 110 | - | 39 |
| 其他 | - | - | - |
以下是性能分析的流程 mermaid 图:
graph TD;
A[选择应用程序] --> B[运行未优化 ProxyCFI];
B --> C[记录性能开销];
C --> D[进行优化(配置文件、函数克隆等)];
D --> E[再次运行应用程序];
E --> F[记录优化后的性能开销];
F --> G[对比分析结果];
3. ProxyCFI 安全分析
为了评估 ProxyCFI 的安全强度,我们进行了两方面的测试:
-
RIPE 渗透测试
:RIPE 是一个控制流攻击测试平台,通过对攻击的五个维度(位置、目标、溢出技术、滥用函数等)进行排列组合来生成攻击。原生 RIPE 针对 32 位 x86 代码,借助最近实现的低脂肪指针扩展,我们将 RIPE 测试套件移植到了 x86 - 64。该移植版本支持五个维度,所有维度的排列组合共有 850 个独特测试。在 ProxyCFI 的保护下,100% 的 RIPE 攻击都被阻止,并且 ProxyCFI 能够检测到攻击逃离 CFG 的准确点。
-
真实世界漏洞测试
:为了评估 ProxyCFI 对真实世界应用程序攻击的有效性,我们纳入了国家漏洞数据库(NVD)中最近报告的攻击。在测试中,ProxyCFI 成功阻止了所有包括 CFG 模仿攻击在内的真实世界攻击。通过分析四个攻击案例(MuPDF、bladeenc、dnsmasq 和 Gravity),我们发现 ProxyCFI 能够根据损坏的指针代理检测到栈旋转、伪造指针代理的跳转尝试等攻击行为,并且能够快速识别漏洞的根本原因。
4. 相关技术对比
在内存安全和控制流完整性方面,有许多相关技术,下面将 ProxyCFI 与这些技术进行对比分析:
-
内存安全技术
:
-
数据执行预防
:数据执行预防技术虽然能一定程度上抵御内存攻击,但对于重用现有代码的攻击却无能为力,因为这类攻击无需注入新代码。
-
Softbound
:这是一种全面的内存安全技术,能够完全杜绝内存利用问题。然而,它存在高开销和兼容性问题,目前还难以广泛应用。
-
控制流完整性技术
:
-
CCFIR
:使用加载时随机跳板部分来重定向所有间接控制流转移,但已被后续工作绕过。
-
Intel CET
:为前向边提供基本的硬件保护,但对于复杂的控制流攻击防护能力有限。
-
Microsoft CFG
:通过限制间接函数调用到函数入口点来实施一种弱形式的 CFI,但容易被 CFG 模仿攻击绕过。
-
CCFI
:通过在代码指针旁边存储基于哈希的消息认证码(MAC)来保护代码指针,并在间接分支前检查 MAC。虽然能抵御 CFG 模仿攻击,但性能开销高达 52%(SPEC’06),限制了其在生产环境中的应用。而 ProxyCFI 同样提供细粒度的控制流保护,平均性能开销仅为 5.9%(SPEC’06)。
-
Return - less kernels
:通过用静态返回表查找替换 ret 指令来避免使用 ret 指令,仅能防范基于返回的攻击。
-
Control - data isolation (CDI)
:将前向和后向边都重写为直接分支,但由于仍使用代码指针来识别程序指针,容易受到不离开 CFG 的控制流攻击,如 Counterfeit OOP。ProxyCFI 通过用指针代理替换代码指针来解决 CFG 模仿攻击问题。
-
Code - Pointer Integrity (CPI)
:通过将代码指针存储在安全区域来提供内存安全,但需要分配一个攻击者无法访问的安全数据区域。ProxyCFI 则不需要任何特殊的数据区域保护。
| 技术名称 | 保护能力 | 性能开销 | 特殊要求 |
|---|---|---|---|
| CCFIR | 有限,已被绕过 | - | - |
| Intel CET | 基本的前向边保护 | - | - |
| Microsoft CFG | 弱形式的 CFI,易被 CFG 模仿攻击绕过 | - | - |
| CCFI | 能抵御 CFG 模仿攻击 | 52%(SPEC’06) | - |
| Return - less kernels | 仅防范基于返回的攻击 | - | - |
| Control - data isolation (CDI) | 易受不离开 CFG 的控制流攻击 | - | - |
| Code - Pointer Integrity (CPI) | 提供代码指针内存安全 | - | 需要安全数据区域 |
| ProxyCFI | 抵御多种控制流攻击,包括 CFG 模仿攻击 | 平均 5.9%(SPEC’06) | 无特殊数据区域保护要求 |
5. ProxyCFI 总结
控制流攻击自首次出现以来,一直是安全领域的重大威胁,尽管人们付出了巨大努力来防范,但这类攻击仍然存在。ProxyCFI 采用了一种新颖的方法,用功能较弱的指针代理替换程序中的所有代码指针。指针代理是一个随机标识符,代表特定函数上下文中的特定程序入口点。使用指针代理的控制转移利用多路直接分支,能够完全预测所有可能的跳转目标。
ProxyCFI 的实现集成到了 GNU GCC C/C++ 编译器工具链中,所有代码指针(包括共享库中的代码指针)都被替换为指针代理。分析表明,在应用针对指针代理的优化后,ProxyCFI 引入的性能下降极小,在广泛的基准测试中平均仅为 4%。安全分析显示,ProxyCFI 能够阻止我们测试的所有控制流攻击,包括 100% 的 RIPE x86 - 64 攻击套件和各种真实世界的攻击,包括 CFG 模仿攻击。
未来,我们可以进一步探索 ProxyCFI 的能力扩展,例如在运行时重新分配指针代理值,以及将指针代理应用于有限的数据指针。
以下是 ProxyCFI 整体流程的 mermaid 图:
graph TD;
A[代码编写] --> B[GCC 编译器集成 ProxyCFI];
B --> C[代码指针替换为指针代理];
C --> D[应用优化(配置文件、函数克隆等)];
D --> E[生成二进制文件];
E --> F[程序加载(指针代理随机化)];
F --> G[程序运行(ProxyCFI 验证)];
G --> H[抵御控制流攻击];
综上所述,ProxyCFI 为控制流攻击的防范提供了一种有效且性能开销较低的解决方案,具有广阔的应用前景。
超级会员免费看

被折叠的 条评论
为什么被折叠?



