[翻译] glibc里的one gadget
字数 1327 2025-08-20 18:18:04

glibc中的one gadget技术详解

一、one gadget概念

one gadget是glibc中调用execve('/bin/sh', NULL, NULL)的一段非常有用的代码片段。在能够控制指令指针(IP/PC)时,使用one gadget可以方便地实现远程代码执行(RCE)。

典型应用场景

  • 能够执行任意函数但无法控制第一个参数时
  • 无法直接调用system("sh")的情况
  • 需要绕过某些安全限制执行shell时

二、one gadget识别条件

64位系统中的识别条件

  1. 能够访问到'/bin/sh'字符串
  2. 调用了exec*系列的函数
  3. 参数设置符合要求

示例分析(64位)

4526a: mov rax,QWORD PTR [rip+0x37dc47]  # 3c2eb8 <_IO_file_jumps@@GLIBC_2.2.5+0x7d8>
45271: lea rdi,[rip+0x146eff]            # 18c177 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
45278: lea rsi,[rsp+0x30]
45278: mov DWORD PTR [rip+0x380219],0x0  # 3c54a0 <__abort_msg@@GLIBC_PRIVATE+0x8c0>
45287: mov DWORD PTR [rip+0x380213],0x0  # 3c54a4 <__abort_msg@@GLIBC_PRIVATE+0x8c4>
45291: mov rdx,QWORD PTR [rax]
45294: call cbbc0 <execve@@GLIBC_2.2.5>

关键点:

  • rdi = libc_base + 0x18c177指向'/bin/sh'字符串
  • rsi = rsp + 0x30设置第二个参数
  • 调用execve函数
  • 约束条件:[rsp + 0x30] == NULL

三、32位与64位差异

主要区别

  1. 数据访问方式不同

    • 64位:使用RIP相对偏移访问数据段
    • 32位:使用[<reg> - 0x??]形式访问只读数据
  2. 调用约定不同

    • 64位:参数通过寄存器传递
    • 32位:参数通过栈传递

32位示例分析

3ac69: mov eax,DWORD PTR [esi-0xb8]
3ac6f: add esp,0xc
3ac72: mov DWORD PTR [esi+0x1620],0x0
3ac7c: mov DWORD PTR [esi+0x1624],0x0
3ac86: push DWORD PTR [eax]
3ac88: lea eax,[esp+0x2c]
3ac8c: push eax
3ac8d: lea eax,[esi-0x567d5]
3ac93: push eax
3ac94: call b0670 <execve@@GLIBC_2.0>

关键点:

  • 需要特定寄存器(ebx或esi)指向libc的GOT区域
  • 参数通过push指令设置
  • 栈操作复杂,需要仔细计算偏移

四、one_gadget工具

工具功能

  1. 自动查找glibc中的one gadget
  2. 分析并显示使用约束条件
  3. 支持符号执行分析复杂约束

安装方法

gem install one_gadget

查找策略

  1. 查找所有访问'/bin/sh'的代码
  2. 筛选附近调用execve的代码段
  3. 分析参数设置指令(如lea rsi, [rsp+0x??])
  4. 使用符号执行确定约束条件

五、常见one gadget示例

glibc-2.19(64位)

0x4647c execve('/bin/sh', rsp+0x30, environ)
0xe5765 execve('/bin/sh', rsp+0x50, environ)
0xe66bd execve('/bin/sh', rsp+0x70, environ)

glibc-2.23(64位)

0x4526a execve('/bin/sh', rsp+0x30, environ)
0xef6c4 execve('/bin/sh', rsp+0x50, environ)
0xf0567 execve('/bin/sh', rsp+0x70, environ)

glibc-2.23(32位)

0x3ac69 execve('/bin/sh', esp+0x34, environ)

六、符号执行技术

实现原理

  1. 将寄存器和栈位置视为符号变量
  2. 模拟指令执行过程
  3. 跟踪数据流和约束条件
  4. 解析最终调用的参数形式

示例分析

对于以下汇编:

mov edx, [eax]
lea esi, [edx + 4]
push esi
call func

如果要func的第一个参数为0,约束条件就是[[eax]+4] == 0

七、实际应用建议

  1. 64位系统:优先使用one gadget,约束条件较简单
  2. 32位系统:需要确保特定寄存器指向GOT区域
  3. 多尝试:不同版本的glibc中one gadget位置不同
  4. 约束验证:使用工具提供的约束条件确保可用性

八、版本差异

不同glibc版本中的one gadget数量:

  • glibc-2.23(64位):6个one gadget
  • glibc-2.23(32位):3个one gadget
  • glibc-2.19(64位):6个one gadget
  • glibc-2.19(32位):4个one gadget

九、总结

one gadget技术是漏洞利用中的重要技巧,掌握其原理和使用方法可以:

  1. 绕过参数控制限制
  2. 简化ROP链构造
  3. 提高漏洞利用成功率
  4. 适应不同环境下的利用场景

建议结合one_gadget工具进行自动化查找和分析,特别是在面对不同版本的glibc时。

glibc中的one gadget技术详解 一、one gadget概念 one gadget是glibc中调用 execve('/bin/sh', NULL, NULL) 的一段非常有用的代码片段。在能够控制指令指针(IP/PC)时,使用one gadget可以方便地实现远程代码执行(RCE)。 典型应用场景 能够执行任意函数但无法控制第一个参数时 无法直接调用 system("sh") 的情况 需要绕过某些安全限制执行shell时 二、one gadget识别条件 64位系统中的识别条件 能够访问到'/bin/sh'字符串 调用了exec* 系列的函数 参数设置符合要求 示例分析(64位) 关键点: rdi = libc_base + 0x18c177 指向'/bin/sh'字符串 rsi = rsp + 0x30 设置第二个参数 调用 execve 函数 约束条件: [rsp + 0x30] == NULL 三、32位与64位差异 主要区别 数据访问方式不同 64位:使用RIP相对偏移访问数据段 32位:使用 [<reg> - 0x??] 形式访问只读数据 调用约定不同 64位:参数通过寄存器传递 32位:参数通过栈传递 32位示例分析 关键点: 需要特定寄存器(ebx或esi)指向libc的GOT区域 参数通过push指令设置 栈操作复杂,需要仔细计算偏移 四、one_ gadget工具 工具功能 自动查找glibc中的one gadget 分析并显示使用约束条件 支持符号执行分析复杂约束 安装方法 查找策略 查找所有访问'/bin/sh'的代码 筛选附近调用execve的代码段 分析参数设置指令(如 lea rsi, [rsp+0x??] ) 使用符号执行确定约束条件 五、常见one gadget示例 glibc-2.19(64位) glibc-2.23(64位) glibc-2.23(32位) 六、符号执行技术 实现原理 将寄存器和栈位置视为符号变量 模拟指令执行过程 跟踪数据流和约束条件 解析最终调用的参数形式 示例分析 对于以下汇编: 如果要 func 的第一个参数为0,约束条件就是 [[eax]+4] == 0 七、实际应用建议 64位系统 :优先使用one gadget,约束条件较简单 32位系统 :需要确保特定寄存器指向GOT区域 多尝试 :不同版本的glibc中one gadget位置不同 约束验证 :使用工具提供的约束条件确保可用性 八、版本差异 不同glibc版本中的one gadget数量: glibc-2.23(64位):6个one gadget glibc-2.23(32位):3个one gadget glibc-2.19(64位):6个one gadget glibc-2.19(32位):4个one gadget 九、总结 one gadget技术是漏洞利用中的重要技巧,掌握其原理和使用方法可以: 绕过参数控制限制 简化ROP链构造 提高漏洞利用成功率 适应不同环境下的利用场景 建议结合one_ gadget工具进行自动化查找和分析,特别是在面对不同版本的glibc时。