Introduction to exploit development - Epilogue

Nov 4, 2025

The end

Throughout this series, we explored the fundamentals of binary exploitation on Linux systems, working with both x86 and ARM architectures. We started with deliberately vulnerable lab environments, progressed through stack-based buffer overflows, developed position-independent shellcode, and concluded with heap exploitation techniques. Each component we examined (memory layout, calling conventions, dynamic linking, GOT/PLT) represents a layer in the complex machinery that enables modern computing - and when misused or corrupted, enables arbitrary code execution.

By working at the assembly level and manually crafting exploits, you hopefully gained some understanding of why these vulnerabilities exist and how they actually work at the machine instruction level. We also got to pop some shells using our very own shellcode, with the knowing of exactly which bytes corrupted which memory locations to achieve this. Pretty neat!

To recap, in this series we covered:

  • Part 1: Lab setup: Configuring vulnerable x86 and ARM environments for exploit development research using QEMU virtualization and physical hardware
  • Part 2: Stack overflows: Understanding memory layout, stack frames, and the mechanics of buffer overflow vulnerabilities that enable control flow hijacking
  • Part 3: Shellcode: Writing position-independent shellcode, NOP sleds, and Return-Oriented Programming techniques for both architectures
  • Part 4: Heap overflows: Heap memory allocation mechanics, Global Offset Table manipulation, and function pointer overwriting

What we didn't cover

The techniques presented here are foundational, but binary exploitation extends far beyond stack and heap overflows. Modern exploitation requires understanding defenses and bypass techniques we only briefly mentioned:

ASLR bypass techniques: Address Space Layout Randomization makes hardcoded addresses unreliable. Information leaks (format string vulnerabilities, uninitialized memory disclosure) may reveal randomized addresses at runtime, but even then things are way more complicated. Understanding what ASLR does and doesn't randomize, as well as how to adjust values based on whatever information you can find, is critical for modern exploitation.

Stack canary bypass: Stack canaries detect buffer overflows before they redirect control flow. However, canaries can be leaked through format strings, brute-forced byte-by-byte on forking servers, or bypassed entirely by corrupting other targets (exception handlers, function pointers). The canary is a speed bump, not a wall - but it will definitely slow you down, that's for sure.

Format string vulnerabilities: Format string bugs (printf(user_input)) enable both information disclosure (reading stack memory) and arbitrary writes (using %n specifier). These are particularly powerful because they provide both the leak primitive needed to defeat ASLR and the write primitive needed for exploitation.

Integer overflow exploitation: Integer overflows in size calculations lead to undersized allocations and subsequent buffer overflows. Catching these requires understanding C's type rules and how signed/unsigned arithmetic differs. The bug is often far removed from the actual vulnerable memory operation, so a keen eye is needed.

Use-after-free (UAF): Accessing freed memory is a temporal memory error distinct from spatial errors (buffer overflows). UAF vulnerabilities require understanding allocator behavior - how memory is reused, what data structures occupy freed chunks, and how to trigger allocation patterns that place attacker-controlled data in previously freed regions.

Return-Oriented Programming (advanced): We covered basic ret2libc, but modern ROP involves chaining dozens of gadgets to achieve complex functionality - syscall invocation, memory mapping, shellcode bootstrapping. Automation tools (ROPgadget, ropper, pwntools) are typically used for practical ROP exploitation.

Kernel exploitation: Everything we covered targeted userspace. Kernel vulnerabilities provide complete system compromise, but require understanding kernel memory layout, kernel stacks, interrupt handling, and privilege separation mechanisms. The techniques are similar (memory corruption to control flow hijacking), but the environment is far less forgiving (easy as heck to crash the entire system).

ARM-specific techniques: We touched on ARM basics, but modern ARM systems use additional security features (Pointer Authentication Codes, Branch Target Identification, Memory Tagging Extension) that complicate exploitation. Understanding ARMv8-A architecture and its security extensions is increasingly important as ARM adoption grows.

...and probably a lot more.

Final thoughts

This series originated from undergraduate coursework in exploit development, subsequently adapted and expanded for this blog. The material represents a snapshot of fundamental techniques, deliberately focused on basics rather than cutting-edge research. Modern exploitation has evolved significantly - defenses are stronger, attack surfaces are more complex.

However, fundamentals remain relevant. Memory is still memory, stacks still grow downward (usually), and strcpy() still doesn't check bounds. Understanding why gets() is dangerous still matters. The mechanics of stack frames, calling conventions, and dynamic linking still underpin everything we build on top.

The dual-architecture approach (x86 and ARM) was intentional. Security research increasingly requires multi-architecture thinking as ARM proliferates (mobile, embedded, server, Apple systems). The differences between architectures (calling conventions, instruction encodings, register usage) matter for exploitation. Understanding both provides flexibility for approaching new architectures (RISC-V 0_0).

Understanding how to break systems and how to defend them makes you a more effective practitioner regardless of whether you pursue offensive or defensive security (or are just a meager software engineer like me).

The journey doesn't end here. It's just beginning. Below you'll find links to some resources for future learning.

References and further reading

Books:

Online resources:

Tools:

  • radare2 - Open-source reverse engineering framework
  • pwntools - Python library for exploit development
  • GEF - GDB Enhanced Features for exploit development
  • Ghidra - NSA's reverse engineering framework (free)
  • IDA Pro - Industry-standard disassembler (expensive, free version available)
https://betweenlayers.io/posts/feed.xml