Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:17:15 +08:00
commit 31df8711f2
13 changed files with 6197 additions and 0 deletions

948
skills/ctf-pwn/patterns.md Normal file
View File

@@ -0,0 +1,948 @@
# CTF Binary Exploitation Patterns
This document contains patterns for recognizing common vulnerability classes and exploitation primitives in CTF challenges. Focus on **conceptual understanding** rather than specific exploits.
## Vulnerability Recognition Patterns
### Unsafe String Operation Patterns
**Conceptual characteristics**:
- Functions that don't check destination buffer size
- Unbounded copying from source to destination
- Reliance on null terminator without size validation
- No length parameter or ignored length parameter
**Dangerous API patterns**:
```c
// Unbounded copy (no size checking)
strcpy(dest, user_input); // Copies until null byte
strcat(dest, user_input); // Appends until null byte
sprintf(dest, "%s", user_input); // Formats without bounds
gets(buffer); // Reads unlimited from stdin
// Underspecified bounds
strncpy(dest, src, sizeof(dest)); // Doesn't guarantee null termination
scanf("%s", buffer); // No size limit specified
read(fd, buffer, 1024); // May exceed buffer size if buffer < 1024
recv(sock, buffer, MAX, 0); // May exceed buffer capacity
```
**What to look for in decompiled code**:
```
Buffer declaration:
char buffer[64]; // Fixed-size local array
Unsafe operation on same buffer:
strcpy(buffer, user_input); // No size check
read(fd, buffer, 256); // Reads more than buffer holds
Distance to critical data:
buffer[64] // Local variable at stack offset
saved_rbp // Usually at buffer + buffer_size
return_address // Usually at buffer + buffer_size + 8
```
**Investigation strategy**:
1. `get-symbols` includeExternal=true → Find strcpy, strcat, gets, scanf, sprintf imports
2. `find-cross-references` to unsafe functions → Locate call sites
3. `get-decompilation` with includeContext=true → Analyze buffer size vs. input size
4. Calculate: input_max_size > buffer_size? → Buffer overflow exists
5. `set-bookmark` type="Warning" category="Buffer Overflow" at vulnerability
**Telltale signs**:
- Local char arrays with small sizes (64, 128, 256 bytes)
- Unbounded string functions called on those arrays
- User input directly passed to unsafe function
- No explicit size checking before copy operation
### Format String Vulnerability Patterns
**Conceptual characteristics**:
- User controls the format string parameter
- Format specifiers allow memory read (%x, %s, %p) and write (%n)
- Stack-based exploitation (format string reads stack arguments)
- Arbitrary read/write primitive when exploited
**Vulnerable patterns**:
```c
// VULNERABLE: User input as format string
printf(user_input);
fprintf(fp, user_input);
sprintf(buffer, user_input);
snprintf(buffer, size, user_input);
syslog(priority, user_input);
// SAFE: Format string is literal
printf("%s", user_input);
fprintf(fp, "Input: %s\n", user_input);
sprintf(buffer, "Data: %s", user_input);
```
**What to look for in decompiled code**:
```
Direct user input to format function:
read(0, buffer, 256);
printf(buffer); // VULNERABLE
Variable format string:
char* fmt = get_format_string(); // Source from user
printf(fmt, args); // VULNERABLE if fmt user-controlled
Missing format string:
fprintf(stderr, error_msg); // VULNERABLE if error_msg from user
```
**Exploitation primitives**:
```
%x or %p → Leak stack values (addresses, canaries, pointers)
%s → Arbitrary read (if pointer on stack)
%n → Arbitrary write (writes byte count to pointer)
%N$x → Direct parameter access (Nth argument)
%N$n → Write to Nth argument pointer
Example attack:
printf("AAAA%10$x"); → Leak 10th stack parameter
printf("AAAA%7$n"); → Write to pointer at 7th stack position
```
**Investigation strategy**:
1. `search-decompilation` pattern="printf|fprintf|sprintf|snprintf|syslog"
2. `get-decompilation` at each match with includeContext=true
3. Check format string argument: Is it a constant string or variable?
4. If variable, trace source: Does it come from user input?
5. `set-bookmark` type="Warning" category="Format String" at vulnerability
**Telltale signs**:
- printf/fprintf with single argument (no format string literal)
- Format string stored in writable buffer
- User input copied into format string variable
- Error message formatted with user-supplied data
### Buffer Size vs. Operation Mismatch Patterns
**Conceptual characteristics**:
- Buffer allocated with one size
- Operation assumes different (larger) size
- Off-by-one errors
- Mismatched size calculations
**Common mismatch patterns**:
```c
// Wrong size constant
char buffer[64];
read(fd, buffer, 128); // Reads 128 into 64-byte buffer
// Off-by-one
char buffer[64];
for (i = 0; i <= 64; i++) // Loop goes to 64 (65 iterations)
buffer[i] = input[i]; // Writes one byte past end
// Null terminator forgotten
char buffer[64];
strncpy(buffer, input, 64); // May not null-terminate
printf("%s", buffer); // Reads past end if not terminated
// Size calculation error
char buffer[64];
memcpy(buffer, src, strlen(src)); // strlen doesn't include null byte
// But may overflow if strlen(src) >= 64
```
**What to look for in decompiled code**:
```
Size declaration:
local_48 = buffer (char array, size 64)
Operation size:
read(0, local_48, 0x80); // 0x80 = 128 > 64
Offset calculation:
local_48[iVar1] = input[iVar1]; // Check iVar1 bounds
Loop bounds:
for (i = 0; i < size; i++) // Is size validated?
buffer[i] = input[i]; // Does size match buffer capacity?
```
**Investigation strategy**:
1. `get-decompilation` → Identify buffer size from local variable declaration
2. Find operations on buffer (read, memcpy, strcpy, loops)
3. Compare buffer size to operation size
4. `rename-variables` → buffer, buffer_size, read_size for clarity
5. `set-decompilation-comment` → "Buffer overflow: reads 128 into 64-byte buffer"
6. `set-bookmark` type="Warning" category="Size Mismatch"
**Telltale signs**:
- Magic constants in read/copy operations that don't match buffer size
- sizeof() used incorrectly (sizeof(pointer) vs. sizeof(array))
- Off-by-one in loop bounds (<= instead of <)
- Missing null terminator checks
### Integer Overflow Leading to Memory Corruption
**Conceptual characteristics**:
- Integer arithmetic wraps around at type bounds
- Overflow in size calculation leads to small allocation
- Small allocation leads to buffer overflow
- Underflow in bounds check bypasses security
**Vulnerable patterns**:
```c
// Allocation size overflow
uint32_t count = user_input; // User controls this
uint32_t size = count * sizeof(element); // May overflow
buffer = malloc(size); // Allocates small buffer due to overflow
for (i = 0; i < count; i++) // Loop uses original count
buffer[i] = data[i]; // Heap overflow
// Bounds check underflow
size_t len = user_input;
if (len - 1 < MAX_SIZE) { // Underflows if len == 0 (unsigned)
memcpy(buffer, src, len); // Large len bypasses check
}
// Sign confusion
int size = user_size; // User controls, may be negative
if (size < MAX_SIZE) { // Passes check if negative
memcpy(buffer, src, size); // Casted to size_t (huge number)
}
```
**What to look for in decompiled code**:
```
Size calculation:
size = user_count * 16; // Multiplication may overflow
Wraparound check missing:
if (user_count < 1000) { // Doesn't check for overflow
size = user_count * 16;
buf = malloc(size);
}
Unsigned underflow:
if (len - 1 < 1024) { // What if len == 0?
Sign conversion:
int signed_size = user_input; // Signed integer
malloc(signed_size); // Casted to size_t (unsigned)
// Negative becomes huge positive
```
**Investigation strategy**:
1. `search-decompilation` pattern="malloc|calloc|realloc"
2. Trace size parameter back to source
3. Check for multiplication/addition in size calculation
4. `change-variable-datatypes` to proper types (uint32_t, size_t, ssize_t)
5. Look for overflow checks (or lack thereof)
6. `set-decompilation-comment` → "Integer overflow: count * size may wrap"
7. `set-bookmark` type="Warning" category="Integer Overflow"
**Telltale signs**:
- Multiplication in allocation size without overflow check
- Unsigned subtraction in bounds check
- Signed/unsigned type confusion
- Missing validation for very large user-supplied sizes
### Use-After-Free Patterns
**Conceptual characteristics**:
- Memory freed but pointer still accessible (dangling pointer)
- Dangling pointer dereferenced (use after free)
- Heap allocator may reuse freed memory for new allocation
- Type confusion when old pointer accesses new object
**Vulnerable patterns**:
```c
// Classic use-after-free
object* ptr = malloc(sizeof(object));
use_object(ptr);
free(ptr);
// ... later in code ...
use_object(ptr); // Use after free!
// Double-free (special case)
free(ptr);
free(ptr); // Corrupts heap metadata
// Use-after-free via aliasing
object* ptr1 = malloc(sizeof(object));
object* ptr2 = ptr1; // Aliased pointer
free(ptr1);
use_object(ptr2); // Use after free via alias
```
**What to look for in decompiled code**:
```
Allocation and free:
heap_ptr = malloc(0x40);
// ... use heap_ptr ...
free(heap_ptr);
Later usage (use-after-free):
// ... some code ...
*heap_ptr = value; // Write to freed memory
function(heap_ptr); // Pass freed pointer
Conditional free (double-free risk):
if (condition1) free(ptr);
if (condition2) free(ptr); // May free twice if both true
No pointer nulling:
free(ptr);
// ptr not set to NULL, can be reused
```
**Investigation strategy**:
1. `search-decompilation` pattern="free"
2. For each free(), trace pointer usage after free
3. `find-cross-references` to pointer variable → See all uses
4. Check if pointer is nulled after free (ptr = NULL)
5. Check if pointer is checked before use (if (ptr != NULL))
6. `rename-variables` → freed_ptr, dangling_ptr for clarity
7. `set-decompilation-comment` at use site → "Use-after-free"
8. `set-bookmark` type="Warning" category="Use-After-Free"
**Telltale signs**:
- free() call without setting pointer to NULL
- Pointer dereferenced after free() in any code path
- Multiple free() calls on same pointer
- Pointer used in different contexts (freed as type A, used as type B)
### Heap Overflow Patterns
**Conceptual characteristics**:
- Allocation with one size
- Write operation exceeds allocated size
- Overflows into adjacent heap chunk
- Can corrupt heap metadata or adjacent object data
**Vulnerable patterns**:
```c
// Allocation too small
buffer = malloc(64);
read(fd, buffer, 128); // Heap overflow
// Calculation error
buffer = malloc(count * sizeof(element));
for (i = 0; i <= count; i++) // Off-by-one (should be <, not <=)
buffer[i] = data[i]; // Overflows by one element
// Unchecked string operation on heap
buffer = malloc(64);
strcpy(buffer, user_input); // Overflow if user_input > 63 bytes
```
**What to look for in decompiled code**:
```
Heap allocation:
heap_buf = malloc(0x40); // Allocates 64 bytes
Write operation:
read(0, heap_buf, 0x100); // Reads 256 bytes → overflow
Adjacent allocations:
buf1 = malloc(0x40);
buf2 = malloc(0x40); // buf2 likely adjacent to buf1
strcpy(buf1, user_input); // May overflow into buf2
Metadata corruption risk:
chunk = malloc(size);
overflow_write(chunk, large_size); // May corrupt next chunk's metadata
```
**Investigation strategy**:
1. `search-decompilation` pattern="malloc"
2. Trace allocated buffer through code
3. Find write operations on buffer (strcpy, memcpy, read, loops)
4. Compare allocation size to write size
5. Check for adjacent allocations (exploitation targets)
6. `set-decompilation-comment` → "Heap overflow: writes 256 into 64-byte allocation"
7. `set-bookmark` type="Warning" category="Heap Overflow"
**Telltale signs**:
- Small malloc() followed by large read/write
- String operations on heap buffers without bounds
- Loop writing to heap array without bounds check
- Multiple sequential allocations (heap layout predictable)
---
## Exploitation Primitive Patterns
### Arbitrary Memory Write Primitives
**Conceptual characteristics**:
- Ability to write controlled data to chosen address
- Achieved through various vulnerability classes
- Foundation for control flow hijacking and data corruption
**Primitive construction patterns**:
**Format string arbitrary write**:
```
// Concept: %n writes byte count to pointer argument
printf("AAAA%7$n");
// If stack[7] is controlled pointer, writes to *stack[7]
Technique:
1. Place target address on stack
2. Position format string to access it (%N$n)
3. Adjust byte count with padding to write desired value
4. Use width specifiers: %200c%7$n → writes 200+4=204
```
**Buffer overflow arbitrary write**:
```
// Concept: Overflow to overwrite pointer, then use pointer
Step 1: Overflow to corrupt pointer
[buffer overflow] → [overwrite ptr variable]
Step 2: Trigger write through pointer
*ptr = value; // Writes to attacker-controlled address
```
**Heap overflow arbitrary write**:
```
// Concept: Overflow heap chunk to corrupt adjacent chunk's pointers
Chunk layout:
[chunk1 metadata][chunk1 data][chunk2 metadata][chunk2 data]
Overflow chunk1 data → overwrite chunk2 metadata → corrupt pointers
When chunk2 used, writes to attacker-controlled addresses
```
**Investigation strategy**:
1. Identify vulnerability (format string, overflow, use-after-free)
2. Analyze what can be overwritten
3. Trace pointer dereferencing after corruption
4. `set-bookmark` type="Analysis" category="Arbitrary Write" → Document primitive
**What enables arbitrary write**:
- Controlled pointer value (overflow, format string)
- Dereference of controlled pointer (assignment, function call)
- Heap metadata corruption (unlink exploitation)
### Arbitrary Memory Read Primitives
**Conceptual characteristics**:
- Ability to read from chosen memory address
- Used to leak addresses, canaries, code/data
- Critical for defeating ASLR and other protections
**Primitive construction patterns**:
**Format string arbitrary read**:
```
// Concept: %s reads string from pointer argument
printf("AAAA%10$s");
// If stack[10] is controlled pointer, prints string at *stack[10]
Technique:
1. Place target address on stack
2. Position format string to access it (%N$s)
3. Read output to obtain memory contents
```
**Uninitialized data read**:
```
// Concept: Uninitialized variables contain previous stack/heap data
Pattern in decompiled code:
char buffer[64];
// No initialization
send(socket, buffer, 64, 0); // Leaks stack contents
Investigation:
Look for send/write without initialization
Check if data used before written
```
**Buffer over-read**:
```
// Concept: Read past end of buffer into adjacent memory
Pattern:
char buffer[64];
strncpy(buffer, input, 64); // No null termination
printf("%s", buffer); // Reads past end until null byte
Result: Leaks adjacent stack data
```
**Investigation strategy**:
1. Find format string vulnerabilities (user-controlled format)
2. Find uninitialized variables sent to output
3. Find string operations missing null termination
4. `set-bookmark` type="Analysis" category="Info Leak" → Document primitive
5. Calculate what can be leaked (addresses, canaries, pointers)
**What enables arbitrary read**:
- Format string with %s and controlled pointer
- Uninitialized buffer sent to network/file
- Missing null terminator allows over-read
- Heap use-after-free with read operations
### Control Flow Hijack Primitives
**Conceptual characteristics**:
- Redirect program execution to attacker-controlled location
- Achieved by overwriting function pointers or return addresses
- Goal: Execute shellcode, ROP chain, or existing functions
**Hijack target patterns**:
**Return address overwrite (stack overflow)**:
```
Stack layout:
[buffer][saved rbp][return address]
Overflow buffer → overwrite return address → redirect on function return
What to look for:
Local buffer vulnerable to overflow
Return address at predictable offset (buffer_size + 8 on x64)
Calculate offset: buffer start to return address location
```
**Function pointer overwrite**:
```
// Global or heap-allocated function pointer
void (*callback)(void) = default_handler;
// Overflow to overwrite callback
buffer_overflow → overwrite callback pointer
// Trigger hijack
callback(); // Calls attacker-controlled address
```
**GOT/PLT overwrite**:
```
// Global Offset Table contains addresses of library functions
// Overwrite GOT entry to redirect library call
Example:
Overwrite GOT[puts] with system address
Next call to puts() actually calls system()
Requirement: Arbitrary write primitive to GOT address
```
**Virtual table (vtable) overwrite**:
```
// C++ objects have vtable pointers
// Overwrite vtable pointer to fake vtable
Object layout:
[vtable ptr][member1][member2]...
Overflow → overwrite vtable ptr → point to attacker-controlled memory
Virtual function call → uses fake vtable → hijacks control flow
```
**Investigation strategy**:
1. Identify overflow vulnerability
2. Determine what's adjacent in memory (return address, function pointer, vtable)
3. Calculate offset from buffer to target
4. `get-data` at GOT/PLT addresses → Get function pointer locations
5. `set-bookmark` type="Analysis" category="Control Flow Hijack"
6. Document target address and offset
**Telltale signs**:
- Function pointers in global variables or structures
- Indirect calls through function pointers
- Virtual function calls (C++ code)
- GOT/PLT entries for library functions
### Information Leak Primitives (Defeating ASLR)
**Conceptual characteristics**:
- Leak address from memory to defeat address randomization
- Calculate base addresses from leaked pointers
- Use leaked addresses in subsequent exploitation
**Leak source patterns**:
**Stack address leak**:
```
// Stack addresses often present on stack itself
Format string: printf("%p %p %p %p") // Leak stack pointers
Uninitialized: Stack variable contains previous stack frame address
Use: Calculate stack layout, predict buffer addresses
```
**Code address leak (PIE bypass)**:
```
// Return addresses on stack point to code section
Format string leak of return address → code address
Calculate code base: leaked_addr & ~0xFFF (page alignment)
Use: Calculate gadget addresses, function addresses
```
**Libc address leak (ASLR bypass)**:
```
// GOT contains resolved libc function addresses
Arbitrary read of GOT entry → libc function address
Calculate libc base: leaked_addr - function_offset
Use: Calculate system(), one_gadget, useful function addresses
```
**Heap address leak**:
```
// Heap pointers often in freed chunks or stack
Use-after-free leak: Read freed chunk (contains fwd/bck pointers)
Format string: Leak heap pointer from stack
Use: Predict heap layout, target heap objects
```
**Investigation strategy**:
1. Identify leak primitive (format string, uninitialized data, over-read)
2. Determine what's leaked (stack, code, heap, libc addresses)
3. Calculate offsets to useful addresses
4. `set-bookmark` type="Note" category="Address Leak" → Document leak
5. `set-comment` → "Leaks libc address, calculate system() as libc_base + 0x4f4e0"
**Telltale signs**:
- printf with user-controlled format string
- Send/write with uninitialized buffer
- String operations without null termination
- Heap metadata visible to program (freed chunks)
---
## Common Exploitation Workflows
### Stack Overflow to Shell
**Attack flow**:
```
1. Find buffer overflow on stack
2. Calculate offset to return address
3. Identify target for hijack:
a. Shellcode address (if NX disabled)
b. system() address (if no ASLR)
c. ROP chain address (if protections enabled)
4. Construct payload: [padding][return address][arguments/ROP]
5. Trigger overflow, return redirects to attacker code
6. Execute shellcode/system("/bin/sh") to get shell
```
**Investigation steps**:
1. `get-decompilation` of vulnerable function → Find buffer overflow
2. `rename-variables` → buffer, user_input, size
3. Calculate offset: buffer to return address (usually buffer_size + 8)
4. `search-strings-regex` pattern="/bin/sh" → Find shell string
5. `get-symbols` includeExternal=true → Find system() import
6. `set-bookmark` type="Analysis" category="Exploit Plan"
7. Document payload structure in comment
### Format String to Arbitrary Write
**Attack flow**:
```
1. Find printf(user_input) vulnerability
2. Test format string: Send "%x %x %x" → leak stack values
3. Find offset to controlled data on stack
4. Construct format string to write to arbitrary address:
- Place target address on stack
- Use %N$n to write to address at stack[N]
5. Target: Overwrite GOT entry, return address, or function pointer
6. Redirect execution to attacker code
```
**Investigation steps**:
1. `search-decompilation` pattern="printf|sprintf" → Find format string calls
2. `get-decompilation` with includeContext → Verify format string from user
3. `get-data` at GOT addresses → Identify targets for overwrite
4. Calculate stack offset to controlled buffer
5. `set-bookmark` type="Warning" category="Format String"
6. Document exploitation: "%7$n writes to address at stack[7]"
### Heap Exploitation to Code Execution
**Attack flow**:
```
1. Find heap vulnerability (use-after-free, heap overflow, double-free)
2. Understand heap layout (chunk sizes, allocation order)
3. Exploit heap corruption:
a. Use-after-free: Free object, allocate new, use old pointer (type confusion)
b. Heap overflow: Overflow chunk to corrupt adjacent chunk metadata
c. Double-free: Corrupt freelist to allocate arbitrary address
4. Gain arbitrary write or control flow hijack primitive
5. Overwrite function pointer, GOT entry, or return address
6. Execute attacker code
```
**Investigation steps**:
1. `search-decompilation` pattern="malloc|free"
2. Trace allocation and free patterns
3. Identify vulnerability (use-after-free, overflow, double-free)
4. `rename-variables` → chunk1, chunk2, freed_ptr, size
5. Analyze adjacent allocations (overflow targets)
6. `set-bookmark` type="Warning" category="Heap Vulnerability"
7. Document exploitation primitive achieved
### Ret2libc (Return-to-libc)
**Attack flow**:
```
1. Find stack overflow vulnerability
2. Cannot use shellcode (NX enabled)
3. Redirect to existing libc function: system()
4. Set up arguments: First arg points to "/bin/sh"
5. Payload structure:
- Overflow to return address
- Overwrite return address → system() address
- Set first argument → pointer to "/bin/sh" string
6. Function returns, calls system("/bin/sh"), spawns shell
```
**Investigation steps**:
1. `get-decompilation` → Find buffer overflow
2. `search-strings-regex` pattern="/bin/sh" → Get shell string address
3. `get-symbols` includeExternal=true → Find system import
4. Check calling convention (x86: stack args, x64: RDI register)
5. Calculate ROP gadgets if needed: pop rdi; ret
6. `set-bookmark` type="Note" category="Ret2libc Plan"
7. Document payload: [padding][system_addr][ret_addr]["/bin/sh"_ptr]
### ROP Chain Construction
**Attack flow**:
```
1. Find code execution vulnerability (overflow, etc.)
2. Protections prevent direct shellcode/ret2libc
3. Build ROP chain: Sequence of gadget addresses
4. Each gadget: Small code fragment ending in 'ret'
5. Chain gadgets to build desired operation (e.g., execve syscall)
6. Place chain on stack, trigger vulnerability
7. Execution flows through gadgets, performs desired operation
```
**Investigation steps**:
1. Identify required gadgets (pop rdi; ret, pop rsi; ret, syscall; ret, etc.)
2. Use external tool (ROPgadget) to find gadgets in binary/libc
3. `set-bookmark` type="Note" category="ROP Gadget" at each gadget address
4. `set-comment` at gadget address → "pop rdi; ret"
5. Document ROP chain structure:
- [gadget1_addr] → pop rdi; ret
- ["/bin/sh"_ptr] → argument for rdi
- [gadget2_addr] → pop rsi; ret
- [NULL] → argument for rsi
- [syscall_addr] → execve syscall
6. `set-bookmark` type="Analysis" category="ROP Chain Plan"
---
## Protection Mechanism Bypass Patterns
### Stack Canary Bypass
**Canary mechanism**:
```
Stack layout with canary:
[buffer][stack canary][saved rbp][return address]
On function return:
if (canary != expected_canary)
__stack_chk_fail(); // Abort on corruption
```
**Bypass techniques**:
**1. Leak canary value (format string, uninitialized data)**:
```
printf(user_input); // Format string leak
Send "%7$p" → leak canary from stack position 7
Include leaked canary in overflow payload to preserve it
```
**2. Brute-force canary (fork server)**:
```
If server forks instead of exiting:
Canary same across fork
Brute-force one byte at a time
256 attempts per byte, 1024 total for 32-bit canary
```
**3. Overwrite without corrupting canary**:
```
Partial overwrite: Overflow only up to return address
Don't touch canary if it's not in the way
Or overwrite saved rbp and return address precisely
```
**Investigation**:
1. `search-decompilation` pattern="__stack_chk_fail" → Detect canary presence
2. `get-decompilation` → See canary check in code
3. Identify canary position on stack
4. `set-bookmark` type="Note" category="Stack Canary" → Document location
5. Plan bypass: leak, brute-force, or avoid
### NX/DEP Bypass (No Execute)
**Protection mechanism**:
```
Stack/heap marked non-executable
Shellcode injection doesn't work (causes segfault)
```
**Bypass techniques**:
**1. Return-to-libc (ret2libc)**:
```
Don't inject code, reuse existing code
Redirect to system(), execve(), etc.
Set up arguments properly
```
**2. Return-Oriented Programming (ROP)**:
```
Chain existing code fragments (gadgets)
Build complex operations from simple gadgets
No new code introduced
```
**3. mprotect/VirtualProtect ROP**:
```
Use ROP to call mprotect(shellcode_addr, RWX)
Change shellcode memory to executable
Jump to now-executable shellcode
```
**Investigation**:
1. `get-memory-blocks` → Check stack/heap permissions (look for 'x' flag)
2. If NX enabled, plan ROP or ret2libc
3. `get-symbols` includeExternal=true → Find usable functions
4. `set-bookmark` type="Analysis" category="NX Bypass"
### ASLR Bypass (Address Space Layout Randomization)
**Protection mechanism**:
```
Addresses randomized each execution
Code base, libc base, stack base, heap base all randomized
Exploit addresses must be dynamically calculated
```
**Bypass techniques**:
**1. Information leak**:
```
Leak address from memory (format string, uninitialized data)
Calculate base address from leaked pointer
Use base + offset to find desired functions
```
**2. Partial overwrite**:
```
Only lowest 12 bits (page offset) are not randomized
Overwrite only last byte of address
Reduces entropy, enables brute-force or partial redirect
```
**3. Heap spraying (rarely applicable in CTF)**:
```
Fill heap with controlled data
Increase probability of hitting controlled memory
```
**Investigation**:
1. Identify leak primitive (format string, over-read, uninitialized)
2. Calculate what's leaked (code, stack, heap, libc)
3. Determine offsets: leaked_addr to target_addr
4. `set-comment` → "Leak libc: system = libc_base + 0x4f4e0"
5. `set-bookmark` type="Analysis" category="ASLR Bypass"
### PIE Bypass (Position Independent Executable)
**Protection mechanism**:
```
Code section randomized (in addition to ASLR)
Function addresses, gadget addresses randomized
Cannot hardcode code addresses
```
**Bypass techniques**:
**1. Leak code address**:
```
Leak return address from stack → points to code
Calculate code base: leaked_addr & ~0xFFF
Calculate function/gadget addresses: code_base + offset
```
**2. Partial overwrite**:
```
Overwrite only last byte of return address
Redirect within same function or nearby functions
Useful for redirecting to existing win() function
```
**Investigation**:
1. Identify if PIE enabled (check binary properties)
2. Find code address leak (stack return address)
3. Calculate offsets from code base to targets
4. `set-bookmark` type="Analysis" category="PIE Bypass"
---
## Using This Reference
### Pattern Recognition Workflow
1. **Identify vulnerability class** → Match decompiled code to vulnerability patterns
2. **Determine exploitation primitive** → What capability does vulnerability provide?
3. **Check protections** → What bypass techniques are needed?
4. **Plan exploitation workflow** → Chain primitives to achieve goal
5. **Document in Ghidra** → Bookmarks, comments, renamed variables
### Investigation Priority
**Start with:**
1. Unsafe API recognition (strcpy, printf, etc.)
2. Buffer size vs. operation size comparison
3. Input flow tracing (where does user data go?)
**Then analyze:**
4. Memory layout (what's adjacent to vulnerable buffer?)
5. Available exploitation targets (return address, function pointers, GOT)
6. Protection mechanisms (canary, NX, ASLR, PIE)
**Finally plan:**
7. Exploitation primitive construction
8. Protection bypass strategy
9. Payload structure
10. Exploit execution plan
### Progressive Understanding
**First pass**: "Unsafe strcpy in main() on buffer[64]"
**Second pass**: "Overflow of 64 bytes to reach return address at offset +72"
**Third pass**: "Can redirect to system@plt, need '/bin/sh' string address"
**Fourth pass**: "Full ret2libc: overflow → system('/bin/sh') → shell"
Each iteration refines the exploitation plan.
### Evidence-Based Exploitation
Every claim needs evidence:
- "Buffer overflow exists" → Show buffer size < input size
- "Return address at offset 72" → Show stack layout calculation
- "Can call system()" → Show system@plt address or import
- "ASLR bypass possible" → Show leak primitive and calculation
Document all evidence with bookmarks and comments in Ghidra.