Disclaimer: This article is for educational purposes and cybersecurity defense research only. The Zend Engine versions discussed contain known vulnerabilities that have been patched in later releases. The author does not condone the use of this information for illegal activities.
| Component | Vulnerability Type | Example |
|-----------|--------------------|---------|
| zend_gc (garbage collector) | Use-after-free | Recursive array destruction |
| zend_hash (HashTable) | Double free / out-of-bounds read | Crafted array keys |
| zend_objects (object handlers) | Type confusion | Overriding get_properties |
| zend_vm (opcode handlers) | JIT miscompilation (not in 3.4.0) | N/A (no JIT yet) |
| zend_string | Off-by-one | zend_string_realloc |
zend_parse_parametersZend Engine v3.4.0 is responsible for mapping PHP function calls to internal C functions via zend_parse_parameters. A type confusion exploit occurs when the Zend Engine misidentifies a variable type (e.g., treating an array as a string). zend engine v3.4.0 exploit
The Vulnerability Pattern:
In early v3.4.0 builds, internal functions using ZEND_PARSE_PARAMETERS did not always validate object handlers before casting. By passing a crafted object with a custom get handler into a function expecting a zend_string, the engine would read the object’s property table as if it were a buffer.
Exploitation:
zval (Zend Value) structure overlaps with a string structure via union abuse.len attribute from the object’s memory space instead of the string's length.system is leaked, the attacker corrupts nearby zend_string structures to point to malicious command strings.// Simplified pseudo – real exploit requires heap spraying
zend_string *str = zend_string_alloc(128, 0);
zend_string_realloc(str, 256, 0);
// Old pointer may leak heap metadata if not cleared
Let's assume a target running PHP 7.3.0 (Zend Engine v3.4.0) with a vulnerable library that unserializes user input.
Step 1: Memory Layout Recon
The attacker sends a primitive payload to trigger a predictable memory leak, often via a Closure or Generator object. The leaked pointer reveals the base address of libc. Disclaimer: This article is for educational purposes and
Step 2: The ROP Chain Since NX (No-Execute) is standard, the attacker cannot execute shellcode on the heap directly. Instead, they construct a ROP (Return Oriented Programming) chain within a serialized string.
pop rdi; ret (to set the command argument).system().ret (stack alignment).Step 3: Triggering the UAF
The attacker sends the malformed PHAR file to a file_exists($input) call. The Zend Engine enters the phar parser, triggering the deserialization flaw (CVE-2020-7068). The zend_string holding the PHAR metadata is freed prematurely. and system('/bin/sh') is executed.
Step 4: The Spray
Immediately after freeing, the attacker sends a large request allocating thousands of SplFixedArray objects. The Zend Engine's heap allocator reuses the recently freed slots, placing the ROP payload directly where the zend_string used to be.
Step 5: Payload Execution
When the Zend Engine later attempts to read the "freed" string's val pointer, it instead reads the attacker's ROP chain. A subsequent function call triggers the dereference, the PC (Program Counter) jumps into the ROP chain, and system('/bin/sh') is executed.