| name | arbitrary-write-2-exec |
| description | 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. |
Arbitrary 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
system() or your shellcode
- 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
call [addr] instructions)
- 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 | %n 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:
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:
pop rdi; ret - Set first argument
pop rsi; ret - Set second argument
pop rax; ret - Set syscall number
mov rax, 0x3b; ret - execve syscall
Practical Workflow
Step 1: Analyze the Binary
checksec --file vulnerable_binary
objdump -R vulnerable_binary | grep puts
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:
scripts/got_overwrite.py - GOT overwrite payloads
scripts/rop_chain.py - ROP chain generation
scripts/find_gadgets.py - Gadget discovery
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
break *puts@GOT
watch *(long*)0x404000
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)
References