A write-what-where condition occurs when an attacker can control both where data is written in memory and what data is written there. This is one of the most…
A write-what-where condition occurs when an attacker can control both *where* data is written in memory and *what* data is written there. This is one of the most severe memory corruption vulnerabilities because it can lead to arbitrary code execution, privilege escalation, or complete system compromise. Unlike buffer overflows that corrupt adjacent memory, write-what-where gives an attacker surgical precision to overwrite critical data structures.
02How It Happens
This weakness typically arises in low-level code (C/C++) where memory management is manual and input validation is insufficient. Common scenarios include:
- Unsafe pointer arithmetic: Code uses user-controlled values to calculate memory addresses without bounds checking.
- Unvalidated array indexing: An attacker supplies an index that is never verified to be within valid bounds, allowing writes to arbitrary offsets.
- Format string vulnerabilities: Misuse of format functions (e.g., printf) where an attacker controls the format string and can write to arbitrary addresses.
- Unsafe deserialization: Untrusted data is deserialized into structures containing function pointers or other sensitive fields that are then overwritten.
The core issue is the absence of a security boundary between user input and the memory address being written to.
03Real-World Impact
An attacker exploiting a write-what-where condition can overwrite function pointers, virtual method tables, return addresses on the stack, or heap metadata to redirect execution flow. This can result in arbitrary code execution with the privileges of the affected process, complete bypass of security mechanisms, or denial of service. Even on systems with modern mitigations (ASLR, DEP), write-what-where remains a critical primitive for building reliable exploits.
Why it's vulnerable: The offset parameter is taken directly from user input without validation. An attacker can supply a negative or very large offset to write beyond the intended buffer, corrupting adjacent memory structures.
Fixed pattern
import ctypes
class DataBuffer:
BUFFER_SIZE = 256
def __init__(self):
self.data = (ctypes.c_char * self.BUFFER_SIZE)()
self.metadata = ctypes.c_int(0)
def safe_write(buffer, offset, value):
# Validate offset is within bounds
if offset < 0 or offset + ctypes.sizeof(ctypes.c_int) > buffer.BUFFER_SIZE:
raise ValueError("Offset out of bounds")
ptr = ctypes.addressof(buffer.data) + offset
ctypes.cast(ptr, ctypes.POINTER(ctypes.c_int))[0] = value
user_offset = int(input("Enter offset: "))
user_value = int(input("Enter value: "))
buf = DataBuffer()
safe_write(buf, user_offset, user_value) # Bounds-checked
Vulnerable pattern
<?php
// Simulated pointer-like operation using array offsets
class MemoryRegion {
private $buffer = array_fill(0, 256, 0);
private $metadata = 0;
public function unsafeWrite($offset, $value) {
// $offset is user-controlled and never validated
$this->buffer[$offset] = $value;
}
}
$region = new MemoryRegion();
$user_offset = $_GET['offset']; // No validation
$user_value = $_GET['value'];
$region->unsafeWrite($user_offset, $user_value);
?>
Why it's vulnerable: The $offset parameter is used directly as an array key without checking whether it falls within the intended buffer bounds. An attacker can supply a negative index or an index far beyond the buffer size to corrupt adjacent data.
Fixed pattern
<?php
class MemoryRegion {
const BUFFER_SIZE = 256;
private $buffer = array();
private $metadata = 0;
public function __construct() {
$this->buffer = array_fill(0, self::BUFFER_SIZE, 0);
}
public function safeWrite($offset, $value) {
// Validate offset is within bounds
if (!is_int($offset) || $offset < 0 || $offset >= self::BUFFER_SIZE) {
throw new Exception("Offset out of bounds");
}
$this->buffer[$offset] = $value;
}
}
$region = new MemoryRegion();
$user_offset = isset($_GET['offset']) ? (int)$_GET['offset'] : 0;
$user_value = isset($_GET['value']) ? (int)$_GET['value'] : 0;
$region->safeWrite($user_offset, $user_value);
?>
05Prevention Checklist
Validate all memory offsets and indices before use; ensure they fall within the bounds of the target buffer or data structure.
Use safe abstractions (managed languages, standard library functions) instead of manual pointer arithmetic whenever possible.
Implement strict input validation on any user-supplied value that influences a write operation, including size, offset, or address calculations.
Enable compiler and runtime protections such as stack canaries, address space layout randomization (ASLR), and data execution prevention (DEP).
Perform code review focusing on memory operations, pointer arithmetic, and deserialization of untrusted data.
Use static analysis tools to detect unsafe pointer usage, out-of-bounds writes, and format string vulnerabilities.
06Signs You May Already Be Affected
Unexplained crashes, segmentation faults, or memory corruption errors in logs may indicate an attempted or successful write-what-where exploit. Unusual changes to critical data structures (e.g., unexpected function behavior, privilege escalation, or code execution) without corresponding legitimate modifications are also red flags. If you maintain C/C++ code that performs manual memory management, review recent changes to pointer arithmetic and array indexing logic.