npx skills add ...
npx skills add yaklang/hack-skills --skill arbitrary-write-to-rce
Arbitrary write to RCE playbook. Use when you have an arbitrary write primitive (from heap exploitation, format string, or OOB write) and need to convert it into code execution by targeting GOT, hooks, _IO_FILE vtable, exit_funcs, TLS_dtor_list, modprobe_path, .fini_array, or C++ vtables.
npx skills add yaklang/hack-skills --skill arbitrary-write-to-rce
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.
| 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 |
__malloc_hook | OK | OK | Removed | libc base |
__free_hook | OK | OK | Removed | libc base |
__realloc_hook | OK | OK | Removed | libc base |
_IO_FILE vtable (direct) | OK | Vtable range check | Vtable range check | libc base + heap |
_IO_FILE via _IO_str_jumps | N/A | OK (2.24–2.27) | Patched | libc base + heap |
_IO_FILE via _IO_wfile_jumps | N/A | OK (≥ 2.28) | OK | libc base + heap |
__exit_funcs | OK | OK | OK | libc base + pointer guard |
TLS_dtor_list | N/A | N/A | OK | TLS addr + pointer guard |
_dl_fini / link_map | OK | OK | OK | ld.so base |
modprobe_path (kernel) | OK | OK | OK | Kernel base |
.fini_array | OK | OK | OK | Binary base (if writable) |
| C++ vtable | OK | OK | OK | Object address + heap |
setcontext gadget | OK | OK (changed in 2.29) | OK | libc base |
| Stack return address | Always | Always | Always | Stack address |
Replace a function pointer in the Global Offset Table.
.got.plt writable) — Full RELRO blocks this entirely| Overwrite From | Overwrite To | Trigger |
|---|---|---|
printf@GOT | system | Next printf(user_input) with input = /bin/sh |
free@GOT | system | Next free(ptr) where ptr points to "/bin/sh" |
strlen@GOT | system | Next strlen(user_input) |
atoi@GOT | system | Next atoi(user_input) with input = "sh" |
puts@GOT | system | Next puts(user_input) |
exit@GOT | main or gadget | Create loop for multi-shot exploit |
__stack_chk_fail@GOT | ret gadget | Neutralize canary check |
See IO_FILE_EXPLOITATION.md for full details.
| glibc | Method | Vtable Target |
|---|---|---|
| < 2.24 | Direct vtable overwrite | Point vtable to fake table with system at __overflow offset |
| 2.24–2.27 | _IO_str_jumps | Within valid range; _IO_str_finish calls _s._free_buffer |
| ≥ 2.28 | _IO_wfile_jumps | Wide-char path: _wide_data->_wide_vtable not range-checked |
| ≥ 2.35 | House of Cat | _IO_wfile_seekoff → _IO_switch_to_wget_mode → fake wide vtable call |
If you can overwrite both the function pointer AND the pointer guard (in TLS at fs:[0x30]):
ROL(target, 0x11)ROR(stored, 0x11) ^ 0 = ROR(ROL(target, 0x11), 0x11) = targetThread-local destructor list — the primary post-2.34 target.
During exit(), _dl_fini iterates the link_map list and calls DT_FINI_ARRAY entries.
link_map entry's l_addr (relocation base) to shift the FINI_ARRAY pointerl_info[DT_FINI_ARRAY] to point to fake arrayexit() → _dl_fini → calls fake destructorAdvantage: No pointer mangling (function pointers in FINI_ARRAY are not mangled).
Overwrite the kernel's modprobe_path to execute arbitrary commands as root.
See kernel-exploitation for kernel write primitives.
Overwrite destructor function pointers called during normal program exit.
Limitation: .fini_array may be read-only in Full RELRO binaries.
setcontext in libc loads registers from a ucontext_t structure — useful as a pivot gadget.