Stack Exploitation Development
Goal: turn a stack bug into the right primitive for that ABI and mitigation set, not into reflex shellcode or nostalgic SEH.
When to activate
- Linear stack overflow, off-by-one, saved-frame-pointer corruption, partial return overwrite, VLA/
allocamisuse, format-string-assisted stack corruption, or uninitialized stack leak is in play. - Need mitigation-aware exploit design instead of generic buffer-overflow advice.
- Need to defeat
PIE/ ASLR with a realistic leak-first, partial-overwrite, or retry-model plan instead of guessed bases. - Need to choose between
ret2libc,ret2dlresolve,ret2csu, SROP, stack pivots, JOP/COP/COOP, or data-only outcomes. - Target is Linux, Windows user-mode, or AArch64 user-mode and the exploitability story depends on calling convention, frame layout, or modern CFI.
- A working chain breaks across builds and the real problem is environment classification, not just gadget collection.
If the problem is mostly gadget selection, chain scoring, and ABI-correct ROP assembly, use offensive-coding/rop-development-dev after this skill narrows the route.
First classify the environment
- Identify architecture and ABI
x86-64 SysV: 16-byte alignment, classicret2libc/ PLT / resolver patterns.Windows x64:rcx,rdx,r8,r9+ 32-byte shadow space;/GS, CFG, EHCONT, and hardware shadow stack may dominate exploitability.AArch64:x0-x7args,x30link register, PAC/BTI/ShadowCallStack may shrink backward-edge options.
- Classify the primitive
- linear overflow / partial overwrite
- off-by-one into saved frame state
- format-string-assisted write or leak
- stack disclosure / uninitialized read
- VLA/
alloca/ stack-growth bug
- Decide the capability you actually need
- canary leak
- stack or module leak
- controlled return / LR
- stack pivot
- syscall or API call
- data-only logic corruption
- Map mitigations before choosing the chain
- NX / DEP
- PIE / ASLR
- RELRO
- stack canary / SSP
_FORTIFY_SOURCE- Intel CET shadow stack / IBT
- Windows
/GS, CFG, EHCONT, hardware shadow stack - ARM64 PAC / BTI / ShadowCallStack
- stack-clash protection, seccomp, SUID, sandboxing
Environment-first selection
| Environment | Bias toward | Avoid or de-prioritize |
|---|---|---|
| x86-64 Linux, no canary/no PIE | ret2win, short ret2libc, same-function re-entry |
overbuilt multi-stage ROP |
| x86-64 Linux, NX + PIE/ASLR | leak-first ret2plt -> ret2libc, ret2csu helpers, pivots |
hardcoded absolute offsets |
| x86-64 Linux, no libc leak but dynamic ELF + writable staging | ret2dlresolve |
blind libc guessing |
| x86-64 Linux, sparse gadgets but clean syscall/sigreturn path | SROP, ret2syscall, ORW |
long gadget lottery |
| x86-64 Linux with CET shadow stack / IBT | data-only, valid-target JOP/COP/COOP, non-return redirection | classic RET-chain as default answer |
Windows x64 with /GS + CFG, no shadow stack |
leak-first API-call ROP, partial overwrites, data-only | legacy SEH mindset |
| Windows x64 with shadow stack + EHCONT | data-only, valid CFG/EHCONT routes, COOP | push/ret, blind NtContinue, blind return smashing |
| AArch64 without PAC/BTI | LR overwrite when spilled, pivots, JOP/ROP, SROP if viable | x86-specific gadget assumptions |
| AArch64 with PAC/BTI/ShadowCallStack | authenticated pointer reuse, data-only, legitimate-target abuse | raw LR overwrite or arbitrary indirect branch |
Technique families worth prioritizing
| Family | Good fit | Typical result | Reality check |
|---|---|---|---|
ret2win |
no-PIE or known win target | immediate control-flow win | still great, but mostly a stage-zero luxury |
ret2plt leak |
imported print/write primitive exists | libc or code leak | default stage one on ELF |
ret2libc |
libc base known or leakable | system, execve, ORW, mprotect |
still the Linux baseline when backward-edge CFI is absent |
ret2dlresolve |
dynamic ELF + writable staging | resolve symbol without libc base | strong when leaks are constrained |
ret2csu |
gadget-poor ELF | helper multi-register call setup | helper, not final trophy |
| SROP | sigreturn path + register starvation | one-frame register control | excellent when syscall setup is the real problem |
| saved frame-pointer pivot | off-by-one or short overwrite | move stack into BSS/heap/attacker buffer | often more realistic than RIP-first thinking |
| partial return overwrite | same-page code targets | ASLR-light pivot or function replay | low-byte wins matter |
| BSS / heap pivot | first bug too short for final chain | larger stage-two workspace | prefer the shortest stable second-input route |
| JOP/COP/COOP | CET / CFG / PAC-era targets | valid-target code reuse without raw ret abuse |
more current than forcing ROP through hostile CFI |
| data-only stack corruption | canaries or shadow stacks block control hijack | auth bypass, length/path/callback corruption | often the right hardened-target ending |
| legacy SEH overwrite | 32-bit legacy Windows only | exception redirection | historical branch, not modern default |
Mitigation-driven rules
- Canary / SSP: do not plan a final return smash before you know how the canary is leaked, preserved, or bypassed.
- NX / DEP: shellcode is conditional, not default. Verify executable memory first.
- PIE / ASLR: decide which mapping you need to recover (
PIE/text,libc, stack, heap), then treat leaks as stage one, not optional polish. - RELRO: easy GOT-overwrite endings may vanish; leaks and direct chains do not.
_FORTIFY_SOURCE:_chkaborts change bug shape and timing, but they do not magically erase leak paths or pre-check corruption.- Intel CET shadow stack: plain return-address corruption usually dies. Stop insisting on RET-only plans when shadow stack is real.
- CET IBT / BTI / CFG: indirect targets must be valid targets, not random gadgets.
- Windows
/GS: protects selected functions and some vulnerable parameters, not every data-only route. - Windows EHCONT: blind
NtContinue/RtlRestoreContextabuse is outdated unless the target build genuinely permits it. - ARM64 PAC: raw forged pointers are lower-probability than signed-pointer reuse or non-return targets.
- ShadowCallStack / hardware shadow stacks: backward-edge hijack becomes the expensive branch; consider forward-edge or data-only outcomes first.
- stack-clash protection: large
alloca/VLA leaps are compiler- and target-sensitive; validate actual probing behavior.
Endgame selection
- No NX and truly executable stack: shellcode is fine, but only after verification.
- NX + libc leak: prefer
ret2libc, syscall chains, or short ORW. - No libc leak but dynamic loader path exists:
ret2dlresolve. - Sparse gadgets but sigreturn reachable: SROP.
- CET / CFG / PAC / shadow stacks dominate: bias toward data-only, JOP/COP/COOP, valid-target abuse, or authenticated-pointer reuse.
- Windows: API-call ROP or data-only object/policy corruption, not legacy SEH nostalgia.
- SUID / seccomp: choose credential-safe
execve, ORW, or allowed-syscall paths oversystem("/bin/sh")reflexes.
Reliability checklist
- Confirm exact ABI, stack alignment needs, and whether a frame pointer exists.
- Find the true overwrite offset with evidence, not guesswork.
- Separate leak acquisition, pivot/control primitive, and endgame.
- Track bad characters, encodings, and input transforms before choosing a pivot or frame format.
- Rerun under randomized layouts and slightly different heap/stack schedules.
- Keep a data-only fallback if backward-edge control becomes too expensive.
Anti-patterns
- Recommending stack shellcode on NX/DEP targets by reflex.
- Treating canary brute force as a normal first choice outside fork/respawn models.
- Forcing classic ROP through CET, shadow stack, PAC, or EHCONT when the target is telling you to pivot.
- Treating 32-bit SEH writeups as modern Windows x64 guidance.
- Ignoring compiler/runtime hardening bundles and reasoning from one mitigation at a time.
Resources
references/
- references/linux-techniques.md — load for Linux route selection,
ret2libc/ret2dlresolve/ SROP / pivot trade-offs. - references/aslr-bypass.md — load for leak-first routing,
ret2plt/ret2main, PIE/text-base leaks,ret2dlresolve, low-byte wins, libc fingerprinting, and brute-force economics. - references/mitigations-and-selection.md — load when mitigations, compiler flags, or runtime hardening are the main decision point.
- references/windows-techniques.md — load for
/GS, CFG, EHCONT, hardware shadow stack, and realistic Windows user-mode routes. - references/arm64-and-modern-cfi.md — load for AArch64 ABI facts, PAC/BTI, ShadowCallStack, and modern CFI-aware selection.
- references/leaks-pivots-and-partials.md — load for canary leaks, partial overwrites,
leave; ret, stage-two pivots, and non-control-data stack wins. - Upstream methodology:
offensive-techniques/binary-exploitation-technique(primitive→impact strategy, mitigation selection) andoffensive-ctf/pwn-ctf/references/overflow.md(concrete recipes).
Load references only after architecture, primitive, and mitigation set are clear. Keep SKILL.md as the router; keep the depth in the references.