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.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
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.
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 . Confirm a
canary bypass by sending the leaked canary back in the overflow and observing the process (no
). Confirm NX status with (an flag = exec
stack).
0x00
return normally
*** stack smashing detected ***
readelf -W -l ./vuln | grep GNU_STACK
E
Workflow
Step 1: Enumerate Protections
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 RELROcat /proc/sys/kernel/randomize_va_space # 0=off, 1=conservative, 2=full ASLR
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
# Forked-server byte-by-byte brute force (children share the canary)
canary = b'\x00'# known NUL LSBfor pos inrange(7): # remaining 7 bytes on x64for guess inrange(256):
io = remote(HOST, PORT)
io.send(b'A'*buf_len + canary + bytes([guess]))
ifb'smashing'notin 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)
# 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.
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.