Skip to content

Back to the catalog

eness/php2shell-CVE-2026-109618-CVE-2026-109619-PoC
github.comrepo

eness/php2shell-CVE-2026-109618-CVE-2026-109619-PoC

php2shell is the name given to two critical pre-auth remote code execution flaws, CVE-2026-109618 and CVE-2026-109619, in PHP core's session upload progress handler (php_session_rfc1867_callback), where zend_hash_update frees live zval pointers that are later reclaimed and redirected into zend_call_function to run zif_system. This repository ships poc_109618.py, a fully automated four-stage HTTP exploit that leaks ASLR offsets via Set-Cookie headers against php:8.4.26-apache on Debian Bookworm, along with a root-cause C source patch, mitigation scripts to disable session.upload_progress, and WAF/ModSecurity/Lighttpd/Apache rules plus detection guidance for anomalous PHP worker child processes. Confirmed PHP versions include 8.4.4 and 8.2.34, with EOL branches (5.x, 7.x, 8.0, 8.1) left without official vendor patches.

TL;DR A remote PoC exploit and patch/mitigation toolkit for php2shell, a pre-auth heap use-after-free RCE chain in PHP's session upload progress feature (CVE-2026-109618/CVE-2026-109619).
Document

What it is

php2shell is the name for CVE-2026-109618 and CVE-2026-109619, two pre-auth RCE flaws in PHP core, rated CVSS v4.0 9.2. Details leaked on October 20 (2026), ahead of coordinated disclosure. The repository by eness holds a working exploit, poc_109618.py, plus mitigations. watchTowr reproduced CVE-2026-109618. Huntress and Florian Roth (process-watcher) are monitoring it. The page demonstrates only 109618 and does not describe 109619 separately.

How it works

php_session_rfc1867_callback in ext/session/session.c keeps two raw zval * pointers (post_bytes_processed, current_file_bytes_processed) into live HashTables. A progress update re-reads session data, and zend_hash_update() frees the old tree. The dangling pointers are then reclaimed by crafted zend_fcall_info and zend_internal_function structures, and zend_call_function() runs system().

The PoC defeats ASLR over plain HTTP in four stages:

  1. Rotate the prefork worker to get a clean heap.
  2. Send an oversized multipart field (--huge-mb, default 12MB) to force OOM and leak the Zend MM chunk base through Set-Cookie: PHPSESSID.
  3. Leak the ZVAL_PTR_DTOR pointer through Set-Cookie to compute the libphp.so base.
  4. Forge a fake HashTable inside a 167-byte zend_string, with pDestructor pointing at zif_system. It overwrites PS(http_session_vars), and freeing the session data runs the command.

The command lives inside that string, so inline commands are capped at 14 bytes (MAX_CMD = 14). Longer payloads need a short trigger such as sh</tmp/c.

Preconditions / Affected

  • session.upload_progress.enabled = 1, which is the PHP default, and a multipart POST.
  • The default exploit profile targets mod_php under Apache prefork with display_errors = 1, memory_limit = 8M (or below --huge-mb), max_input_vars = 1000, session.use_cookies = 1 and session.use_strict_mode = 0.
  • Calibrated for php:8.4.26-apache on Debian 12 (--profile bookworm) and for custom Apache 2.4.68 builds (--profile lab). Other layouts need --zif-offset and --dtor-offset. Local Docker targets can be auto-profiled via docker/offsets.py.
  • Confirmed on php-src 8.4.4 and 8.2.34. The page says PHP 5, 6, 7 and 8 "may be affected". EOL branches (5.x, 7.x, 8.0, 8.1) get no official patch.

What to do

Disable the feature (file uploads keep working), then reload the service:

session.upload_progress.enabled = Off
php_admin_flag[session.upload_progress.enabled] = off

The second line is for FPM pool files such as /etc/php/*/fpm/pool.d/www.conf. The repo's helper script:

sudo ./quick-fix/run.sh --check
sudo ./quick-fix/run.sh --dry-run
sudo ./quick-fix/run.sh
sudo ./quick-fix/run.sh --revert

When building from source, apply patch/session-upload-progress-counters.patch, which stores the counters as zend_long and adds php_session_rfc1867_sync_counters():

git apply --check /path/to/patch/session-upload-progress-counters.patch
git apply /path/to/patch/session-upload-progress-counters.patch

Then rebuild, install and restart. For PHP 5.6, 7.4, 8.0 and 8.1, the page links third-party backports in Anton-Barinov/php2shell-patches. They build side by side into /opt/php-<ver>-patched.

Other controls in the repo:

  • FrankenPHP: php_ini session.upload_progress.enabled 0 inside the frankenphp block.
  • ModSecurity: apache/modsecurity-php2shell.conf denies requests whose ARGS_NAMES equal PHP_SESSION_UPLOAD_PROGRESS (rule id 1026109618).
  • Apache and Lighttpd: apache/.htaccess and lighttpd/php2shell.conf block POST, PUT and PATCH requests with multipart/form-data on paths that take no uploads.
  • Cloudflare: templates are in cloudflare-rule-fix/.

For detection, alert on PHP workers (php-fpm, php-cgi, php-cgi.exe, httpd, apache2) spawning:

  • shells (/bin/sh, /bin/bash, cmd.exe, powershell.exe);
  • python or perl;
  • curl, wget, nc or certutil.exe;
  • reverse-shell strings (/dev/tcp/, fsockopen, mkfifo);
  • recon commands (whoami, id, uname -a, ipconfig).

Where no EDR is present, run process-watcher in observe mode. After suspected compromise, isolate the host, keep web and PHP logs, and check /tmp and /var/tmp for dropped files.

Caveats

  • Vendor patches were scheduled for about October 21 at 14:00 UTC. The page does not confirm release or give fixed version numbers.
  • The page warns against blocking on the PHPSESSID cookie alone, because it breaks valid sessions. Blanket multipart blocking breaks uploads, so scope it to non-upload routes.
  • The exploit is tuned to specific builds. Success elsewhere depends on correct offsets and a matching configuration.
  • The author states the repo is for authorized research only.

Organisations named here

  • php_session_rfc1867_callback
  • zend_call_function
  • zif_system

CVEs named here

  • CVE-2026-109618
  • CVE-2026-109619

Technologies named here

  • PHP core
  • poc_109618.py
  • Official Docker PHP image
  • docker/offsets.py
  • Apache HTTP Server
  • process-watcher
  • WordPress
  • quick-fix/run.sh
  • patch/session-upload-progress-counters.patch
  • Drupal
  • Joomla
  • Anton-Barinov/php2shell-patches
  • cloudflare-rule-fix/
  • Magento
  • frankenphp/Caddyfile-snippet
  • OpenCart
  • cPanel
  • lighttpd/php2shell.conf
  • Plesk
  • apache/modsecurity-php2shell.conf
  • FrankenPHP
  • apache/.htaccess
  • lighttpd
  • PHP
  • Docker
  • Cloudflare
  • Huntress
  • WatchTowr

Techniques named here

  • Remote ASLR bypass via OOM-induced memory leak
  • Remote base address leak via session serialization alignment
  • HTTP worker rotation for clean heap state
  • Detection via anomalous child process monitoring
  • Use-after-free

Threat actors named here

  • PHP2Shell