[译]使用 COOP 绕过 CFI 保护
字数 2013 2025-08-18 11:35:40

使用 COOP 绕过 CFI 保护技术详解

1. 引言

控制流完整性(CFI)已成为漏洞利用缓解的重要标准,有多种实现方式如Microsoft CFG、Microsoft RFG、PaX Team的RAP和Clang的CFI。本文介绍一种高级代码重用技术——伪造面向对象编程(COOP),用于绕过现代CFI保护。

2. 漏洞背景

CVE-2015-5122是Hacking Team利用的Adobe Flash Player(<=18.0.0.203)的UAF漏洞。该漏洞提供进程内存的完整读写原语,通过覆盖vector对象的length成员实现。

3. 传统利用方法分析

传统利用方法通过以下步骤实现:

  1. 覆盖vector对象的length成员
  2. 使用ExploitByteArray类提供读写原语
  3. 定义伪造的"magic"方法并覆盖虚函数指针
  4. 调用VirtualProtect修改内存页保护标志
  5. 执行ROP链

这种方法能绕过ASLR和DEP,但无法绕过CFI保护,因为:

  • 函数返回地址与原始调用不匹配
  • 栈迁移和ROP链执行会被基于Shadow Stack的CFI检测

4. CFI约束条件

为绕过现代CFI实现,必须遵循以下约束:

  1. 间接调用/跳转到非已知地址
  2. 返回不符合规定的调用堆栈
  3. 避免过度使用间接分支
  4. 避免堆栈指针迁移(即使是暂时的)
  5. 不注入新代码指针或滥用现有代码指针
  6. 避免间接调用/跳转/返回到"关键函数"

5. COOP技术原理

伪造面向对象编程(COOP)是一种针对C++应用程序的代码重用技术,基于以下假设:

  • CFI实现不考虑C++语义
  • 不验证虚函数调用与调用者对象类的关系

5.1 技术组成要素

  1. vfgadgets:执行特定操作的虚函数
  2. Main Loop Gadget(ML-G):特殊的vfgadget,包含遍历对象列表并调用每个对象虚函数的循环

5.2 技术实现步骤

  1. 伪造vtable对象并选择vptr
  2. 找到合适的vfgadgets
  3. 组合vfgadgets实现所需功能
  4. 通过伪造对象列表控制执行流程

6. 实际案例演示

6.1 案例1:获取可执行内存页

组合两个vfgadgets:

  1. ATL::CComControl::CreateControlWindow
  2. CLibrariesFolderBase::v_AreAllLibraries

6.1.1 ATL::CComControl::CreateControlWindow分析

关键特性:

  • 调用ATL::_stdcallthunk::Init分配EXECUTE_READWRITE内存页
  • 创建thunk将Windows回调转换为虚函数调用
  • thunk数据格式:c7 44 24 04 [thisPointer] e9 [WndProc]

绕过检查:

  • 仅验证对象的一个成员为NULL,完全可控

6.1.2 CLibrariesFolderBase::v_AreAllLibraries分析

作为Main Loop Gadget的特性:

  • 每次迭代调用相同虚函数(vtable偏移0x4c)
  • 仅在函数返回0时停止迭代
  • 接收3个参数,传递2个参数

6.1.3 组合实现

伪造对象结构:

  1. magic方法指针指向ML-ARG-G(vtable+0x18)
  2. ML-ARG-G内部调用CreateControlWindow(vtable+0x4c)

执行流程:

  1. 保存原始this指针
  2. 设置伪造vptr
  3. 配置vtable中的vfgadget指针
  4. 调用magic方法启动COOP流程
  5. 读取分配的EXECUTE_READWRITE内存页地址(存储在this+0x5c)
  6. 写入shellcode并执行

6.2 案例2:文件操作链

发现的5个vfgadgets可实现:

  1. 创建指定路径的子目录
  2. 写入文件"digest.s"
  3. 调用MoveFileEx重命名文件为"atl.dll"
  4. 调用SetCurrentDirectory设置进程当前目录
  5. 调用LoadLibrary加载"atl.dll"

7. 技术优势分析

COOP技术成功绕过CFI的原因:

  1. Microsoft CFG无法检测合法函数的重定向
  2. 不违反后端CFI策略(无返回地址覆盖)
  3. 不使用ROP链
  4. 不更改堆栈指针
  5. 仅操作对象指针,不操作代码指针
  6. VirtualAlloc从合法偏移调用,绕过EMET关键函数保护

8. 防御建议

有效防御COOP攻击需要:

  1. CFI实现考虑语言语义和上下文状态
  2. 实施细粒度策略验证虚函数调用与对象类的关系
  3. 监控异常的对象创建和虚函数调用模式
  4. 加强关键函数保护机制

9. 总结

COOP技术通过巧妙利用C++虚函数机制和CFI实现的局限性,成功绕过了现代CFI保护。防御此类攻击需要更深入的语义分析和细粒度的控制流验证,标志着软件安全进入了一个需要更复杂防御策略的新阶段。

使用 COOP 绕过 CFI 保护技术详解 1. 引言 控制流完整性(CFI)已成为漏洞利用缓解的重要标准,有多种实现方式如Microsoft CFG、Microsoft RFG、PaX Team的RAP和Clang的CFI。本文介绍一种高级代码重用技术——伪造面向对象编程(COOP),用于绕过现代CFI保护。 2. 漏洞背景 CVE-2015-5122是Hacking Team利用的Adobe Flash Player( <=18.0.0.203)的UAF漏洞。该漏洞提供进程内存的完整读写原语,通过覆盖vector对象的length成员实现。 3. 传统利用方法分析 传统利用方法通过以下步骤实现: 覆盖vector对象的length成员 使用ExploitByteArray类提供读写原语 定义伪造的"magic"方法并覆盖虚函数指针 调用VirtualProtect修改内存页保护标志 执行ROP链 这种方法能绕过ASLR和DEP,但无法绕过CFI保护,因为: 函数返回地址与原始调用不匹配 栈迁移和ROP链执行会被基于Shadow Stack的CFI检测 4. CFI约束条件 为绕过现代CFI实现,必须遵循以下约束: 间接调用/跳转到非已知地址 返回不符合规定的调用堆栈 避免过度使用间接分支 避免堆栈指针迁移(即使是暂时的) 不注入新代码指针或滥用现有代码指针 避免间接调用/跳转/返回到"关键函数" 5. COOP技术原理 伪造面向对象编程(COOP)是一种针对C++应用程序的代码重用技术,基于以下假设: CFI实现不考虑C++语义 不验证虚函数调用与调用者对象类的关系 5.1 技术组成要素 vfgadgets :执行特定操作的虚函数 Main Loop Gadget(ML-G) :特殊的vfgadget,包含遍历对象列表并调用每个对象虚函数的循环 5.2 技术实现步骤 伪造vtable对象并选择vptr 找到合适的vfgadgets 组合vfgadgets实现所需功能 通过伪造对象列表控制执行流程 6. 实际案例演示 6.1 案例1:获取可执行内存页 组合两个vfgadgets: ATL::CComControl::CreateControlWindow CLibrariesFolderBase::v_AreAllLibraries 6.1.1 ATL::CComControl::CreateControlWindow分析 关键特性: 调用 ATL::_stdcallthunk::Init 分配EXECUTE_ READWRITE内存页 创建thunk将Windows回调转换为虚函数调用 thunk数据格式: c7 44 24 04 [thisPointer] e9 [WndProc] 绕过检查: 仅验证对象的一个成员为NULL,完全可控 6.1.2 CLibrariesFolderBase::v_ AreAllLibraries分析 作为Main Loop Gadget的特性: 每次迭代调用相同虚函数(vtable偏移0x4c) 仅在函数返回0时停止迭代 接收3个参数,传递2个参数 6.1.3 组合实现 伪造对象结构: magic方法指针指向ML-ARG-G(vtable+0x18) ML-ARG-G内部调用CreateControlWindow(vtable+0x4c) 执行流程: 保存原始this指针 设置伪造vptr 配置vtable中的vfgadget指针 调用magic方法启动COOP流程 读取分配的EXECUTE_ READWRITE内存页地址(存储在this+0x5c) 写入shellcode并执行 6.2 案例2:文件操作链 发现的5个vfgadgets可实现: 创建指定路径的子目录 写入文件"digest.s" 调用MoveFileEx重命名文件为"atl.dll" 调用SetCurrentDirectory设置进程当前目录 调用LoadLibrary加载"atl.dll" 7. 技术优势分析 COOP技术成功绕过CFI的原因: Microsoft CFG无法检测合法函数的重定向 不违反后端CFI策略(无返回地址覆盖) 不使用ROP链 不更改堆栈指针 仅操作对象指针,不操作代码指针 VirtualAlloc从合法偏移调用,绕过EMET关键函数保护 8. 防御建议 有效防御COOP攻击需要: CFI实现考虑语言语义和上下文状态 实施细粒度策略验证虚函数调用与对象类的关系 监控异常的对象创建和虚函数调用模式 加强关键函数保护机制 9. 总结 COOP技术通过巧妙利用C++虚函数机制和CFI实现的局限性,成功绕过了现代CFI保护。防御此类攻击需要更深入的语义分析和细粒度的控制流验证,标志着软件安全进入了一个需要更复杂防御策略的新阶段。