blog.git

blog

~ Personal research notes. blog.sqzer.com
git clone https://github.com/debuman/blog.git

content/writing/php2shell-cve-2026-109618-cve-2026-109619.md (10185B)

      1 ---
      2 title: "PHP2Shell (CVE-2026-109618 / CVE-2026-109619) Vulnerability Analysis & Technical Report"
      3 titleKo: ""
      4 date: 2026-10-22
      5 deck: ""
      6 type:
      7 tags: []
      8 draft:
      9 ---
     10 
     11 ## 1. Executive Overview
     12 
     13 In October 2026, two critical security vulnerabilities were publicly disclosed in the PHP core engine, which powers approximately 70% of web systems worldwide. These flaws allow unauthenticated attackers to gain full control of targeted web servers or leak process memory without requiring any login or credential verification. This set of vulnerabilities has been dubbed **'PHP2Shell'**.
     14 
     15 Regardless of the source code security of individual web applications (such as WordPress, Drupal, or Laravel), these vulnerabilities stem directly from **memory management defects within the PHP engine itself**.
     16 
     17 ### 1.1 Intuitive Analogy: System Architecture Perspective
     18 To understand the flaw intuitively, imagine a website as an **apartment building**:
     19 * **Standard Web Application Hacking**: Picking the lock or breaking a window of an individual apartment unit.
     20 * **PHP2Shell Attack**: A structural flaw in the building's core materials (the PHP engine itself), allowing attackers to bypass the front desk security or keypads entirely and gain direct control of the entire building management room.
     21 
     22 ### 1.2 Key Vulnerability Summary
     23 
     24 | Item | Details |
     25 | :--- | :--- |
     26 | **Vulnerability Identifiers** | **CVE-2026-109618** (OOM Memory Corruption & Disclosure), **CVE-2026-109619** (Stale Global State RCE) |
     27 | **Severity** | **Critical** (CVSS v4.0 Score: **9.2**) |
     28 | **Attack Vector** | Unauthenticated Remote Code Execution (RCE), Memory Disclosure |
     29 | **Affected Versions** | PHP 5.4.0 through unpatched releases across all active branches (8.2, 8.3, 8.4, 8.5) |
     30 | **Patched Releases** | **PHP 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 or higher** |
     31 
     32 ---
     33 
     34 ## 2. Vulnerability Mechanics & Attack Pipeline
     35 
     36 The root cause of the PHP2Shell attack lies in a structural flaw where the PHP engine fails to properly clean up its state during fatal errors—specifically **Out-Of-Memory (OOM)** conditions—and abruptly performs an emergency stack unwind via `longjmp()`.
     37 
     38 The attack unfolds across a 3-stage pipeline:
     39 
     40 1. **Stage 1: Inducing Intentional OOM (Out-Of-Memory)**  
     41    The attacker sends a specially crafted HTTP multipart (file upload) request that rapidly exhausts PHP's allocated `memory_limit`.
     42 2. **Stage 2: Emergency Abort & Residual Dangling Pointers (Triggering Use-After-Free)**  
     43    When OOM occurs, the PHP engine skips standard cleanup routines and terminates via `longjmp()`. While the active Heap memory is freed, global memory pointers are left uninitialized (Dangling Pointers).
     44 3. **Stage 3: Memory Re-allocation & Server Hijacking via Secondary Request**  
     45    The attacker immediately issues a second HTTP request targeted at the same web server worker process. Malicious payload structures (fake function pointers) fill the newly allocated memory space, causing the server to reference the dangling pointer, execute malicious code, or leak sensitive memory data (passwords, API keys, etc.).
     46 
     47 ---
     48 
     49 ## 3. Deep Technical Analysis: Memory Management Defects
     50 
     51 This section details the C-level memory management architecture and exploit mechanics within the PHP core engine.
     52 
     53 ### 3.1 C-Level Pointer Uninitialization and `longjmp()` Emergency Unwinding
     54 Under normal execution, PHP frees allocated memory upon request completion and resets pointer addresses to `NULL (0)`. However, when a memory allocation function (`emalloc()`) fails due to OOM, the PHP core immediately executes `longjmp()` to unwind the stack directly to the top-level error handler.
     55 
     56 During this abrupt unwinding, cleanup routines inside core functions such as `_zend_hash_str_add_or_update_i()` are bypassed. Consequently, even though the OS and PHP allocator mark the Heap memory region as freed, global execution state objects (such as `zend_executor_globals`) retain **dangling pointers** pointing to the freed memory addresses.
     57 
     58 ### 3.2 HTTP Multipart Manipulation & `memory_limit` Exhaustion Techniques
     59 To bypass the server's `post_max_size` guard while triggering `memory_limit` exhaustion, attackers craft HTTP headers and body structures with the following traits:
     60 
     61 * **Empty Filename Specification (`filename=""`)**: Generates metadata structures for PHP's internal file upload management array (`PG(http_post_files)`) continuously without requiring actual file payloads.
     62 * **Deeply Nested Field Names (`a[b][c][d]...`)**: Triggers the creation of multi-dimensional hash tables, fragmenting the Heap memory into numerous small chunks and accelerating exhaustion.
     63 * **Chunked Transfer Encoding**: Streams request data without specifying an initial content length, preventing web servers from pre-validating memory allocation thresholds.
     64 
     65 ### 3.3 Web Server Worker Process Reuse & State Persistence
     66 Modern web hosting environments (such as Apache `mod_php` or `PHP-FPM`) keep worker processes alive across multiple requests to optimize performance.
     67 
     68 Immediately after corrupting a worker process's global state with the first request, the attacker uses HTTP/1.1 Keep-Alive or synchronized concurrent requests to ensure the **second request hits the exact same worker process**.
     69 
     70 ### 3.4 Heap Memory Re-allocation & Control Flow Hijacking
     71 When the second request arrives at the corrupted worker, PHP's memory manager (Zend MM) re-allocates the recently freed Heap chunk for the new request's data.
     72 
     73 The attacker structures the second request body with a fake virtual method table (VTable) and function pointers. When the PHP engine mistakenly trusts the dangling pointer from the prior request and invokes a method, execution branches to the attacker-controlled address (e.g., ROP gadget), achieving **Remote Code Execution (RCE)**.
     74 
     75 ### 3.5 Memory Disclosure via Residual Data & Session Cookies
     76 In `CVE-2026-109618`, the flaw leads not only to RCE but also to severe memory leaks:
     77 1. Triggering OOM during session initialization leaves the session ID pointer (`PS(id)`) pointing to freed Heap memory.
     78 2. When the second request arrives, the PHP engine treats whatever residual data remains in that memory space (such as database passwords, API keys, encryption tokens, or ASLR bypass addresses from previous operations) as a valid session ID string.
     79 3. PHP URL-encodes this raw memory content and returns it in the `Set-Cookie: PHPSESSID=...` response header, allowing attackers to decode and extract sensitive server secrets directly.
     80 
     81 ---
     82 
     83 ## 4. Threat Intelligence & Exploit Dynamics
     84 
     85 ### 4.1 Weaponization via Artificial Intelligence (LLM) & Automated Debugging
     86 Although these flaws remained dormant in the PHP core for over a decade, security researchers (Wiz Research, Calif, etc.) leveraged **advanced Large Language Models (LLMs)** combined with automated debugging tools (GDB/LLVM) to compress what used to take months of manual research into a matter of hours.
     87 
     88 ### 4.2 ASLR Mitigation & The 2-Stage Exploit Chain
     89 According to analysis by security expert Marcus Hutchins, most public proof-of-concept (PoC) scripts circulating online fail or simply crash the server. This is because modern operating systems enforce **ASLR (Address Space Layout Randomization)**.
     90 
     91 To achieve reliable exploitation, attackers must execute a **2-stage exploit chain**:
     92 * **[Stage 1] Memory Disclosure Attack**: Exploit `CVE-2026-109618` to extract process memory addresses and module base addresses via response cookies.
     93 * **[Stage 2] ASLR Bypass & RCE Execution**: Calculate exact ROP gadget offsets using the leaked addresses, then deliver the secondary payload to achieve stable code execution.
     94 
     95 ---
     96 
     97 ## 5. Server Architecture Risk Matrix
     98 
     99 | Server Environment | Vulnerable? | Risk Assessment & Vector |
    100 | :--- | :---: | :--- |
    101 | **Apache + mod_php (prefork)** | **Yes (Highest Risk)** | Unauthenticated RCE possible across any request path regardless of application code. |
    102 | **Apache + PHP-FPM** | **Yes (High Risk)** | RCE possible via endpoints triggering `session_start()`, `unserialize()`, or upload handling. |
    103 | **Nginx + PHP-FPM** | **Yes (High Risk)** | Same vector as Apache + PHP-FPM. Higher `client_max_body_size` increases exploitability. |
    104 | **FrankenPHP / LSAPI** | **Yes (Caution)** | Similar to FPM worker reuse models, susceptible to state corruption. |
    105 
    106 ---
    107 
    108 ## 6. Remediation & Mitigation
    109 
    110 ### 6.1 Permanent Solution (P0) - Apply Official Patches
    111 Applying official vendor patches is the **only complete solution** to defend against all exploit variations.
    112 
    113 1. **Immediately Upgrade PHP Core**:
    114    * PHP 8.2 branch $\rightarrow$ **8.2.35 or higher**
    115    * PHP 8.3 branch $\rightarrow$ **8.3.36 or higher**
    116    * PHP 8.4 branch $\rightarrow$ **8.4.27 or higher**
    117    * PHP 8.5 branch $\rightarrow$ **8.5.12 or higher**
    118 2. **Restart Web Services**:
    119    * After updating binaries, run `systemctl restart apache2` or `systemctl restart php-fpm` to flush corrupted worker instances from memory.
    120 
    121 ### 6.2 Temporary Mitigations (P1)
    122 If immediate patching is not possible, implement these temporary measures to reduce exposure:
    123 
    124 * **Update `php.ini` Settings**:
    125   ```ini
    126   session.upload_progress.enabled = 0
    127   session.auto_start = 0
    128   ```
    129 * **Web Application Firewall (WAF) Rules**:
    130   * Block request bodies containing `PHP_SESSION_UPLOAD_PROGRESS`.
    131   * Drop requests containing empty filenames (`filename=""`) combined with deeply nested fields (`a[b][c][d]`).
    132 
    133 ---
    134 
    135 ## 7. Forensic & Detection Guide
    136 
    137 System administrators can check Linux server logs for signs of exploitation attempts using the following commands:
    138 
    139 1. **Check for Pre-execution OOM Errors**:
    140    ```bash
    141    grep -cE 'Allowed memory size of [0-9]+ bytes exhausted.*in Unknown on line 0' \
    142      /var/log/php_errors.log /var/log/apache2/error.log /var/log/httpd/error_log /var/log/php*-fpm.log
    143    ```
    144 2. **Check for Worker Segmentation Faults**:
    145    ```bash
    146    grep -E "Segmentation fault|signal 11|SIGSEGV" /var/log/apache2/error.log /var/log/php*-fpm.log
    147    ```
    148 3. **Inspect Response Cookies for Memory Leaks**:
    149    * Review web server or WAF logs for abnormally long or binary-encoded `PHPSESSID` cookie values in HTTP responses.
    150 
    151 ---