从glibc 2.34移除csu函数谈起:ret2csu技巧的过去、现在与替代方案

张开发
2026/4/21 11:10:17 15 分钟阅读

分享文章

从glibc 2.34移除csu函数谈起:ret2csu技巧的过去、现在与替代方案
从glibc 2.34移除csu函数看ROP技术的演进与替代方案在二进制安全领域ROPReturn-Oriented Programming技术一直是攻击者绕过现代防护机制的重要手段。其中ret2csu作为一种经典的ROP技巧因其通用性和高效性备受安全研究人员关注。然而随着glibc 2.34版本的发布这一技术的基础——__libc_csu_init和__libc_csu_fini函数被彻底移除标志着ROP攻防进入了一个新的阶段。1. csu函数的起源与设计初衷__libc_csu_init和__libc_csu_fini这两个函数原本是glibc中负责程序初始化和清理的核心组件。它们的出现源于C/C程序启动和终止时的复杂需求。在传统的程序执行流程中__libc_start_main会依次调用__libc_csu_init- 执行全局构造函数和.init_array中的函数main- 程序主逻辑__libc_csu_fini- 执行全局析构函数和.fini_array中的函数这种设计有几个关键优势模块化初始化允许库开发者在main执行前注册初始化函数跨平台一致性为不同架构提供统一的初始化机制资源管理确保程序退出时正确释放资源从实现上看__libc_csu_init的核心逻辑是遍历.init_array段中的函数指针并依次调用。典型的实现包含以下关键步骤lea r12, __frame_dummy_init_array_entry ; 加载.init_array地址 lea rbp, __do_global_dtors_aux_fini_array_entry ; 计算数组长度 sub rbp, r12 sar rbp, 3 ; 计算元素数量这种设计无意中创造了一个ROP攻击者的宝藏——一系列精心编排的寄存器操作和函数调用指令。2. ret2csu技术的原理与实战应用ret2csu技术的核心在于利用__libc_csu_init函数中的两段特殊指令序列安全研究人员通常称之为gadget1和gadget2。2.1 关键gadget分析gadget1 (位于0x4006A6)add rsp, 8 pop rbx pop rbp pop r12 pop r13 pop r14 pop r15 retngadget2 (位于0x400690)mov rdx, r13 mov rsi, r14 mov edi, r15d call qword ptr [r12rbx*8] add rbx, 1 cmp rbx, rbp jnz short loc_400690这两个gadget组合起来可以实现控制rdi、rsi、rdx三个关键参数寄存器调用任意函数通过r12和rbx控制维持栈平衡通过rbp和rbx的循环控制2.2 典型利用场景在x86_64架构下函数调用遵循System V AMD64 ABI规范前六个参数通过寄存器传递rdi - 第一个参数rsi - 第二个参数rdx - 第三个参数rcx - 第四个参数r8 - 第五个参数r9 - 第六个参数ret2csu特别适合构造如下的函数调用链# 典型利用代码结构 payload padding payload p64(gadget1_addr) # 设置寄存器值 payload p64(0) # add rsp,8的补偿 payload p64(0) # rbx payload p64(1) # rbp (避免循环) payload p64(func_ptr) # r12 - 要调用的函数 payload p64(arg3) # r13 - rdx payload p64(arg2) # r14 - rsi payload p64(arg1) # r15 - edi payload p64(gadget2_addr) # 实际执行调用 payload p64(0)*7 # gadget2返回后的栈平衡这种技术在CTF题目和实际漏洞利用中极为常见特别是在需要构造复杂函数调用如write泄露地址但缺乏合适gadget的情况下。3. glibc 2.34的变革与安全考量glibc 2.342021年发布对程序启动机制进行了重大重构移除了传统的__libc_csu_init和__libc_csu_fini函数。这一变化背后有几个关键原因3.1 技术演进的需求现代程序对启动速度和内存占用有了更高要求。新的初始化机制将相关功能整合到__libc_start_main内部减少了不必要的间接调用。3.2 安全加固的必然选择csu函数的存在本质上违反了最小权限原则。作为通用初始化代码它们包含了过多本不必要的功能问题类型具体表现安全风险过度权限可调用任意函数任意代码执行信息泄露可控制多个寄存器绕过ASLR逻辑缺陷循环控制不严谨可利用性高3.3 对现有利用技术的影响这一变更直接导致ret2csu技术在glibc 2.34的环境中失效ROP链构造难度显著增加需要寻找新的通用gadget来源4. 后csu时代的ROP技术演进随着csu函数的移除安全研究人员开始探索新的ROP技术路径。以下是几种有前景的方向4.1 替代gadget来源libc中的新候选_dl_fini函数中的复杂逻辑文件操作相关函数中的寄存器操作异常处理路径中的有用指令序列非libc来源程序自身的gadget特别是大型应用其他动态链接库中的有用片段编译器生成的意外有用指令4.2 新型利用技术面向数据的编程DOP通过控制数据流而非代码流实现攻击对现有防护机制更具规避性部分控制流劫持结合内存破坏和逻辑漏洞实现有限条件下的利用4.3 防御措施的演进现代防护系统也在持续进化主要方向包括防护技术原理对抗ROP的效果CET (Control-flow Enforcement Technology)硬件级控制流验证阻断非直接跳转PAC (Pointer Authentication Codes)指针完整性校验防止指针篡改BTI (Branch Target Identification)分支目标标记限制有效跳转目标5. 实战从传统到现代的ROP构造让我们通过一个实际案例对比csu时代和现代环境下的ROP利用差异。5.1 传统ret2csu利用以经典的泄露libc地址为例传统方法可能这样构造# 传统ret2csu利用代码 def leak_address(): payload bA*offset payload p64(gadget1) payload p64(0) # add rsp,8 payload p64(0) # rbx payload p64(1) # rbp payload p64(write_got) # r12 payload p64(8) # r13 - rdx (length) payload p64(read_got) # r14 - rsi (buf) payload p64(1) # r15 - edi (fd) payload p64(gadget2) payload p64(0)*7 # cleanup payload p64(main_addr) # 恢复执行 return payload5.2 现代环境下的替代方案在glibc 2.34环境中可能需要采用更复杂的组合# 现代ROP链构造示例 def modern_leak(): payload bA*offset # 使用多个小gadget组合 payload p64(pop_rdi) p64(1) payload p64(pop_rsi_r15) p64(read_got) p64(0) payload p64(pop_rdx_rcx_r8) p64(8) p64(0) p64(0) payload p64(write_plt) payload p64(main_addr) return payload这种方案的关键在于使用多个专用小gadget替代单一通用gadget接受更长的ROP链和更高的利用复杂度依赖程序自身的gadget而非libc的通用实现6. 对安全研究的启示glibc 2.34移除csu函数不仅是技术实现的变化更反映了安全领域的几个重要趋势攻击面缩减开发者越来越注重减少非必要的复杂代码结构深度防御通过多层次防护增加漏洞利用难度攻防博弈升级简单通用的利用技术逐渐失效催生更高级的攻击方法对于安全研究人员这意味着需要更深入地理解底层机制开发更精细化的利用技术关注硬件级安全特性带来的影响在实际漏洞研究中曾经依赖ret2csu的场景现在需要更创新的解决方案。例如在一次针对某大型开源软件的漏洞利用开发中我们发现通过组合以下技术成功替代了传统的ret2csu利用程序自身的异常处理路径中的指令序列结合部分写原语构造有限控制通过间接调用链实现最终利用这种转变也促使防御方开发更全面的缓解措施。微软的网络安全专家Mark Russinovich曾指出现代安全防护必须假设攻击者能够找到意想不到的利用路径因此需要构建覆盖整个攻击面的防护体系。

更多文章