Skip to main content

July 10, 2026

The picoCTF Binary Exploitation Roadmap: Stack to Heap to ROP

How to learn binary exploitation for CTF in order: a beginner-to-advanced pwn roadmap from x86 assembly and gdb through stack smashing, mitigations, ROP, and heap.

Five stepped platforms rising left to right, each carrying a progressively more intricate object.

The order to learn binary exploitation, in one paragraph

Learn pwn in this order: first the substrate (x86 assembly, gdb, pwntools), then the first bug class (stack buffer overflow, shellcode, format string), then the defenses that stop the naive version (stack canary bypass, ASLR and PIE bypass), then code reuse when the stack is non-executable (ret2libc, ROP without a libc leak, SROP and ret2dlresolve), and finally the harder allocator bugs (heap exploitation, use-after-free). That sequence is not arbitrary. Each tier removes an assumption the previous tier relied on.

Key insight: The decision rule for any new binary: run checksec ./vuln first. The mitigations it reports tell you which technique to study. No canary plus a writable stack means plain overflow into shellcode. Canary present means you need a leak before the overflow matters. NX (No-eXecute stack) on means shellcode is dead and you climb into ROP. PIE on means you need an address leak before any hardcoded gadget works. Full RELRO closes the GOT-overwrite and ret2dlresolve doors. You do not pick a technique by taste; the binary's defenses pick it for you.

This page is a map, not a lesson. Every link below goes to a full writeup on this site that teaches the technique with code. Read this page to know what to read next and why, then follow the link when you are ready to go deep. If you are brand new, do not skip the foundations tier. Most people who bounce off pwn bounced because they tried to read an exploit before they could read disassembly.

The path in order

Five tiers, easy to hard. Each step names the post that teaches it, the one thing it teaches, and the moment you actually need it. Work top to bottom. Do not jump to the heap before you can land a stack overflow in your sleep.

TierWhat it removesPosts
1. FoundationsYour inability to read what the CPU is doingassembly, gdb, pwntools
2. Stack smashingThe assumption that input stays inside its bufferoverflow, shellcode, format string
3. MitigationsThe defenses that block the naive overflowcanary bypass, ASLR/PIE bypass
4. Return-orientedThe need for an executable stack at allret2libc, ROP without libc, SROP/ret2dlresolve
5. HeapThe assumption that the bug lives on the stackheap exploitation, use-after-free

Tier 1: Foundations (do not skip these)

You cannot exploit a binary you cannot read. This tier is the alphabet. Spend real time here; everything downstream assumes you can disassemble a function, set a breakpoint, and script the I/O.

The alphabet is short and written down. The System V AMD64 ABI fixes the six argument registers (rdi, rsi, rdx, rcx, r8, r9), the 16-byte stack alignment required at every call, and the frame layout that puts the return address at %rbp+8. The ELF specification explains the sections and program headers that checksec reports on. Read those two documents once and most of this roadmap becomes recall rather than research.

  1. x86 assembly for CTF teaches registers, the calling convention, and how the stack frame is laid out. You need it the moment you open a disassembler and see push rbp ; mov rbp, rsp and want to know what it means.
  2. The gdb CTF guide teaches you to watch registers and memory while the program runs. You need it the first time a payload crashes and you have to find out which gadget died.
  3. pwntools for CTF teaches you to script the connection, pack addresses, and build payloads in Python. You need it the instant you stop pasting bytes by hand, which should be immediately.
  4. Integer overflow and signedness bugs teaches where a wrong length comes from in the first place. Every tier below starts at the point where a size is already too big or already negative; this is the tier that explains how it got that way, and it is the cheapest bug class to learn.
Note: A reasonable bar before leaving this tier: open any small binary, find main in gdb, set a breakpoint, step to a call, and read the arguments out of the registers. If that is comfortable, move on.

Tier 2: Stack smashing (your first shells)

Now you cause your first crash on purpose, then turn it into control. This is where binary exploitation finally feels like exploitation.

  1. Buffer overflow teaches the core primitive: write past a buffer, overwrite the saved return address, and redirect execution. Every later technique is a variation on owning rip. Learn this one cold.
  2. x86-64 shellcode teaches what to point that return address at when the stack is executable: your own bytes that call execve("/bin/sh"). You need it whenever NX is off or the challenge hands you an mprotect or a known executable region.
  3. Format string teaches a second, separate bug class: an attacker-controlled printf format gives you an arbitrary read and an arbitrary write. You need it both to leak (canaries, libc, the stack) and to write (GOT entries, return addresses), which makes it the Swiss-army primitive of the whole roadmap.
Tip: Format string is worth learning early even though it feels like a detour. Its arbitrary read is the cleanest way to defeat the very next tier's defenses: you leak the canary and the PIE base with one bug, then overflow with the leak in hand.

Tier 3: Mitigations (why your overflow stopped working)

Modern binaries fight back. The same overflow that popped a shell on a training binary now gets caught or lands at the wrong address. This tier is about defeating two specific defenses, and it is the tier where checksec becomes your first command every time.

  1. Stack canary bypass teaches you to handle the random guard value the compiler places before the return address. You need it the moment checksec says Canary: found and your overflow dies with stack smashing detected. The fix is almost always: leak the canary first, then include it unchanged in your payload.
  2. ASLR and PIE bypass teaches you to deal with randomized load addresses. You need it when no hardcoded address is stable across runs. The move is to leak one real address, compute the base by subtraction, and rebase every gadget off it.
A mitigation is not a wall. It is a precondition. Each one says "you may not proceed until you have leaked X," and the leak is usually a different bug than the one you finish with.

Tier 4: Return-oriented programming (when the stack is not executable)

With NX on, your shellcode never runs. Instead you reuse code that is already executable: stitch together existing instruction snippets that each end in ret. This is the deepest tier in pure stack exploitation, and it has its own internal ladder.

  1. ret2libc teaches the workhorse: leak a libc address, rebase, and call system("/bin/sh") straight out of the library. Start here. It is the default whenever a leak is available and it carries you through most CTF pwn.
  2. ROP without a libc leak teaches what to do when ret2libc's precondition fails: no leak, a static binary, or Full RELRO. It covers ret2plt, ret2syscall, ret2csu, and stack pivots. You need it the day a binary refuses to give you a libc address.
  3. SROP and ret2dlresolve teaches two advanced moves for minimal-gadget targets: forge a signal frame to set every register at once, or fake a relocation entry so the dynamic linker resolves system for you. You need these when the gadget set is deliberately starved.
Warning: Do not start tier 4 at ROP without libc or SROP. Those exist to solve problems that only appear once ret2libc fails, and you will not recognize the problem until you have felt it. Get one clean ret2libc shell first.

Tier 5: Heap (the bug is not on the stack anymore)

The final tier moves the bug off the stack and into the dynamic allocator. The mental model is completely different: you are no longer overwriting return addresses, you are corrupting allocator metadata and the pointers programs keep to heap objects. This is the steepest jump on the roadmap, which is why it is last.

  1. Heap exploitation teaches how malloc and free manage chunks and bins, and how corrupting that bookkeeping turns into a write primitive. You need it the first time a challenge is built around an allocator instead of a stack buffer.
  2. Use-after-free teaches the most common heap bug in practice: a pointer kept and used after its chunk was freed, letting you reallocate that memory and control what the stale pointer reads or calls. You need it for any menu-driven binary that frees without nulling.
Note: Heap technique is glibc-version-sensitive in a way stack technique is not. The exact bin and check behavior changes between glibc releases, so always confirm which version the target ships before you reach for a specific primitive.

Where to practice on this site, easy to hard

Reading is not solving. Here are picoCTF challenges on this site that exercise the roadmap in roughly increasing difficulty. Do them in order and you will hit each tier in the same sequence you read it.

  • picoCTF 2024 heap 0 is the gentlest possible introduction to the heap. It shows that an out-of-bounds heap write reaches a neighbor, before any allocator-metadata corruption is needed. Despite the name, it is a great early warm-up for the idea that the heap is just memory.
  • picoCTF 2022 ropfu forces a syscall-style ROP chain with no win function. Best on-site practice for tier 4 without a libc leak.
  • picoCTF 2024 format string 3 is a focused tier-2 format string that pushes you into using the arbitrary write, the primitive you will lean on to defeat mitigations.
  • picoCTF 2025 PIE TIME 2 is the tier-3 leak-and-rebase loop in isolation: defeat PIE by leaking an address and computing the base.
  • picoCTF 2025 handoff combines a tiny overflow window with a stack pivot into shellcode, bridging tiers 2 and 4.
  • picoCTF 2021 unsubscriptions are free is a clean use-after-free with a function-pointer hijack: the tier-5 capstone of this list.

How the pieces fit

Key insight: Real exploits stack the tiers. A single challenge can be a format-string leak (tier 2) to beat a canary and PIE (tier 3), feeding a ROP chain (tier 4) that calls into libc. The tiers are not stages you graduate out of; they are a vocabulary you compose. The reason to learn them in order is that each one only makes sense once you have felt the limit of the one before it. The canary post is meaningless until an overflow has died on you. ret2libc is meaningless until NX has killed your shellcode. Heap is meaningless until you are bored of the stack.

Keep checksec as your compass the entire way. It is the single command that tells you which tier a given binary lives in, and therefore which post to reread before you start typing.

Quick reference

checksec output, mapped to the post you need

If you are starting today

Read assembly, gdb, and pwntools this week. Solve heap 0 and a basic overflow next week. Do not touch the heap proper or SROP until ret2libc is automatic. The order is the whole point.

Binary exploitation is not a pile of tricks; it is a ladder where each rung is the answer to the wall the last rung hit, so learn it in order and let checksec tell you which rung you are on. The dates make the ladder literal: the stack overflow was documented in 1996, NX shipped in 2004, ROP answered NX in 2007, and ASLR plus PIE became the default through the 2010s. Each rung is a decade of the same argument.

Sources and further reading

The primary literature for this category is short, and reading it in the same order as the ladder is the fastest way to understand why each mitigation exists.

Run it in the browser

Tools on this site that do the work described above. No install, nothing uploaded: they run entirely in your browser.

Try it on these picoCTF challenges

Walkthroughs that put this technique to work, grouped by event.

Keep reading

Guides that build on the same ideas, plus the roadmap this topic sits under.