pwn ctf hints
spoiler-free hints for binary exploitation challenges.
buffer overflow · ROP chains · heap exploitation · format string · ret2libc · ASLR/PIE bypass
what pwn ctf challenges look like
pwn challenges give you a binary (usually ELF) and a remote service running that same binary. the goal is to exploit a vulnerability to gain code execution and read the flag. start by checking protections with checksec, then reverse the binary in Ghidra or GDB to find vulnerabilities.
common pwn challenge types
- stack buffer overflowinput exceeds a fixed-size buffer on the stack, overwriting the return address. find the offset to RIP/EIP using a cyclic pattern, then redirect to your payload.
- ret2libcno NX stack, or NX is on so you can't run shellcode directly — ROP to leak a libc address, calculate base, then call system("/bin/sh").
- ROP chainno executable stack — chain together small "gadgets" (existing code ending in ret) to call functions or set registers.
- format stringprintf(user_input) without a format string — use %p to leak stack values, %n to write arbitrary memory. find the offset to the return address or GOT entry.
- heap — use after freea freed chunk is used again — overwrite the freed object's vtable or function pointer before it's reused.
- heap — double freefreeing the same chunk twice corrupts the allocator's free list — leads to arbitrary write in older glibc versions.
- heap — fastbin duptcache/fastbin attack — corrupt the fd pointer of a freed chunk to allocate over a target like __malloc_hook.
useful tools
pwntools for scripting exploits · GDB with pwndbg or peda for dynamic analysis · Ghidra / IDA / Binary Ninja for static analysis · ROPgadget or ropper for finding gadgets · checksec to audit binary protections · patchelf to swap libc versions.
faq
what is the first thing to check on a pwn binary?+
run checksec to see NX, PIE, canary, and RELRO. those protections dictate the approach: a missing stack canary opens a straight buffer overflow, while a full set pushes you toward a ROP chain and a libc leak. then reverse the binary in Ghidra or GDB to find the actual bug.
how do I find the offset to the return address?+
generate a cyclic pattern (pwntools cyclic or gdb-peda pattern_create), feed it in until the program crashes, then read the value that landed in the crashed register and look it up to get the exact offset to the saved return address.
why does ret2libc work when the stack is not executable?+
you never execute your own code — you reuse libc. leak a libc address (often a GOT entry via puts), subtract the known symbol offset to compute the libc base, then return into system with a pointer to "/bin/sh". matching the exact libc version is what makes the offsets line up.