Skill v1.0.0
currentAutomated scan100/100version: "1.0.0" name: binary-protection-bypass description: >- Binary protection bypass playbook. Use when identifying and bypassing ASLR, PIE, NX/DEP, stack canary, RELRO, FORTIFY_SOURCE, CET, and MTE protections in ELF binaries to enable exploitation.
SKILL: Binary Protection Bypass — Expert Attack Playbook
AI LOAD INSTRUCTION: Expert binary protection identification and bypass techniques. Covers ASLR, PIE, NX, RELRO, canary, FORTIFY_SOURCE, stack clash, CET shadow stack, and ARM MTE. Each protection is paired with its bypass methods and required primitives. Distilled from ctf-wiki mitigation sections and real-world exploitation. Base models often confuse which protections block which attacks and miss the combinatorial effect of multiple protections.
0. RELATED ROUTING
- stack-overflow-and-rop — ROP chains to bypass NX, ret2libc for ASLR bypass
- format-string-exploitation — primary method for leaking canary, PIE, libc addresses
- heap-exploitation — heap attacks for RELRO bypass (when GOT is read-only)
- arbitrary-write-to-rce — what to overwrite when GOT is protected by RELRO
Advanced Reference
Load PROTECTION_BYPASS_MATRIX.md for comprehensive protection × bypass × primitive matrix.
1. PROTECTION IDENTIFICATION
$ checksec ./binary[*] '/path/to/binary'Arch: amd64-64-littleRELRO: Full RELRO ← GOT read-onlyStack: Canary found ← stack canary enabledNX: NX enabled ← stack not executablePIE: PIE enabled ← position-independent codeFORTIFY: Enabled ← fortified libc functions
Quick Identification Table
| Protection | Check Command | Binary Indicator | |
|---|---|---|---|
| ASLR | cat /proc/sys/kernel/randomize_va_space | OS-level (0=off, 1=partial, 2=full) | |
| PIE | checksec or readelf -h (Type: DYN) | Binary compiled with -pie | |
| NX | checksec or readelf -l (no RWE segment) | gcc -z noexecstack (default on) | |
| Canary | checksec or look for __stack_chk_fail@plt | gcc -fstack-protector-all | |
| Partial RELRO | readelf -l (GNU_RELRO segment, .got.plt writable) | gcc -Wl,-z,relro | |
| Full RELRO | readelf -l + .got section read-only | gcc -Wl,-z,relro,-z,now | |
| FORTIFY | Presence of __printf_chk, __memcpy_chk etc. | gcc -D_FORTIFY_SOURCE=2 |
2. ASLR BYPASS
ASLR randomizes base addresses of stack, heap, libc, and mmap regions at each execution.
| Bypass Method | Required Primitive | Notes | |
|---|---|---|---|
| Information leak | Any read primitive (format string, OOB read, UAF) | Leak libc/stack/heap address → calculate base | |
| Partial overwrite | Write primitive (limited length) | Overwrite last 1-2 bytes (page offset fixed) | |
| Brute force (32-bit) | Ability to reconnect/retry | ~256–4096 attempts (8-12 bits entropy) | |
| Return-to-PLT | Stack overflow | PLT addresses are at fixed offset from binary base (if no PIE) | |
| ret2dlresolve | Stack overflow + write primitive | Resolve arbitrary function without knowing libc base | |
| Format string leak | Format string vulnerability | %N$p for stack/libc/heap addresses | |
| Stack reading | Byte-by-byte (fork server) | Read stack byte-by-byte via crash oracle |
ASLR Entropy (x86-64 Linux)
| Region | Entropy (bits) | Positions | |
|---|---|---|---|
| Stack | 22 | ~4M | |
| mmap / libc | 28 | ~256M | |
| Heap (brk) | 13 | ~8K | |
| PIE binary | 28 | ~256M |
3. PIE BYPASS
PIE (Position Independent Executable) randomizes the binary's own code/data base address.
| Bypass Method | Required Primitive | Notes | |
|---|---|---|---|
| Information leak | Read return address from stack | PIE base = leaked_addr - known_offset | |
| Partial overwrite | One-byte or two-byte write | Last 12 bits of page offset are fixed | |
| Format string leak | Format string vulnerability | %N$p where N points to .text return address | |
| Relative addressing | Knowledge of binary layout | If you know relative offsets, only need one leak |
Partial Overwrite Details
PIE binary loaded at: 0x555555554000 (example)Function at offset 0x1234: 0x555555555234Overwrite return address last 2 bytes: 0x?234 → 0x?XXXUnknown: bits 12-15 (one nibble = 4 bits = 16 possibilities)Success rate: 1/16 per attempt
4. NX / DEP BYPASS
NX (No-eXecute) / DEP (Data Execution Prevention) prevents execution of code on the stack/heap.
| Bypass Method | Detail | |
|---|---|---|
| ROP (Return-Oriented Programming) | Chain existing code gadgets ending in ret | |
| ret2libc | Call libc functions (system, execve) directly | |
| ret2csu | Use __libc_csu_init gadgets for controlled function calls | |
| ret2dlresolve | Forge dynamic linker structures to resolve arbitrary functions | |
| SROP | Use sigreturn to set all registers from fake signal frame | |
| mprotect ROP | Chain mprotect(addr, size, PROT_RWX) → make page executable → jump to shellcode | |
| JIT spray | In JIT environments (V8, etc.), create executable code via JIT compiler |
mprotect Chain
# Make stack executable, then jump to shellcoderop = b'A' * offsetrop += p64(pop_rdi) + p64(stack_page) # page-aligned addressrop += p64(pop_rsi) + p64(0x1000) # sizerop += p64(pop_rdx) + p64(7) # PROT_READ|PROT_WRITE|PROT_EXECrop += p64(mprotect_addr)rop += p64(shellcode_addr) # jump to shellcode on now-executable stack
5. RELRO BYPASS
| RELRO Level | GOT Status | Bypass | |
|---|---|---|---|
| No RELRO | GOT fully writable | Direct GOT overwrite | |
| Partial RELRO | .got.plt writable (lazy binding) | GOT overwrite still works | |
| Full RELRO | All GOT entries resolved at load, GOT read-only | Cannot write GOT → target other structures |
Full RELRO Alternative Targets
| Target | When | How | |
|---|---|---|---|
__malloc_hook | glibc < 2.34 | Overwrite with one_gadget | |
__free_hook | glibc < 2.34 | Overwrite with system, trigger free("/bin/sh") | |
_IO_FILE vtable | Any glibc | FSOP / vtable hijack | |
__exit_funcs | Any glibc | Overwrite exit handler list | |
TLS_dtor_list | glibc ≥ 2.34 | Thread-local destructor list (needs pointer guard) | |
.fini_array | If writable | Overwrite destructor function pointers | |
| Stack return address | Direct stack write | Overwrite return address for ROP |
See arbitrary-write-to-rce for comprehensive target list.
6. CANARY BYPASS
| Method | Condition | Detail | |
|---|---|---|---|
| Format string leak | printf(user_input) | %N$p to read canary from stack | |
| Brute-force | fork() server (canary persists in child) | Byte-by-byte: 256 × (canary_size-1) attempts | |
| Stack reading | Partial overwrite / info leak | Overwrite canary's null byte, leak via output | |
| Thread canary overwrite | Overflow reaches TLS | Canary at fs:[0x28]; overflow past buffer to TLS → overwrite canary with known value | |
| Canary-relative overwrite | Overflow after canary but before return addr | Skip canary, only overwrite return address (rare layout) | |
| Heap-based | Vulnerability is on heap, not stack | Canary only protects stack | |
| __stack_chk_fail GOT overwrite | Partial RELRO | Overwrite __stack_chk_fail@GOT to point to harmless function → canary check passes |
Canary Format
x86: 0x00XXXXXX (4 bytes, leading null byte)x86-64: 0x00XXXXXXXXXXXXXX (8 bytes, leading null byte)
The leading \x00 prevents string operations from accidentally reading the canary.
7. FORTIFY_SOURCE BYPASS
_FORTIFY_SOURCE=2 adds buffer size checking and restricts format string operations.
| Fortified Function | Restriction | Bypass | |
|---|---|---|---|
__printf_chk | %n with positional args (%N$n) forbidden | Use non-positional %n or %hn chain | |
__memcpy_chk | Destination buffer size checked | Use heap overflow instead of stack | |
__strcpy_chk | Same | ||
__read_chk | Read size checked against buffer |
Format String with FORTIFY_SOURCE
# %1$n is blocked by __printf_chk# But sequential (non-positional) %n may still work:# Print exact byte count, then %hn — must be very precise# Or: find unfortified printf in binary/libc via ROP
8. CET (Control-flow Enforcement Technology)
Intel CET adds two mechanisms:
Shadow Stack
- Hardware-maintained copy of return addresses
- On
ret, CPU checks shadow stack matches actual stack - Mismatch →
#CPfault (control protection exception)
| Impact | Detail | |
|---|---|---|
| ROP blocked | Return address overwrite detected on ret | |
| JOP possible | jmp [reg] not checked by shadow stack | |
| COP possible | call [reg] pushes to shadow stack but target validated by IBT |
Indirect Branch Tracking (IBT)
- Indirect
jmp/callmust land onENDBR64instruction - Non-ENDBR landing →
#CPfault
Bypass:
- Data-only attacks (don't change control flow)
- Find valid ENDBR gadgets that chain into useful operations
- JOP with ENDBR-prefixed gadgets
- Target structures outside CFI scope (modprobe_path, function pointer arrays)
9. MTE (Memory Tagging Extension, ARM)
ARM MTE assigns 4-bit tags to memory pointers and allocations. Tag mismatch = fault.
| Aspect | Detail | |
|---|---|---|
| Tag bits | 4 bits in pointer (bits 56-59) = 16 possible tags | |
| Granule | 16 bytes (each 16-byte granule has one tag) | |
| Check | Load/store: pointer tag must match memory tag | |
| Probabilistic | Random tag → 1/16 chance attacker guesses correctly |
Bypass Approaches
| Method | Success Rate | |
|---|---|---|
| Brute-force | 1/16 per attempt (6.25%) | |
| Tag oracle | Side-channel to determine tag (timing, error messages) | |
| In-bounds exploit | Stay within same tagged region (use relative offsets) | |
| Tag bypass gadget | Use LDGM/STGM instructions if accessible | |
| Speculative execution | Spectre-style bypass of tag check |
10. DECISION TREE
Binary analysis: checksec output├── NX disabled?│ └── Shellcode on stack/heap (simplest path)│├── NX enabled (standard modern binary)?│ ├── Need code execution → ROP/ret2libc│ ││ ├── Canary enabled?│ │ ├── fork server? → byte-by-byte brute-force│ │ ├── Format string? → leak canary via %p│ │ ├── Heap vuln? → canary doesn't protect heap│ │ └── Partial RELRO? → overwrite __stack_chk_fail@GOT│ ││ ├── PIE enabled?│ │ ├── Format string? → leak .text address → PIE base│ │ ├── Partial overwrite → last 12 bits fixed (1/16 brute-force)│ │ └── OOB read? → leak code pointer│ ││ ├── ASLR enabled?│ │ ├── Info leak available → leak libc base│ │ ├── No leak → ret2dlresolve or SROP│ │ ├── 32-bit? → brute-force feasible (~4096 attempts)│ │ └── Return-to-PLT (no libc base needed for PLT calls)│ ││ ├── RELRO level?│ │ ├── None/Partial → GOT overwrite│ │ └── Full → alternative targets:│ │ ├── glibc < 2.34 → __malloc_hook / __free_hook│ │ ├── glibc ≥ 2.34 → _IO_FILE / exit_funcs / TLS_dtor_list│ │ ├── .fini_array (if writable)│ │ └── Stack return address│ ││ └── FORTIFY_SOURCE?│ ├── Blocks positional %n → use sequential %n or heap exploit│ └── Blocks buffer overflows in fortified functions → use unfortified paths│├── CET (shadow stack)?│ ├── ROP blocked → data-only attack or JOP│ └── ENDBR-gadget chaining│└── MTE (ARM)?├── 1/16 brute-force└── Stay in-bounds for relative corruption