Memory-corruption exploitation
When it applies
You have a native binary or service on an authorized target that mishandles your input — a
network-facing daemon, a thick-client, a setuid helper found during privesc, or a binary carved
from firmware (reverse-eng-firmware). reverse-eng-binary-triage located the bug; this skill turns
that crash into controlled execution. Pentest-only — this is destructive and can crash the service.
Why it works
C/C++ has no memory safety: writing past a buffer overwrites saved return addresses and pointers, and
a user-controlled format string reads/writes arbitrary memory. Redirect execution to your code or to
existing code (ROP) and the process does your bidding. Modern mitigations (NX, ASLR, PIE, stack
canaries) don't remove the bug — they shape the technique.
Method
- Check protections first —
checksec ./bin (or pwntools): NX, PIE, RELRO, canary. This
decides everything. No canary + NX → ROP; PIE → you need a leak; no PIE, no NX → maybe shellcode.
- Find the offset — send a cyclic pattern (
cyclic 200 / pattern_create), crash it under
gdb+GEF/pwndbg, read the value in $rip/$eip, and cyclic -l <value> for the exact offset to
the saved return address.
- Pick the primitive by protections:
- ret2win — a target function already in the binary; overwrite the return address with it.
- ret2libc / ROP — with NX, chain gadgets: leak a libc address (call
puts(puts@got) via the
PLT), compute the libc base, return to system("/bin/sh") or a one_gadget. Build gadgets with
ROPgadget/ropper, the chain with pwntools ROP().
- Format string (
printf(user)) — leak stack/canary/PIE base with %p, then do arbitrary
writes with %n (GOT overwrite → redirect a call to system). fmtstr_payload automates it.
- Defeat mitigations with leaks — ASLR/PIE need a leaked address (from a format string or an
info-leak bug) to rebase; a stack canary must be leaked (or brute-forced byte-by-byte on a forking
server) and replayed in your overflow so the check passes.
- Build it with pwntools — a repeatable script:
process()/remote(), recvuntil, pack with
p64(), stage the leak, then send the final chain; iterate locally, then fire at the target.
- Land a shell — reuse
payloads-reverse-shells for what to run once you have execution.
Gotchas
- Match the exact libc — remote exploitation fails on the wrong libc version/offsets; identify it
(leaked addresses → a libc-database lookup) before computing
system/one_gadget.
- Bad bytes —
\x00, \x0a, \x20 can truncate input depending on the read function; check and
avoid them in addresses/payload.
- Local works, remote doesn't — environment/stack alignment differs; the
movaps alignment crash
before system is fixed by an extra ret gadget.
- This crashes the target — it's inherently disruptive; only on authorized pentest targets, never
a live bug-bounty production service, and note the risk in the RoE.
Verify success
Reliable control of execution demonstrated on the target — a returned shell, a run command, or a
controlled $rip with a working ROP chain — reproducible from your pwntools script.
References
pwntools docs & tutorials; checksec; GEF/pwndbg; ROPgadget/ropper; one_gadget; libc-database.
Find the bug with reverse-eng-binary-triage; shell payloads in payloads-reverse-shells.
1---2name: exploit-memory-corruption3description: Turn a memory-corruption bug in a native binary into code execution — stack overflows, format strings, and ROP against modern mitigations. Load when you control input to a compiled program and it crashes or misbehaves: a network daemon, a thick client, a setuid/SUID helper, or extracted firmware. Signals: segfault on long/`%n` input, a crash with control of a register, no source, checksec output, "exploit this binary/service".4---56# Memory-corruption exploitation78## When it applies9You have a native binary or service on an authorized target that mishandles your input — a10network-facing daemon, a thick-client, a setuid helper found during `privesc`, or a binary carved11from firmware (`reverse-eng-firmware`). `reverse-eng-binary-triage` located the bug; this skill turns12that crash into controlled execution. Pentest-only — this is destructive and can crash the service.1314## Why it works15C/C++ has no memory safety: writing past a buffer overwrites saved return addresses and pointers, and16a user-controlled format string reads/writes arbitrary memory. Redirect execution to your code or to17existing code (ROP) and the process does your bidding. Modern mitigations (NX, ASLR, PIE, stack18canaries) don't remove the bug — they shape the technique.1920## Method211. **Check protections first** — `checksec ./bin` (or `pwntools`): NX, PIE, RELRO, canary. This22 decides everything. No canary + NX → ROP; PIE → you need a leak; no PIE, no NX → maybe shellcode.232. **Find the offset** — send a cyclic pattern (`cyclic 200` / pattern_create), crash it under24 `gdb`+GEF/pwndbg, read the value in `$rip`/`$eip`, and `cyclic -l <value>` for the exact offset to25 the saved return address.263. **Pick the primitive by protections:**27 - **ret2win** — a target function already in the binary; overwrite the return address with it.28 - **ret2libc / ROP** — with NX, chain gadgets: leak a libc address (call `puts(puts@got)` via the29 PLT), compute the libc base, return to `system("/bin/sh")` or a `one_gadget`. Build gadgets with30 `ROPgadget`/`ropper`, the chain with `pwntools` `ROP()`.31 - **Format string** (`printf(user)`) — leak stack/canary/PIE base with `%p`, then do arbitrary32 writes with `%n` (GOT overwrite → redirect a call to `system`). `fmtstr_payload` automates it.334. **Defeat mitigations with leaks** — ASLR/PIE need a leaked address (from a format string or an34 info-leak bug) to rebase; a stack canary must be leaked (or brute-forced byte-by-byte on a forking35 server) and replayed in your overflow so the check passes.365. **Build it with pwntools** — a repeatable script: `process()`/`remote()`, `recvuntil`, pack with37 `p64()`, stage the leak, then send the final chain; iterate locally, then fire at the target.386. **Land a shell** — reuse `payloads-reverse-shells` for what to run once you have execution.3940## Gotchas41- **Match the exact libc** — remote exploitation fails on the wrong libc version/offsets; identify it42 (leaked addresses → a libc-database lookup) before computing `system`/`one_gadget`.43- **Bad bytes** — `\x00`, `\x0a`, `\x20` can truncate input depending on the read function; check and44 avoid them in addresses/payload.45- **Local works, remote doesn't** — environment/stack alignment differs; the `movaps` alignment crash46 before `system` is fixed by an extra `ret` gadget.47- **This crashes the target** — it's inherently disruptive; only on authorized pentest targets, never48 a live bug-bounty production service, and note the risk in the RoE.4950## Verify success51Reliable control of execution demonstrated on the target — a returned shell, a run command, or a52controlled `$rip` with a working ROP chain — reproducible from your pwntools script.5354## References55pwntools docs & tutorials; `checksec`; GEF/pwndbg; ROPgadget/ropper; `one_gadget`; libc-database.56Find the bug with `reverse-eng-binary-triage`; shell payloads in `payloads-reverse-shells`.