CTF Binary Exploitation (Pwn)
Quick reference for binary exploitation (pwn) CTF challenges. Each technique has a one-liner here; see supporting files for full details.
Additional Resources
- overflow-basics.md — stack/global overflow, canary bypass, ret2win
- rop-and-shellcode.md — ret2libc, ret2csu, syscall ROP, exotic gadgets
- rop-advanced.md — SROP, RETF arch-switch, .fini_array, ret2vdso, stack pivot
- format-string.md — fmt leaks, GOT/hook overwrite, blind fmt, argv[0] tricks
- advanced.md — heap/UAF classics (House of Orange/Spirit/Lore), ret2dlresolve, JIT
- advanced-2.md — 2024-26: House of Apple 2 (glibc 2.34+), House of Einherjar, musl meta-pointer
- advanced-exploits.md — 2024 era: GC UAF, VM bugs, FSOP+seccomp, custom sandboxes
- advanced-exploits-2.md — 2024-early-2025: io_uring SQE inj, TLS dtor, MOP, corphone
- advanced-exploits-3.md — 2025-2026: vkfs FS, MIPS $gp, alloca, ObjC, ARM64 PAC, cmp timing
- sandbox-escape.md — custom VM, FUSE/CUSE, busybox/restricted shell
- heap-leakless.md — glibc 2.32-2.39+ leakless (Rust/Water/Tangerine/Corrosion)
- kernel.md — Linux kernel fundamentals, QEMU debug, spray structures
- kernel-techniques.md — tty_struct kROP, SLUB internals, userfaultfd, DiceCTF 2026
- kernel-bypass.md — KASLR/FGKASLR, KPTI, SMEP/SMAP, exploit delivery
- kernel-advanced.md — EntryBleed, SLUBStick, DirtyCred, folly page-aliasing
- brop.md — Blind ROP full chain without binary access
- browser-jit.md — V8/SpiderMonkey/JSC JIT type-confusion, sandbox bypass, OSR-exit
- rust-pwn.md — Rust unwind drop, transmute, set_len uninit, async state confusion
Pattern Recognition Index
Map observable signals (not challenge names) to the right technique. Scan this first when you're handed a binary and a remote.
| Signal observed in binary / source | Technique → file |
|---|---|
checksec: NX but no canary, stack buffer + read/gets |
Plain stack overflow → overflow-basics.md |
Canary + forking server (pre-fork accept loop) |
Byte-by-byte canary brute-force → overflow-basics.md |
int/ssize_t length → read(fd, buf, len) with only len > MAX check |
Signed→size_t confusion → advanced-exploits-2.md |
printf(user_ptr) with no format string |
Format-string leak + GOT overwrite → format-string.md |
| glibc 2.32+ tcache with Safe-Linking; no leaks possible | House of Rust / Water → heap-leakless.md |
glibc 2.39+, no free() primitive exposed |
House of Tangerine (malloc-only AAW) → heap-leakless.md |
mmap(MAP_FIXED) exposed with controllable addr, prot |
MOP — libc code-page zeroing → advanced-exploits-3.md |
| Fork/clone + tiny shared-mem handshake validating input char-by-char | strace byte-count side-channel → advanced-exploits-2.md |
Kernel chall, unpriv userns, splice()/vmsplice() + large kmalloc free |
Pipe-backed folio_put page-UAF → advanced-exploits-3.md |
Container with custom bind-mounts on /dev, /proc under runc ≤ 1.1.x |
runc 2025 symlink-race escape → advanced-exploits-3.md |
| Unicorn/QEMU sandbox with host-side helper reads | Host/guest hook divergence → advanced-exploits-3.md |
| Kernel io_uring SQE reachable via UAF / type confusion | io_uring worker abuse → kernel-advanced.md, advanced-exploits-2.md |
| KASLR + Linux ≥ 5.8 + prefetch available | EntryBleed → kernel-advanced.md |
| Windows driver IOCTL + NT kernel | PreviousMode / token stealing → kernel-advanced.md, advanced-exploits-2.md |
| No binary given, remote only, forking server with long timeout | Blind ROP (BROP) → brop.md |
seccomp filter blocking execve, open/read/write allowed |
ORW ROP → rop-and-shellcode.md, rop-advanced.md |
MIPS ELF + overflow reachable + $gp loadable from writable region |
$gp-pivot fake-GOT → advanced-exploits-3.md |
Custom FS with (mip,x,y)-style path tuples + SHA256 hashing |
Coord-indexed FS overflow → advanced-exploits-3.md |
| Format-string read + later FILE* UAF in same binary | FILE UAF + fstr bridge → advanced-exploits-3.md |
pthread + user-controlled alloca(n) + shutdown(fd, SHUT_WR) |
Cross-thread alloca smash + partial-close leak → advanced-exploits-3.md |
libobjc linked + tcache-sized free followed by objc_msgSend |
Isa-pointer UAF dispatch hijack → advanced-exploits-3.md |
aarch64 kernel mod + paciza/autiza + IOCTL sizeof bound |
ARM64 PAC-key exfil via bounds-mismatch AAR → advanced-exploits-3.md |
seccomp kills write/socket + /usr/bin/cmp reachable + /flag readable |
cmp timing oracle → advanced-exploits-3.md |
| C++ pwn with vtable dispatch + 0x110/0x480 chunk sizes | House of Spirit via C++ vtable → advanced-exploits.md |
SPLICE_F_GIFT / MSG_ZEROCOPY / TCP_ZEROCOPY_RECEIVE in proxy |
Zero-copy page aliasing TOCTOU → kernel-advanced.md |
seccomp allows io_uring_* only, kernel ≥ 6.1 |
IORING_SETUP_NO_MMAP escape → sandbox-escape.md |
| Sandboxed proc can recv from helper via AF_UNIX | SCM_RIGHTS fd smuggling → sandbox-escape.md |
setuid binary scrubs secret after read, coredumps reachable |
Coredump race → sandbox-escape.md |
| Non-standard eBPF prog on kprobe, flag gated by global state | eBPF FSM syscall-sequence → sandbox-escape.md |
| Traefik ≤ 2.11.13 front + Flask/Node admin routes | X-Forwarded-* reach → polyglot chain → advanced-exploits-3.md |
d8 / js / jsc binary + *.patch modifying JIT compiler sources |
JIT type confusion → browser-jit.md |
V8 build with v8_enable_sandbox=true; primitive only inside cage |
ExternalPointerTable bypass → browser-jit.md |
Turbofan typer patch touching Type::Range / Type::OtherNumber |
Range-analysis type confusion → browser-jit.md |
IonMonkey RangeAnalysis.cpp diff or JSC DFGSpeculativeJIT.cpp diff |
OSR-exit / range bug → browser-jit.md |
| Rust panic caught + recovered with unsafe state between | Unwind-path Drop corruption → rust-pwn.md |
mem::transmute / slice::from_raw_parts_mut on user-controlled len |
Sliced-length OOB → rust-pwn.md |
Vec::reserve(n) + set_len(n) without n writes |
Uninitialised-drop vtable hijack → rust-pwn.md |
as u32 / as usize on subtraction result in release build |
Truncation overflow → rust-pwn.md |
async fn with Pin<&mut Self> across .await + raw-ptr aliasing |
Future state-machine confusion → rust-pwn.md |
unprivileged_bpf_disabled=0 + kernel 5.13-6.5 + bpf_prog_load reachable |
eBPF verifier pointer-arith bypass → kernel-advanced.md |
BPF_MAP_TYPE_RINGBUF + kernel < 5.15 |
Ringbuf stale-byte KASLR leak → kernel-advanced.md |
Recognize the mechanic first. The challenge title is never the signal.
For inline code/cheatsheet quick references (grep patterns, one-liners, common payloads), see quickref.md. The Pattern Recognition Index above is the dispatch table — always consult it first; load quickref.md only if you need a concrete snippet after dispatch.