Linux x64 下的万能 Gadget
字数 1208 2025-08-05 08:20:14
Linux x64 下的万能 Gadget 教学文档
一、通用 Gadget 概述
在 Linux x64 环境下进行 ROP (Return-Oriented Programming) 攻击时,__libc_csu_init() 函数提供了一个极其强大的通用 Gadget。这个 Gadget 存在于几乎所有调用了 libc.so 的 x64 程序中,可以用于控制多个寄存器和函数参数。
关键特性:
- 可以控制最多三个函数参数 (rdi/rsi/rdx)
- 可以通过函数指针 (通常是 GOT 表项) 调用目标函数
- 支持循环调用 (通过设置 rbp=rbx+1)
- 需要至少 56 字节栈空间 (加上返回地址共 64 字节)
二、Gadget 结构分析
主要执行流程:
- 从
0x40061A开始执行,布置 rbx/rbp/r12/r13/r14/r15 六个寄存器 - 返回到
0x400600,继续布置 rdx/rsi/rdi - 通过
call qword ptr[r12+rbx*8]执行目标函数
栈空间布局:
+------------------+
| 返回地址 (0x40061A) |
+------------------+
| rbx 值 |
+------------------+
| rbp 值 |
+------------------+
| r12 值 |
+------------------+
| r13 值 |
+------------------+
| r14 值 |
+------------------+
| r15 值 |
+------------------+
| 返回地址 (0x400600) |
+------------------+
三、隐藏 Gadget 发现
1. pop rdi; ret Gadget
在地址 0x400622 上的 pop r15; ret 指令 (0x41 0x5F 0xC3) 中,后两个字节 (0x5F 0xC3) 组成了 pop rdi; ret 指令。
用途:
- 实现单参数函数调用
- 仅需 24 字节栈空间
栈布局:
+------------------+
| 返回地址 (0x400623) | // pop rdi; ret 地址
+------------------+
| 参数1 (rdi) |
+------------------+
| 目标函数地址 |
+------------------+
2. pop rsi; ...; ret Gadget
在地址 0x400620 上的 pop r14 两字节指令 (0x41 0x5E) 中,后一个字节 (0x5E) 是 pop rsi 指令。
结合 0x400623 的 pop rdi; ret,可以实现双参数函数调用。
栈布局:
+------------------+
| 返回地址 (0x400623) | // pop rdi; ret
+------------------+
| 参数1 (rdi) |
+------------------+
| 返回地址 (0x400620) | // pop rsi; ...
+------------------+
| 参数2 (rsi) |
+------------------+
| 目标函数地址 |
+------------------+
四、实际应用场景
1. 泄漏 libc 函数地址
典型的两步攻击:
- 使用
puts(puts@got)泄漏 libc 函数地址 - 计算 system 和 "/bin/sh" 地址
- 执行
system("/bin/sh")
2. 单参数函数调用
使用 pop rdi; ret Gadget 可以高效完成:
puts(puts@got)泄漏地址system("/bin/sh")获取 shell
3. 多参数函数调用
使用完整 Gadget 可以调用需要多个参数的函数
五、总结
__libc_csu_init()是 Linux x64 下极其强大的通用 Gadget- 包含
pop rdi、pop rsi、pop rdx、ret等指令片段 - 可以组合实现单参数、双参数、三参数函数调用
- 最小仅需 24 字节栈空间即可完成基本攻击
- 是 Linux x64 ROP 攻击的核心技术之一
六、参考实现
# 示例:使用 pop rdi; ret 调用 puts(puts@got)
rop_chain = [
pop_rdi_ret, # 0x400623
puts_got, # 参数1: puts@got
puts_plt, # 调用 puts
main_addr # 返回地址,准备第二阶段
]
# 示例:使用完整 Gadget 调用 execve
rop_chain = [
csu_init_addr1, # 0x40061A
0, # rbx
1, # rbp (rbx+1)
func_ptr, # r12: 函数指针
arg1, # r13 -> rdi
arg2, # r14 -> rsi
arg3, # r15 -> rdx
csu_init_addr2, # 0x400600
0, # 填充
0, # 填充
0, # 填充
0, # 填充
0, # 填充
0, # 填充
0, # 填充
]