Engineer a reliable exploit from a known memory-corruption bug — stack, heap, or kernel — taking a local crash to a stable remote exploit: ret2libc/ret2csu/one_gadget, tcache/fastbin/unsorted-bin techniques matched to the glibc version, kernel pwn against SMEP/SMAP/KASLR/KPTI, and remote stabilization (libc fingerprinting, stack alignment, recvuntil anchoring, spray sizing). Load when you have binary + bug + target environment and "local works, remote crashes". Signals: pwn, ROP, ret2libc, on...
Installs into .claude/skills of the current project.
Are you the author of Exploit Pwn Chain?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/noorqureshi-exploit-pwn-chain)
---
name: exploit-pwn-chain
description: >
Engineer a reliable exploit from a known memory-corruption bug — stack, heap, or kernel — taking
a local crash to a stable remote exploit: ret2libc/ret2csu/one_gadget, tcache/fastbin/unsorted-bin
techniques matched to the glibc version, kernel pwn against SMEP/SMAP/KASLR/KPTI, and remote
stabilization (libc fingerprinting, stack alignment, recvuntil anchoring, spray sizing). Load when
you have binary + bug + target environment and "local works, remote crashes". Signals: pwn, ROP,
ret2libc, one_gadget, tcache, heap spray, kROP, modprobe_path, pwntools, checksec output.
domain: exploit-dev
type: methodology
stability: learning
modes: [pentest]
severity: critical
mitre: [T1203, T1068]
cwe: [CWE-121, CWE-122, CWE-416, CWE-787]
tools: [pwntools, gef, pwndbg, ropgadget, ropper, one_gadget, libc-database, qemu-system]
schema_version: 1
---
# Pwn chain: bug to working exploit
## When it applies
You already know where it crashes — `reverse-eng-binary-triage` or `exploit-memory-corruption`
found the overflow/UAF/double-free — and now you must produce a *stable* exploit against the real
remote target, not a script that only works on your laptop. Covers userspace stack pwn, glibc heap
exploitation, and Linux kernel/driver pwn (e.g. an ioctl bug for privesc). Pentest-only; note the
crash risk in the RoE (`tradecraft-scope-roe`).
## Why it works
A local win and a remote win differ by engineering, not by the bug: the remote libc version, ASLR
slide, stack alignment, network buffering, and heap layout all shift. The chain is always the same —
model the protections, leak what randomization hides, build the primitive (ROP/poisoned
bin/sprayed object), then iterate against the real environment until the success rate is measured,
not assumed.
## Method
> **Stack / heap / kernel technique reference (templates, glibc version table, spray objects,
> privesc paths):** see [`cheatsheet.md`](cheatsheet.md) next to this file.
1. **Classify bug + protections.** `checksec ./vuln` (NX / canary / PIE / RELRO / FORTIFY) decides
the whole strategy. Bug class: stack overflow / format string / heap (UAF, double-free,
overflow) / integer / race / kernel.
2. **Pick the strategy.** NX off + no ASLR → shellcode. NX + libc provided → ret2libc / one_gadget.
NX + no libc → leak, then libc-database lookup. Heap → technique per glibc version (tcache /
fastbin / unsorted / large bin). Kernel → `commit_creds` ROP, `modprobe_path`, or `core_pattern`.
3. **Stage libc + gadgets.** `./find puts 0x6f0` in libc-database; `ROPgadget --binary ./libc.so.6
--only "pop|ret"`; `one_gadget ./libc.so.6`; base = `leaked - libc.sym['puts']`. Run the target
under the exact remote libc locally:
`patchelf --set-interpreter ./ld-linux-x86-64.so.2 --set-rpath . ./vuln`.
4. **Write the pwntools skeleton.** `context.binary = ELF('./vuln')`; iterate with
`process()` / `gdb.debug('./vuln', 'b *main+xx')`; `cyclic()` / `cyclic_find()` for the offset;
finish at `p.interactive()`.
5. **Make it work locally** — attach, watch registers, tune offsets with pwndbg/GEF
(`vmmap`, `heap`, `bins`, `telescope`), then switch to `remote()`.
6. **Stabilize remotely.** Never guess libc offsets — leak and reverse-lookup. Fix `movaps` stack
alignment with an extra `ret` gadget. Anchor reads with `recvuntil(b'exact marker')`, never
`sleep`; prefer `sendlineafter` over `sendline`. For heap sprays, oversize the spray and leave
padding chunks against consolidation. Then loop the exploit (`while True`) until it succeeds
≥ 95% over 20+ remote runs.
## Gotchas
- **"Local works, remote segfaults in `system`"** — almost always 16-byte stack misalignment
(`movaps xmm0, [rsp]`); add one `ret` gadget. Second cause: wrong libc version — leak first.
- **Heap techniques are glibc-version-locked** — tcache appeared in 2.27, safe-linking in 2.32,
hooks removed in 2.34. Same binary + different libc = completely different exploit path. Check
with `./libc.so.6 | head -1`.
- **Kernel pwn: confirm CPU flags first** — `+smep +smap +pku` in the qemu line (or the real
kernel's config) dictates the ROP chain; KPTI forces the
`swapgs_restore_regs_and_return_to_usermode` trampoline for the return to userland.
- **One KASLR leak is enough** — compute everything as offsets from it; repeated leaking just adds
failure surface.
- **canary on forking servers** — child processes share the canary; brute-force it byte by byte
(1/256 per byte).
- **Static binaries have no GOT** — use SROP or raw syscalls instead of ret2libc.
## Verify success
The exploit runs end-to-end against the real remote target ≥ 95% of the time across 20+ consecutive
runs, from the same pwntools script, with the libc identified by leak — not assumed. A shell (or
root shell, for kernel pwn) that survives reconnection is the proof.
## References
pwntools docs; GEF (bata24 fork for kernel structs) / pwndbg; ROPgadget / ropper; one_gadget;
libc-database. Find the bug with `reverse-eng-binary-triage`; userspace basics in
`exploit-memory-corruption`; post-exploitation via `exploit-chaining` and `payloads-reverse-shells`.
---
_Portions adapted from [reverse-skill](https://github.com/zhaoxuya520/reverse-skill) by zhaoxuya520, MIT License._