Bypassing ASLR, DEP, Shadow Stacks, and Defeating Control Flow Guard in Modern Binaries
Security Architecture Takeaway
Modern memory corruption is an arms race between mitigation technologies (ASLR, DEP, CET Shadow Stacks) and exploitation primitives (ROP, JOP, COP). Bypassing modern defenses requires turning information disclosures into arbitrary read/write primitives.
Empirical Threat & Architecture Analysis: Defensive Mitigations vs. Adversarial Bypass Strategies
| Security Mitigation | Intended Protection Mechanism | Adversarial Bypass Technique |
|---|---|---|
| DEP / NX (Data Execution Prevention) | Marks stack and heap pages as non-executable | Return-Oriented Programming (ROP) using executable code gadgets |
| ASLR (Address Space Layout Randomization) | Randomizes base addresses of stack, heap, and libraries | Information leak via uninitialized memory or format strings |
| Stack Canaries | Places random integer before return pointer | Canary leaking or overwriting SEH / function pointers before return |
| Intel CET Shadow Stack | Hardware-enforced return address stack | Data-Only Attacks (DOP) altering critical variable flags without hijacking RIP |
| Control Flow Guard (CFG / Clang CFI) | Validates indirect call targets against bitmap | Invoking legal export targets with controlled arguments or JOP gadgetry |
1. The Anatomy of Modern Stack-Based Vulnerabilities
The era of simple `strcpy` buffer overflows jumping directly onto shellcode in the stack ended with the widespread deployment of Data Execution Prevention (DEP/NX). Modern binary exploitation requires constructing Return-Oriented Programming (ROP) chains. An attacker searches existing executable pages (such as `libc` or `ntdll`) for instruction sequences ending in a `ret` opcode (`0xC3`). By arranging gadget addresses on the stack, the attacker chains sequences together to call `mprotect()` or `VirtualProtect()`, flipping shellcode pages to `PAGE_EXECUTE_READWRITE`.2. Bypassing ASLR via Memory Disclosure Leaks
Address Space Layout Randomization (ASLR) randomizes memory base offsets upon execution. To deploy a functional ROP chain, an attacker must first defeat ASLR by discovering the base address of a loaded module. This is achieved via information disclosure primitives:// Example format string memory leak exploitation
char buffer[128];
// Vulnerable print call without format specifier
printf(user_supplied_input);
// Exploit string: "%p %p %p %p %p %p"
// Leaks saved base pointers, libc return addresses, and stack canaries!
By calculating the fixed offset between the leaked function pointer and the module base (`Module_Base = Leaked_Addr - Function_Offset`), the entire address space is de-randomized in memory.