利用开发(ROP 链构造 / 堆利用)

SkillDev tools

利用开发:ROP 链构造、堆利用。 触发词:ROP、堆利用、fastbin、tcache、利用开发、exploit

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the 利用开发(ROP 链构造 / 堆利用) skill

What this skill tells your AI

The instructions your AI receives, as published by dslsdzc/rev-skills in .claude/skills/re-exploit/SKILL.md and read by ahel’s review.

何时使用 / 何时不用

  • 用:拿到已定位的漏洞(越界读写 / 崩溃 / 危险输入)要升级为 RCE / 任意读写——漏洞分析([[re-crash-triage]] / [[re-vuln]])移交的利用开发环节
  • 用:ROP 链构造——gadget 搜索、栈布局、ret2csu / SROP / ret2dlresolve
  • 用:堆利用——fastbin / tcache 攻击、unsorted bin 泄露、double free 系列
  • 用:seccomp 沙箱绕过(ORW:open / read / write 链)
  • 不用:入门级 pwn(ret2win / 简单 ret2libc / 格式化字符串)→ [[re-pwn]]
  • 不用:只有崩溃还没有定位(→ [[re-crash-triage]]);还没崩溃找 bug(→ [[re-fuzzing]])
  • 注意:利用验证是动态执行,默认在沙箱内跑([[re-analyze/platform-tips]] 最高原则,见 [[re-sandbox]]);先规划再写(坑 4),组合绕过分步验证

工具准备

参考 [[re-analyze/platform-tips]]——利用验证默认沙箱;静态准备(gadget 搜索 / 规划)可免沙箱,动态验证进沙箱。

pwntools(pip 安装,Python 3.8+)—— 利用脚本主力

  • pip install pwntools(官方 PyPI,4.15.x;官方文档声明支持 Python 3.8+,64 位系统支持最好)
  • 发行版包:Debian/Ubuntu sudo apt install python3-pwntools、Fedora sudo dnf install python3-pwntools、Arch sudo pacman -S python-pwntools(Extra 仓库官方包)
  • Python 3.12+(Ubuntu 24.04 自带 3.12)直接 pip 装报 PEP 668 externally-managed-environment——对策:venv(python3 -m venv ~/venvs/pwn && source ~/venvs/pwn/bin/activate)或发行版包或 --break-system-packages
  • 验证: pwn --version / python3 -c "import pwn; print(pwn.version)"

ropper / ROPgadget —— gadget 搜索

  • ropper:pip install ropper(官方 PyPI);Arch sudo pacman -S ropper(Extra 官方包);Debian/Ubuntu/Fedora 无官方包 → pip
  • ROPgadget:pip install ROPgadget(官方 PyPI);Debian/Ubuntu sudo apt install python3-ropgadget、Fedora sudo dnf install python3-ROPGadget、Arch sudo pacman -S ropgadget(均为官方包)
  • 验证: ropper --versionROPgadget --binary ./target | head;常用搜索:ROPgadget --binary ./target | grep 'pop rdi'ropper -f ./target --search "pop rdi"

gdb + gef/pwndbg(见 [[re-gdb]])—— 栈/堆布局验证

  • gdb: Debian/Ubuntu sudo apt install gdb、Fedora sudo dnf install gdb、Arch sudo pacman -S gdb、macOS brew install gdb;32 位目标 Debian/Ubuntu 补 gdb-multiarch + libc6-i386
  • 堆利用调试建议装 pwndbgheap / bins(tcachebins / fastbins / unsorted)命令直接看 chunk 布局与 bin 链表(gef 也有 heap bins,功能略弱);验证: gdb 里 heap bins 有输出
  • pwndbg 内置 checksec(见 [[re-pwn]] 工具准备)

angr(可选,见 [[re-angr]])—— 溢出大小 / 路径约束自动化

  • pip install angr——Python 版本兼容性以 [[re-angr]] 的「工具准备」为准(版本矩阵只在该处维护一份,避免两处漂移)
  • 用:溢出偏移不确定(符号化输入求覆盖返回地址的约束)、利用路径校验逻辑复杂
  • 验证: python3 -c "import angr; print(angr.__version__)"

操作步骤

按顺序执行;每步产物(利用面结论、gadget 清单、链布局、PoC)记录证据路径 + sha256(存证方法见 [[re-triage]]),供报告引用。

  1. 利用面分析(崩溃点 / 可控数据)

    • 输入:[[re-crash-triage]] 的最小 PoC / 漏洞报告(崩溃点 + 输入通道)——确认可控字节范围与偏移cyclic 定位崩溃时 rip 偏移,见 [[re-pwn]] 步骤 2)
    • pwn checksec --file ./target:NX / PIE / Canary / RELRO——每项决定一条限制:栈不可执行 → 不能直接跑 shellcode;PIE → 地址要泄露 base;RELRO full → GOT 不可写(改函数指针 / 栈地址 / libc 钩子替代)
    • seccomp 检查seccomp-tools dump ./target(Gem: gem install seccomp-tools,官方途径;Arch 官方仓库无此包——仅 AUR 有 seccomp-tools,直接用 gem 即可)或静态找 prctl / seccomp 调用——若禁 execve 则拿 shell 路线作废,改 ORW 链(步骤 4)
    • 记录:崩溃偏移、保护矩阵、seccomp 规则、可利用原语(任意写 / 栈溢出 / 堆越界)
  2. ROP 链(gadget 搜索、栈布局)

    ROPgadget --binary ./target | grep -E 'pop rdi|pop rsi|pop rdx'   # 64 位传参 gadget
    ROPgadget --binary ./target | grep 'ret' | head                   # 对齐用 ret
    ropper -f ./target --search "syscall"                             # SROP / shellcode 跳板
    
    • 布局模板(64 位,先泄露后执行两段式): padding + pop_rdi_ret + arg1 + func_addr + [对齐 ret] + 下一段...
    • 参数顺序:rdi → rsi → rdx(SysV ABI);缺 rdx gadget 时用 ret2csu__libc_csu_init 里的 pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; ret + 搬运 mov 段)或 ret2dlresolve
    • 16 字节对齐call$rsp % 16 == 0 才满足 movaps(glibc 新版本 system/printf 内部会用),不对齐在 gadget 链前补一个 ret
    • 栈布局产物:链注释图(偏移 + gadget 地址 + 参数)+ 算好的偏移表
  3. 堆利用(fastbin / tcache 攻击模式)

    • 先看 glibc 版本(ldd ./target | grep libc)决定攻击面(坑 3):
      • tcache(glibc ≥ 2.26):tcache poisoning——double free 后改 fd 到目标地址附近 → 下一次分配拿到任意地址(2.32+ 指针被 safe-linking 异或,坑 3);UAF 直接改 fd 更快
      • fastbin(glibc < 2.26 / 老题):fastbin dup——double free 同一 chunk 两次 → 同一地址连续分配两次 → 伪造堆上任意写
      • unsorted bin 泄露:free 大 chunk(> fastbin 上限)进 unsorted bin,fd/bk 指向 main_arena —— show/格式化读泄露 libc base(libc_base = leaked - main_arena_offset
    • 用 pwndbg 逐 chunk 验证:
      (gdb) heap            # 看 chunk 布局与地址
      (gdb) bins            # 看各 bin 链表(tcachebins/fastbins/unsorted)
      
    • 模式清单:double free → tcache dup;UAF → fd 覆写 / 泄露;off-by-one(单字节溢出)→ 改 next chunk size 造重叠 chunk;house of 系列(高版本利用)标注复杂度再上
    • 目标落地:任意地址分配 → 改 __free_hook(≤2.33)/ __malloc_hook / GOT 可写项 / 栈返回地址 → 触发 get shell 或任意读写
  4. 沙箱 / 缓解绕过(seccomp)

    • 若步骤 1 发现禁 execveORW 链——ROP 依次调 open(flag_path, 0)read(fd, buf, n)write(1, buf, n)
      ROPgadget --binary ./target | grep -E 'syscall|pop rdi|pop rsi|pop rdx'   # 或 libc 里的 gadget
      
    • 找不到现成 syscall gadget 时用 libc 的(先泄露 libc base)或 SROP(rt_sigreturn 构造寄存器帧)
    • 缓解绕过思路:PIE → 先泄露 base(格式化 / 堆泄露 / puts 泄露,见 [[re-pwn]] 步骤 3-4);Canary → 泄露后再溢出(payload = pad + canary + pad + ret,canary 低 1 字节为 \x00 可直接截断处理);RELRO full → 不打 GOT,改栈 / __free_hook / environ 泄栈地址
    • 组合顺序纪律:先泄露(canary / libc base / heap base)→ 再覆盖(坑 4)
  5. PoC 验证

    from pwn import *
    context.binary = './target'; context.log_level = 'debug'
    p = process('./target')            # 沙箱内本地;远程: remote(host, port)
    p.sendline(payload)
    p.interactive()
    
    • 验证纪律:逐步验证每段链(泄露段先打,看到泄露值对得上再打覆盖段)——一次全链失败无法定位是哪段错(坑 4);gdb 断在链入口逐条 si 确认跳转与栈布局
    • 本地跑通 → 记录 PoC(文件 + sha256 + 运行输出)→ 远程最终验证;PoC hash 与漏洞特征可进 [[re-ioc]]

内核利用

与用户态同框架:fuzz([[re-fuzzing]])→ crash([[re-crash-triage]])→ 利用(本路径)。

  • 提权原语:modprobe_path 覆写(触发内核执行任意路径)、cred 结构覆写(uid/gid 置 0)、io_uring / BPF 子系统利用面
  • 堆喷与对象布局:堆喷策略(同尺寸对象占位)、对象重叠(UAF 后伪造对象)、SLUB 分配器行为(per-CPU 缓存)
  • 内核 UAF 利用路径:漏洞触发(悬垂引用)→ 对象重用(占位伪造)→ 控制流劫持(函数指针 / ops 表覆写)
  • 环境:调试内核(KASAN 开、KASLR 关闭或绕过)、gdb/kgdb 断点、模块化测试(只读分析 + 沙箱验证)

跨域联合

  • [[re-vuln]]:本技能被漏洞挖掘网关引用——网关 4-5 步(逆向定位 → 报告)之后,可利用的漏洞进入本技能做利用开发(漏洞挖掘域"从崩溃到 PoC"的收口)
  • [[re-crash-triage]]:崩溃分析 / 最小 PoC 输入交接本技能(利用面分析第一步的输入);本技能产出的 PoC 反过来验证漏洞可达性
  • [[re-pwn]]:入门衔接——栈溢出 / 格式化字符串 / ret2libc 基础在本技能扩展为复杂 ROP 与堆利用
  • [[re-ctf]]:pwn 赛题进阶(堆题 / 高难度 ROP 题)经网关调度本技能
  • [[re-angr]](可选):溢出偏移求约束、利用路径校验自动化
  • [[re-gdb]]:栈 / 堆布局动态验证(pwndbg heap/bins);[[re-binary-core]] 底座定位原语与后门
  • [[re-sandbox]] / [[re-analyze/platform-tips]]:利用验证默认沙箱内跑(最高原则);远程目标仅做最终验证

常见坑与陷阱

  • gadget 地址受 ASLR / PIE 影响(泄漏为先):现象——按静态地址(objdump 出的 gadget / 函数地址)写链,本地偶发成功远程必挂,或泄露后算出的 base 对不上;原因——PIE 开启时二进制基址随 ASLR 变化(低 12 位页内偏移不变),libc 基址同理;静态地址只在无 PIE(或已算 base)时成立;对策——泄漏为先:第一段链先泄露(puts/printf 打 GOT 或堆/格式化泄露),libc_base = leaked - offsetbinary_base = leaked - offset,后续所有 gadget/函数地址 = base + 静态偏移(低 12 位直接拼);每次泄露后重新计算再发覆盖段,别复用上一轮的 base
  • tcache 双链表检查(safe-linking 异或 / key 检查):现象——glibc 2.32+ 上 classic tcache poisoning 崩(malloc(): unaligned tcache chunk detected)或 double free 直接 abort(free(): double free detected in tcache 2);原因——2.32 起 tcache fd 被 safe-linking 异或(PROTECT_PTR(pos, ptr) = ptr ^ (pos >> 12),pos 是该 chunk 的 fd 字段自身存储地址(常规 chunk 即 chunk_addr + 0x10),不是 heap_base);2.29 起 double free 检查 key 字段:free 进 tcache 时把 key 写成 tcache 结构地址,再 free 同 chunk 时发现 key 仍等于 tcache 指针就遍历整个 bin 找重复(命中直接 malloc_printerr abort)——"中间插一次 free 别的 chunk"不清除首个 chunk 的 key 字段,绕不过;对策——写新 fd 前先泄露堆地址再编码:stored_fd = new_fd ^ (fd_field_addr >> 12)(UAF 读到的 fd 是已解密指针,但新值必须重新编码——PROTECT_PTR 作用于每次写入,只有原样写回才免编码);double free 绕 key 检查只有两条路:① UAF 改写 key 字段(改成非 tcache 指针值)② 改 size 使 chunk 落入不同 bin(key 检查只看目标 bin 的链头,落别的 bin 不触发)
  • glibc 版本差异(check 变化):现象——本地(如 glibc 2.31)打通的堆利用,题目远程(2.35 / 2.27)行为完全不同:tcache 不存在 / 数量上限不同 / __free_hook 没了 / safe-linking 出现;原因——堆管理器每版本收紧检查:2.26 引入 tcache、2.29 加 key 检测、2.32 加 safe-linking、2.34 删 __malloc_hook/__free_hook(2.34+ 用 __libc_malloc 指针或环境劫持)、2.37 起 global_max_fast 收窄为 uint8_t(fastbin 上限随之收紧)、tcache 初始化改用 __getrandom_nocancel;对策——ldd ./target | grep libc 先确认版本,攻击面按版本选(步骤 3 清单);本地环境与远程不一致时用 patchelf --set-interpreter ./ld-2.35.so --replace-needed libc.so.6 ./libc-2.35.so 换 libc 本地复现;2.34+ 换目标(__malloc_hook 不存在 → 打 exit 函数指针 / setcontext / vtable 思路);每个 check 收紧点(key / safe-linking / count)列检查清单逐步验证
  • 绕过组合复杂(先规划再写):现象——防护多个叠加时(NX+PIE+Canary+seccomp+高版本 glibc)脚本越改越乱,动不动全崩,调试半天发现是某一小段逻辑错;原因——每个保护是独立约束,组合后依赖链长(泄露 canary → 泄露 libc → 泄露堆 → ORW 链),一步错全盘错,边写边试没有全局规划;对策——先写利用规划表再写代码:列清(1)需要哪些原语(栈溢出 / UAF / 格式化写)(2)需要泄露什么、泄露顺序与依赖(canary 必须在覆盖前、libc base 必须在调 libc 函数前)(3)每段链的入口与出口;然后分步实现分步验证:泄露段单独跑通(值对得上)→ 覆盖段单独跑通(gdb 确认返回地址命中)→ 合链;gdb 断点逐段 si;每改一步先确认上一步仍通
  • 对齐问题(movaps / 栈对齐):现象——ROP 链到 systemprintf 就段错误,gdb 看指令在 movaps 处崩,链前半段明明全对;原因——x86-64 ABI 要求 call 时栈 16 字节对齐,GCC 生成的 libc 函数(printf/system/execve)内部 movaps 假设对齐,不对齐直接 SIGSEGV;对策——在调用 gadget 链里、目标函数前补一个 ret gadget(ret 使 $rsp += 8 调整对齐);或选对齐版 gadget(pop rdi; ret + 偶数字节 padding);64 位所有 libc 函数调用前都按此检查

Signals

GitHub stars
57
Forks
8
Last commit
Sep 2026

ahel review

  • K1binfo
    installs-packages

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Catalog kind
skill
Gateway key
re-exploit
Source
github.com/dslsdzc/rev-skills