
前言:内存破坏漏洞利用与对抗的发展历史
第一步:利用——代码注入类攻击:
代码注入类攻击是一类攻击技术,攻击者通过利用软件漏洞(如缓冲区溢出、输入验证不当等)向目标程序的内存中插入并执行恶意代码,从而劫持程序控制流,执行未授权操作。
第二步:对抗——数据执行保护(DEP):
数据执行保护是一种系统级内存保护功能,使系统能够将一个或多个内存页标记为不可执行。将内存区域标记为不可执行意味着代码无法从该内存区域运行,这使得利用缓冲区溢出更加困难。DEP阻止从默认堆、堆栈和内存池等数据页运行代码。如果应用程序尝试从受保护的数据页运行代码,则会发生内存访问冲突异常,如果未处理该异常,调用进程将终止。
第三步:利用——代码重用类攻击:
代码重用攻击是一种利用现有程序代码(而非注入新代码)来执行恶意操作的攻击方式。它通常用于绕过数据执行保护(DEP)等安全机制,因为DEP会禁止在数据区执行注入的代码,但不会阻止程序本身的代码执行。
第四步:对抗——地址随机化(ASLR)与控制流完整性(CFI):
为了防御代码重用攻击,现代操作系统和编译器引入了一些安全机制:
地址空间布局随机化(ASLR):通过随机化代码段、堆、栈等地址,使攻击者难以预测ROP/JOP gadgets的地址。但如果存在信息泄露漏洞,ASLR可能被绕过。
控制流完整性(Control-Flow Integrity, CFI):限制函数调用和跳转的目标地址,只允许合法路径上的控制流执行。使ROP、JOP、COP等攻击更难实施。
WOOT’24:论文的重点研究内容
这篇论文的题目为:SoK: On the Effectiveness of Control-Flow Integrity in Practice。
解决了CFI研究中的哪些问题?
- 第一,实际生产环境有哪些已经部署的CFI机制;
- 第二,这些CFI机制在何处部署以及如何部署;
- 第三,它们在对抗攻击方面的有效性以及仍然存在的局限性有哪些?
- Which CFI schemes are found in practice?
- Where and how consequently are they deployed?
- What are their capabilities and limitations to prevent attacks?
实际生产环境已经部署哪些CFI?
- 编译器:LLVM Clang CFI;
- Windows:WCFG、XFG;
- ARM:PAC(文章没有提到,MTE也已经部署);
- Intel:CET(同时包含有Shadow Stack以及IBT)。
- LLVM Clang CFI, used primarily on Android and the Linux Kernel;
- Windows Control Flow Guard (WCFG) and its successor eXtended Flow Guard (XFG);
- ARMv8 Pointer Authentication (PA) including Branch Target Identification (BTI), utilised by recent Apple Systems on a Chip (SoCs) starting with the A12, S4, and M1 chips, by Android, and by Windows on ARM;
- Intel Control-flow Enforcement Technology (CET), supported on Intel processors starting with the 11th Gen and used by Windows and Linux.
这篇论文的主要贡献是什么?
- 作者对实际应用中的主流控制流完整性(CFI)解决方案进行了系统化整理,包括 LLVM 的 CFI 方案以及微软在 Windows 上的闭源实现 WCFG 和 XFG。
- 作者通过对 Android 和 Windows 二进制文件的大规模分析,研究了 CFI 的覆盖范围、安全特性及其实践中的有效性。
- 作者分析了相同设备的不同版本 Android 固件发布情况,以深入了解其随时间的演进。
- We systematize prevalent CFI solutions in practice, including LLVM’s CFI scheme and Microsoft’s closedsource implementations WCFG and XFG on Windows.
- We study CFI coverage, security characteristics, and effectiveness in practice by running a large-scale binary analysis on Android and Windows binaries.
- We analyse Android firmware releases of the same devices to get insights into the development over time.
本篇文档重点关注什么内容?
考虑到我们的主题是寻找体系结构安全与内存安全机制相关的话题,本篇文档的重点将侧重于以下几个方面:
- 这篇论文提到、介绍并分析了哪些已经实际部署的CFI安全机制(即,论文的第一个主要贡献);
- 这些CFI安全机制是否已经能够被体系结构侧信道攻击所绕过(与先前2024/11/18的博客所对应);
- 在前两者的基础上思考体系结构安全与内存安全之间的关系;
- 值得一提的是,这篇论文的威胁模型中提到假定攻击者已经能够绕过ASLR:
The CFI adversary model assumes that by using these capabilities, the adversary can break Address Space Layout Randomisation (ASLR).
WOOT’24:CFI软硬件、前后向分类的基本概念
按照CFI完整性检查机制是由软件实现的还是需要底层硬件支持,可以划分为:
- 基于软件的CFI:例如,LLVM CFI、WCFG、XFG、LLVM影子栈、栈Canary;
- 基于硬件的CFI:例如,ARM PAC、ARM BTI、Intel IBT、FineIBT、Intel CET影子栈;
按照所防护的对象(可以看作控制流转移指令,也就是分支指令)的转移方式,可以划分为:
- 前向CFI:前向转移指的是将控制权定向到程序中一个新位置的转移方式,其实就可以看作是
call
指令和jmp
指令; - 后向CFI:后向转移指的是将控制权返回到先前位置的转移方式,其实就可以看作是
ret
指令。
因此,前面所提到的这些CFI机制中,前向CFI和后向CFI分别包含:
- 前向CFI:LLVM CFI、WCFG、XFG、ARM PAC、ARM BTI、Intel IBT、FineIBT;
- 后向CFI:LLVM影子栈、Intel CET影子栈、栈Canary。
WOOT’24:软件实现的前向CFI
LLVM CFI:
LLVM CFI是Clang编译器前端的一部分,支持包括 C++ 在内的 C 语言家族。它能够保护间接函数调用、通过成员函数指针进行的调用、虚函数调用、使用多态类(即声明或继承虚函数的类)进行的非虚函数调用,以及多态类的非法类型转换。
根据Clang编译器的手册,可选的CFI编译参数有以下几个部分:
-fsanitize=cfi-cast-strict
: Enables strict cast checks.-fsanitize=cfi-derived-cast
: Base-to-derived cast to the wrong dynamic type.-fsanitize=cfi-unrelated-cast
: Cast from void* or another unrelated type to the wrong dynamic type.-fsanitize=cfi-nvcall
: Non-virtual call via an object whose vptr is of the wrong dynamic type.-fsanitize=cfi-vcall
: Virtual call via an object whose vptr is of the wrong dynamic type.-fsanitize=cfi-icall
: Indirect call of a function with wrong dynamic type.-fsanitize=cfi-mfcall
: Indirect call via a member function pointer with wrong dynamic type.
参考链接:https://clang.llvm.org/docs/ControlFlowIntegrity.html
Windows WCFG和XFG(闭源):
Microsoft Windows 具有专有的 CFI 实现,并直接集成到操作系统中。该实现称为控制流保护(Control Flow Guard,WCFG),首次发布于 2014 年 11 月。WCFG 施加了一种强制 CFI 策略,要求间接调用必须指向已知的取地址函数或导出函数。这意味着所有目标属于同一个等价类,因此 WCFG 是一种粗粒度的 CFI 方案。对于间接调用(包括使用虚函数表进行的虚函数调用),WCFG 通过调用检查函数进行保护,或直接替换为调用一个分发函数,该函数先执行 WCFG 检查,然后再分发调用。
微软正在开发 WCFG 的继任者 eXtended Flow Guard(XFG),尽管尚未公开文档,但已在 Windows 预览版本中提供。XFG 采用类似于 LLVM CFI 实现的基于类型的策略,但其 CFI 检查基于嵌入式标签进行。
体系结构侧信道攻击:
Spectre攻击能够绕过LLVM CFI:
Research has demonstrated that Spectre v1-like attacks can bypass software-based CFI defenses, such as LLVM-CFI, even in the presence of all default mitigations.
WOOT’24:硬件实现的前向CFI
参考如下PPT与文档:
https://iamywang.github.io/images/arch-mem-1/memory-safety.pdf
https://iamywang.github.io/2024/11/18/arch-mem-2/
体系结构侧信道攻击:
可以说,基于硬件实现的前向CFI均容易遭受侧信道攻击的威胁,这些论文普遍发表于体系结构或者信息安全领域的顶级会议上:
- ISCA’22:绕过ARM PAC的PACMAN攻击;
- Security’24:绕过IBT和FineIBT的BHI攻击变体;
- Oakland’25:绕过ARM MTE的TikTag攻击。
WOOT’24:软件实现的后向CFI
LLVM Shadow Stack:
LLVM 在 AArch64 架构上实现了一种影子栈(shadow stack)方案。Clang 支持的设计是一种基于信息隐藏的紧凑型影子栈,即影子栈使用寄存器 X18 维护其专有的栈指针,而该寄存器必须对攻击者保持未知状态,以提供保护。这意味着该寄存器不能被溢出到栈上(例如在调用未受保护的代码时),否则攻击者可能通过此途径获取影子栈的位置。
SafeStack:
除了影子调用栈(shadow call stack),LLVM 还实现了 SafeStack。SafeStack 的核心思想是在栈上分离安全和不安全的内存对象。被视为安全的内存对象包括返回地址、栈溢出数据(stack spills)以及仅通过帧指针(frame pointer)访问、未被取地址的局部变量。而其他所有对象都会被存储在不安全栈上。
体系结构侧信道攻击:
这类软件实现的影子栈自身仍然存在内存安全问题,USENIX Security’16会议以及BlackHat’16会议上分别有针对LLVM影子栈以及SafeStack的漏洞利用工作,实际上意味着利用体系结构侧信道进行绕过的意义不大。
WOOT’24:硬件实现的后向CFI
Intel CET:
Intel CET(Control-Flow Enforcement Technology)是Intel新推出的一项新的硬件级对策,其主要目的是防止攻击者通过ROP/JOP/COP等攻击手段来劫持控制流。
对于ROP攻击的防护,其基本思想与影子栈(shadow stack)类似,即由操作系统在内存中复制一份程序的内存栈或者是仅仅保留控制流跳转地址。然后,这个影子栈无法由正常的store、load指令进行控制,只能通过专门的指令来进行控制。因此,即使攻击者覆盖了软件栈上的返回地址,但是由于影子栈中仍然保存着原始的跳转地址,因此检查失败后会通过抛出异常来终止程序的执行。
体系结构侧信道攻击:
从现有资料中,可以认为,无法对Intel CET影子栈实施推测执行攻击。
- Instructions at the target of a RET instruction will not execute, even speculatively, if the RET addresses (either from normal stack or shadow stack) are speculative-only or do not match.
- Speculative execution only occurs when:
- return address on stack == return address on RSB
- Never returns to malicious address
参考文献
[1] Becker, L., Hollick, M., & Classen, J. (2024). SoK: On the Effectiveness of {Control-Flow} Integrity in Practice. In 18th USENIX WOOT Conference on Offensive Technologies (WOOT 24) (pp. 189-209).
[2] Ammar, M., Caulfield, A., & Nunes, I. D. O. (2025). Sok: Integrity, attestation, and auditing of program execution. In 2025 IEEE Symposium on Security and Privacy (SP). IEEE Computer Society.
[3] Ravichandran, J., Na, W. T., Lang, J., & Yan, M. (2022, June). PACMAN: attacking ARM pointer authentication with speculative execution. In Proceedings of the 49th Annual International Symposium on Computer Architecture (pp. 685-698).
[4] Wiebing, S., de Faveri Tron, A., Bos, H., & Giuffrida, C. (2024). InSpectre Gadget: Inspecting the Residual Attack Surface of Cross-privilege Spectre v2. In 33rd USENIX Security Symposium (USENIX Security 24) (pp. 577-594).
[5] Kim, J., Park, J., Roh, S., Chung, J., Lee, Y., Kim, T., & Lee, B. (2025). TikTag: Breaking ARM’s Memory Tagging Extension with Speculative Execution. In 2025 IEEE Symposium on Security and Privacy (SP). IEEE Computer Society.
[6] https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html