executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
re-exploit利用开发:ROP 链构造、堆利用。 触发词:ROP、堆利用、fastbin、tcache、利用开发、exploit
Independent GitHub snapshot · Automated classification · Original documentation governs
参考 [[re-analyze/platform-tips]]——利用验证默认沙箱;静态准备(gadget 搜索 / 规划)可免沙箱,动态验证进沙箱。
pip install pwntools(官方 PyPI,当前正式版 4.15.0)——Python 版本兼容性以 [[re-pwn]] 的「工具准备」为准(版本矩阵只在该处维护一份,避免两处漂移)sudo apt install python3-pwntools、Fedora sudo dnf install python3-pwntools、Arch sudo pacman -S python-pwntools(Extra 仓库官方包)externally-managed-environment——对策:venv(python3 -m venv ~/venvs/pwn && source ~/venvs/pwn/bin/activate)或发行版包或 --break-system-packagespwn --version / python3 -c "import pwn; print(pwn.version)"pip install ropper(官方 PyPI);Arch sudo pacman -S ropper(Extra 官方包);Debian/Ubuntu/Fedora 无官方包 → pippip install ROPgadget(官方 PyPI);Debian/Ubuntu sudo apt install python3-ropgadget、Fedora sudo dnf install python3-ROPGadget、Arch sudo pacman -S ropgadget(均为官方包)ropper --version;ROPgadget --binary ./target | head;常用搜索:ROPgadget --binary ./target | grep 'pop rdi'、ropper -f ./target --search "pop rdi"sudo apt install gdb、Fedora sudo dnf install gdb、Arch sudo pacman -S gdb、macOS brew install gdb;32 位目标 Debian/Ubuntu 补 gdb-multiarch + libc6-i386heap / bins(tcachebins / fastbins / unsorted)命令直接看 chunk 布局与 bin 链表(gef 也有 heap bins,功能略弱);验证: gdb 里 heap bins 有输出checksec(见 [[re-pwn]] 工具准备)pip install angr——Python 版本兼容性以 [[re-angr]] 的「工具准备」为准(版本矩阵只在该处维护一份,避免两处漂移)python3 -c "import angr; print(angr.__version__)"按顺序执行;每步产物(利用面结论、gadget 清单、链布局、PoC)记录证据路径 + sha256(存证方法见 [[re-triage]]),供报告引用。
利用面分析(崩溃点 / 可控数据):
cyclic 定位崩溃时 rip 偏移,见 [[re-pwn]] 步骤 2)pwn checksec --file ./target:NX / PIE / Canary / RELRO——每项决定一条限制:栈不可执行 → 不能直接跑 shellcode;PIE → 地址要泄露 base;RELRO full → GOT 不可写(改函数指针 / 栈地址 / libc 钩子替代)seccomp-tools dump ./target(Gem: gem install seccomp-tools,官方途径;Arch 官方仓库无此包——仅 AUR 有 seccomp-tools,直接用 gem 即可)或静态找 prctl / seccomp 调用——若禁 execve 则拿 shell 路线作废,改 ORW 链(步骤 4)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 跳板
padding + pop_rdi_ret + arg1 + func_addr + [对齐 ret] + 下一段...__libc_csu_init 里的 pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; ret + 搬运 mov 段)或 ret2dlresolvecall 时 $rsp % 16 == 0 才满足 movaps(glibc 新版本 system/printf 内部会用),不对齐在 gadget 链前补一个 ret堆利用(fastbin / tcache 攻击模式):
ldd ./target | grep libc)决定攻击面(坑 3):
fd 到目标地址附近 → 下一次分配拿到任意地址(2.32+ 指针被 safe-linking 异或,坑 3);UAF 直接改 fd 更快show/格式化读泄露 libc base(libc_base = leaked - main_arena_offset)(gdb) heap # 看 chunk 布局与地址
(gdb) bins # 看各 bin 链表(tcachebins/fastbins/unsorted)
__free_hook(≤2.33)/ __malloc_hook / GOT 可写项 / 栈返回地址 → 触发 get shell 或任意读写沙箱 / 缓解绕过(seccomp):
execve:ORW 链——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 构造寄存器帧)\x00 可直接截断处理);RELRO full → 不打 GOT,改栈 / __free_hook / environ 泄栈地址PoC 验证:
from pwn import *
context.binary = './target'; context.log_level = 'debug'
p = process('./target') # 沙箱内本地;远程: remote(host, port)
p.sendline(payload)
p.interactive()
si 确认跳转与栈布局与用户态同框架:fuzz([[re-fuzzing]])→ crash([[re-crash-triage]])→ 利用(本路径)。
heap/bins);[[re-binary-core]] 底座定位原语与后门objdump 出的 gadget / 函数地址)写链,本地偶发成功远程必挂,或泄露后算出的 base 对不上;原因——PIE 开启时二进制基址随 ASLR 变化(低 12 位页内偏移不变),libc 基址同理;静态地址只在无 PIE(或已算 base)时成立;对策——泄漏为先:第一段链先泄露(puts/printf 打 GOT 或堆/格式化泄露),libc_base = leaked - offset、binary_base = leaked - offset,后续所有 gadget/函数地址 = base + 静态偏移(低 12 位直接拼);每次泄露后重新计算再发覆盖段,别复用上一轮的 basemalloc(): 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 不触发)__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)列检查清单逐步验证si;每改一步先确认上一步仍通system 或 printf 就段错误,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 函数调用前都按此检查