Hacktricks-skills arbitrary-write-2-exec
Binary exploitation skill for arbitrary write to code execution attacks. Use this skill whenever the user mentions arbitrary write vulnerabilities, write primitives, GOT overwrites, function pointer overwrites, or needs to convert a write primitive into code execution. Also trigger for CTF challenges involving memory corruption, heap exploits, or when the user asks about turning write access into shellcode execution.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/binary-exploitation/arbitrary-write-2-exec/arbitrary-write-2-exec/SKILL.MDArbitrary Write to Code Execution
This skill helps you convert arbitrary write primitives into code execution in binary exploitation challenges. An arbitrary write vulnerability lets you write any value to any memory address - this skill shows you how to weaponize that into RCE.
Core Concept
An arbitrary write primitive is dangerous because you can overwrite:
- GOT entries - Redirect function calls to your shellcode
- Function pointers - Hijack control flow directly
- Return addresses - Classic stack-based exploitation
- vtable pointers - In C++ applications
- Global variables - That affect program logic
Attack Patterns
Pattern 1: GOT Overwrite (Most Common)
When you can write to the Global Offset Table, overwrite a function's entry to point to your shellcode or
system().
Steps:
- Find a function that gets called after your write primitive (e.g.,
,puts
)printf - Get the address of that function's GOT entry
- Overwrite it with the address of
or your shellcodesystem() - Trigger the function call
Example:
# Overwrite puts@GOT with system@plt write(puts_got_addr, system_plt_addr) puts(";id;#") # Now calls system(";id;#")
Pattern 2: Function Pointer Overwrite
If the binary has global function pointers, overwrite them directly.
Steps:
- Identify function pointers in the binary (look for
instructions)call [addr] - Overwrite the pointer with your shellcode address
- Trigger the call
Pattern 3: Return Address Overwrite
Classic stack smashing - if you can write to the stack, overwrite the return address.
Steps:
- Find the offset to the return address
- Overwrite it with your shellcode or ROP chain address
- Return from the function
Finding Write Primitives
Look for these vulnerability patterns:
| Vulnerability | Write Primitive |
|---|---|
| Format string | writes to stack |
| Heap overflow | Can corrupt adjacent data |
| Use-after-free | Can control freed chunk metadata |
| Integer overflow | Can cause out-of-bounds writes |
| Off-by-one | Can corrupt next structure |
Shellcode Placement
You need a place to put your shellcode:
- BSS section - Writable, but not executable by default
- Heap - Writable, may need to make executable
- Stack - Writable, may need to make executable
- mmap() - Allocate RWX memory explicitly
Making memory executable:
// Use mprotect via ROP mprotect(addr & ~0xfff, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC)
ROP Chain Construction
When you can't execute shellcode directly, use Return-Oriented Programming:
- Find gadgets in the binary (instructions ending in
)ret - Chain them to set up registers and call
system() - Use the write primitive to place the ROP chain
- Redirect execution to it
Common gadgets:
- Set first argumentpop rdi; ret
- Set second argumentpop rsi; ret
- Set syscall numberpop rax; ret
- execve syscallmov rax, 0x3b; ret
Practical Workflow
Step 1: Analyze the Binary
# Check protections checksec --file vulnerable_binary # Find GOT entries objdump -R vulnerable_binary | grep puts # Find function pointers radare2 -c "afl" vulnerable_binary
Step 2: Identify the Write Primitive
- What can you write?
- Where can you write?
- What constraints exist (size, alignment, null bytes)?
Step 3: Choose Your Target
- GOT entry? (easiest if available)
- Function pointer? (direct control)
- Return address? (classic)
- vtable? (C++ specific)
Step 4: Craft the Payload
Use the scripts in this skill to generate payloads:
- GOT overwrite payloadsscripts/got_overwrite.py
- ROP chain generationscripts/rop_chain.py
- Gadget discoveryscripts/find_gadgets.py
Step 5: Test and Iterate
- Test with gdb/pwndbg
- Check for ASLR issues
- Verify NX/PIE constraints
Common Pitfalls
- ASLR - If enabled, you need to leak an address first
- NX - Can't execute shellcode on stack/heap without mprotect
- PIE - Addresses are randomized, need to leak base
- Canaries - Stack canaries prevent return address overwrites
- Null bytes - Some functions stop at null bytes
Debugging Tips
# Set breakpoints on GOT entries break *puts@GOT # Watch for writes to specific addresses watch *(long*)0x404000 # Trace execution traceexec ./vulnerable
When to Use This Skill
Use this skill when:
- You have a write primitive and need RCE
- You're solving CTF challenges with memory corruption
- You need to understand GOT overwrites
- You want to convert heap vulnerabilities to code execution
- You're analyzing binaries for write-based vulnerabilities
Next Steps
After mastering arbitrary write to exec:
- Learn heap exploitation (heap grooming, tcache poisoning)
- Study format string vulnerabilities
- Practice with pwnable.kr and similar platforms
- Learn advanced ROP techniques (JOP, SIP, ROPgadget)