Shellcode
- •
What it is
- •
Raw machine code placed in a process and executed there. It often uses direct syscalls to avoid depending on libc addresses; the destination memory must be executable.
- •
- •
How it works
- •
Find or create an injection point (vulnerable buffer, or — as in pwn.college's teaching harness — a region the challenge explicitly maps RWX and executes for you).
- •
Write minimal assembly that calls syscalls directly instead of libc wrappers (no symbol resolution needed).
- •
Assemble to raw bytes, satisfy any delivery constraints (size limit, forbidden bytes/opcodes — see Bad Character Filtering Bypass and Self-Modifying Shellcode).
- •
Deliver the bytes and let the harness/vulnerability redirect execution into them.
- •
High addresses [ mapped RWX region ] ← shellcode bytes land here, executes in place [ ... ] Low addresses
- •
- •
When to use it
- •
An executable input region and a way to redirect execution into it make direct shellcode possible.
- •
Challenge harness explicitly maps and executes attacker-supplied bytes (pwn.college's
ello-ackers-style challenges) rather than requiring a separate memory-corruption bug. - •
No libc leak available and a static/PIE-agnostic syscall path exists -> prefer direct syscalls over library calls.
- •
- •
Examples
- •
In a shellcoding challenge, use
open("/flag", 0)followed bysendfile(1, fd, NULL, 100)to print the flag.
- •
- •
pwntools
- •
from pwn import asm, context, disasm context.arch = 'amd64' print(disasm(asm('xor eax, eax')))
- •
- •
- •
Variants
- •
Multi-stage shellcode
- •
A small first stage reads a larger second stage. Reusing register values can save bytes, but verify the exact entry state in the debugger.
- •
- •
Size-golfed shellcode
- •
Reuse constants, shorter encodings, and known register values to reduce payload size.
- •
- •
See also Shellcode Chunking (Short Jumps) for surviving patterned in-flight corruption of the payload, and Symlink Path Shortening for shrinking a required path string via filesystem pre-staging.
- •
- •
Cards
- •
Why write raw syscalls instead of calling libc functions in shellcode?
- •
No leak needed — you don't have to resolve or know libc's address; the syscall instruction talks to the kernel directly.
- •
- •
What's the general shape of a "spawn a shell" shellcode?
- •
Build the target string/args, load the syscall number and args into the right registers,
syscall.
- •
- •