PHP2Shell: Kritische CVE-2026-109618 & CVE-2026-109619 – Technische Warnmeldung und Versionsmatrix
PHP2Shell: Kritische CVE-2026-109618 & CVE-2026-109619 – Technische Warnmeldung und Versionsmatrix
<time datetime="2026-10-23">Geprüft am 23. Oktober 2026</time> · Quellen: php.net Security Advisories, GitHub Security Advisories GHSA-w8hw-w9fx-j79w und GHSA-6wmf-4rv5-p3rp
Am 21. Oktober 2026 haben das PHP-Core-Team und mehrere Sicherheitsforschungsstellen zwei kritische Schwachstellen veröffentlicht, die gemeinsam als PHP2Shell bezeichnet werden: CVE-2026-109618 und CVE-2026-109619. Der CVSS-v4.0-Basisscore liegt bei 9,2 (Critical). Ein nicht authentifizierter Angreifer kann mit einem einzelnen HTTP-Request beliebige Betriebssystembefehle im Kontext des Webserver- oder PHP-FPM-Workers (www-data, nginx, apache) ausführen. Der entscheidende Punkt: Die Fehler liegen nicht in Anwendungscode, sondern im C-Kern der PHP-Engine, genauer in der Behandlung von RFC1867-Multipart-Uploads und der Zend-Memory-Manager-(ZMM)-Fehlerbehandlung. Framework-Middleware, Input-Validierung und die meisten WAF-Regeln greifen daher zu spät oder gar nicht.
1. Schwachstellenmatrix und gesicherte Fakten
| Merkmal | CVE-2026-109618 | CVE-2026-109619 |
|---|---|---|
| Fehlerklasse | Speicherzustandskorruption im OOM-Pfad | Verbleibender globaler Zustand / Use-After-Free (UAF) |
| CVSS v4.0 | 9,2 (Critical) | 9,2 (Critical) |
| Authentifizierung | Keine (unauthentifiziert) | Keine (unauthentifiziert) |
| Standard-Exposition | session.upload_progress standardmäßig aktiv | session.upload_progress standardmäßig aktiv |
| Auslösezeitpunkt | Request-Body-Parsing (vor Benutzercode) | Parsing und Session-Teardown |
| Betroffene Umgebungen | PHP-FPM, Apache mod_php, FrankenPHP, LiteSpeed | PHP-FPM, Apache mod_php, FrankenPHP, LiteSpeed |
| Betroffene Versionen | PHP 5.4–8.5 | PHP 5.4–8.5 |
Die betroffene Bandbreite ist PHP 5.4 bis 8.5. Zusammenfassungen, die 5.x–8.4 nennen, sind falsch: Auch der 8.5-Zweig ist vor 8.5.12 verwundbar. Da session.upload_progress seit PHP 5.4 standardmäßig auf On steht, befinden sich nahezu alle nicht explizit gehärteten Produktionsumgebungen im Angriffsbereich – unabhängig davon, ob die Anwendung Sessions verwendet.
2. Angriffslebenszyklus: Kompromittierung vor der Anwendungsausführung
Die zentrale Gefahr von PHP2Shell ist der Zeitpunkt der Ausführung. Der verwundbare C-Code läuft während des HTTP-Streamings, bevor index.php, ein Framework-Router oder ein WAF-Regelsatz auf Anwendungsebene überhaupt greifen kann.
[ EINGEHENDER HTTP-POST ]
(beliebiger Pfad: /index.php, /login, nicht existierendes /404)
│
▼
┌─────────────────────────────────────────────────────────┐
│ PHP-Engine / SAPI-Schicht (C-Kern) │
│ - liest Header, Content-Type: multipart/form-data │
└───────────────────────────┬─────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────┐
│ ext/session/session.c :: php_session_rfc1867_callback() │
│ - erkennt PHP_SESSION_UPLOAD_PROGRESS │
│ - cached rohen internen Zeiger: cached_post_bytes │
│ - [KRITISCHER FEHLER] OOM/Session-Reset tritt auf │
│ - Speicher wird FREIGEGEBEN -> Zeiger wird DANGLING │
└───────────────────────────┬─────────────────────────────┘
┌────────────────┴────────────────┐
▼ ▼
[ normale Requests ] [ PHP2Shell-Exploit ]
Anwendungscode läuft Fake-zval-Spray
(Laravel, WordPress) vtable-Hijack -> system()
▼ ▼
normale Antwort [ RCE ERREICHT ]
(noch bevor Benutzercode läuft!)
Daraus folgen drei harte Konsequenzen:
- Auslösung vor der Anwendung: Der Callback feuert während des Parsens, nicht nach dem Routing.
- Kein Upload-Formular nötig: Jeder erreichbare Endpunkt – auch ein 404-Handler – genügt.
- Sessions irrelevant: Selbst wenn die Anwendung nie
session_start()aufruft, ist der Pfad aktiv, solange die Option global aktiviert ist.
3. Ursachenanalyse: cached_post_bytes, longjmp und ZMM
In ext/session/session.c werden während des Upload-Fortschritts rohe zval-Zeiger aus der Session-HashTable in prozessweite statische Variablen kopiert.
/* ext/session/session.c – vereinfachtes Modell */
static zval *cached_post_bytes;
static zval *cached_file_bytes;
static int php_session_rfc1867_callback(unsigned int event,
void *event_data,
void **extra)
{
switch (event) {
case MULTIPART_EVENT_START: {
zval *progress = php_session_get_progress_entry();
ZVAL_LONG(&progress->value.bytes_processed, 0);
/* FEHLER: Rohadresse eines internen zval global cachen */
cached_post_bytes = &progress->value.bytes_processed;
cached_file_bytes = &progress->value.files[0].bytes_processed;
break;
}
case MULTIPART_EVENT_FILE_DATA:
/* bei jedem Chunk wird der Zeiger dereferenziert */
Z_LVAL_P(cached_post_bytes) += chunk_len;
break;
}
return SUCCESS;
}
Wird die Session neu geladen (session_reread()) oder der Eintrag per zend_hash_update() ersetzt, gibt zval_ptr_dtor den zugrunde liegenden Chunk an den Zend Memory Manager zurück. Die globalen Zeiger werden jedoch nicht invalidiert. Der nächste Chunk schreibt in freigegebenen Speicher:
*cached_post_bytes += chunk_len; /* klassischer UAF-Write */
CVE-2026-109618 erreicht dasselbe Ziel über einen anderen Pfad. Bei Überschreitung von memory_limit führt PHP einen longjmp()-Bailout aus. Wenn während des RFC1867-Streamings ein OOM auftritt, bevor alle Zwischenstrukturen vollständig initialisiert sind, verarbeitet die Cleanup-Routine teilinitialisierte Objekte. Die ZMM-Bin-Metadaten geraten dadurch in einen inkonsistenten Zustand; nachfolgende Allokationen können überlappende Chunks erhalten. Beide CVE führen zu einem gültigen Schreibpfad in freigegebenen Speicher, nur mit unterschiedlichem Auslöser.
4. Offizielle Fix-Releases und EOL-Zweige
| PHP-Zweig | Verwundbar | Erste sichere Version | Maßnahme |
|---|---|---|---|
| PHP 8.5 | < 8.5.12 | 8.5.12 | sofort aktualisieren |
| PHP 8.4 | < 8.4.27 | 8.4.27 | sofort aktualisieren |
| PHP 8.3 | < 8.3.36 | 8.3.36 | sofort aktualisieren |
| PHP 8.2 | < 8.2.35 | 8.2.35 | im Security-Support aktualisieren |
| PHP 8.1 / 8.0 / 7.4 und älter | alle | kein Upstream-Release | Distributions-Backport oder Workaround |
Für PHP 8.1 und älter gibt es keine offiziellen Upstream-Minor-Releases mehr. Nutzen Sie Backports von Ubuntu Pro, Debian LTS, CloudLinux oder RHEL, oder wenden Sie bis dahin die temporäre Mitigation an.
5. Sofortmaßnahmen für Betreiber
5.1 Laufzeit und Paketstand prüfen
# CLI- und FPM-Version
php -v
php-fpm -v
# Debian/Ubuntu
dpkg -l | grep -E '^ii\s+php[0-9.]*-(fpm|cli|common)'
# RHEL/CentOS/Rocky/AlmaLinux
rpm -qa | grep -i '^php'
# CVE-Referenz in den Distributions-Changelogs
zgrep -E "CVE-2026-10961[89]" /usr/share/doc/php*/changelog* 2>/dev/null
# FPM-Konfiguration validieren
php-fpm -t
5.2 Sofortige, unterbrechungsfreie Mitigation
; /etc/php/8.x/fpm/php.ini
session.upload_progress.enabled = Off
; /etc/php/8.x/fpm/pool.d/www.conf
php_admin_flag[session.upload_progress.enabled] = off
sudo systemctl reload php8.3-fpm
# alternativ direkt per Signal
sudo kill -USR2 "$(cat /var/run/php-fpm.pid)"
# Wirkung prüfen
php -r 'echo "upload_progress=", ini_get("session.upload_progress.enabled"), PHP_EOL;'
Diese Option deaktiviert ausschließlich den Legacy-Callback für Fortschrittsbalken. Normale Datei-Uploads über $_FILES, move_uploaded_file() und moderne Browser-File-APIs funktionieren unverändert.
5.3 Kompromittierungsindikatoren
# kürzlich erzeugte oder veränderte Dateien im Webroot
find /var/www -type f -mtime -2 -ls 2>/dev/null | head -50
# Prozesse unter www-data/nginx
ps -eo pid,user,lstart,cmd | awk '$2=="www-data"||$2=="nginx"'
# ausgehende Verbindungen (Reverse Shell)
ss -tpn | grep ESTAB | grep -E 'www-data|php-fpm'
6. Häufige Fragen
F: Beeinträchtigt session.upload_progress.enabled = Off reguläre Uploads?
Nein. Die Direktive steuert nur den 2012 eingeführten Fortschritts-Callback. Dateispeicherung, Temp-Pfade und $_FILES bleiben unberührt.
F: Reicht eine WAF als Schutz? Nein. Reale Payloads liegen häufig unter 500 Byte, sodass Größenbeschränkungen nicht greifen. Zudem wird der Request geparst, bevor Routing und WAF-Regeln auf Anwendungsebene wirksam werden. Die einzige belastbare Lösung ist der Patch oder die Deaktivierung auf Engine-Ebene.
F: Was ändert sich konkret in 8.5.12? Die Lebensdauer der globalen RFC1867-Zeiger und die Reihenfolge der Cleanup-Routinen im OOM-Bailout wurden korrigiert. 8.4.27, 8.3.36 und 8.2.35 enthalten dieselbe Korrektur als Backport.
7. Auswirkungen auf Hosting, Container und Shared-Umgebungen
Die praktische Reichweite von PHP2Shell hängt stark vom Betriebsmodell ab. In klassischen Shared-Hosting-Umgebungen mit mod_php oder PHP-FPM teilen sich viele Kunden denselben Master-Prozess. Ein erfolgreicher Exploit läuft zwar nur im Kontext des jeweiligen vHost-Benutzers, kann aber über gemeinsam genutzte Session-Verzeichnisse, OPcache-Segmente und temporäre Dateien weitere Mandanten beeinflussen. Provider sollten daher nicht nur die PHP-Pakete aktualisieren, sondern auch prüfen, ob Kunden eigene php.ini-Werte über php_admin_value überschreiben dürfen. Ist das der Fall, lässt sich die Deaktivierung von session.upload_progress nicht zentral erzwingen; hier muss die Panel-Konfiguration angepasst werden.
In Container-Umgebungen ist das Risiko oft höher, weil Basisimages über Monate hinweg unverändert weiterverwendet werden. Ein php:8.3-fpm-Image ohne explizites Update enthält weiterhin eine verwundbare Engine, selbst wenn der Anwendungscode täglich neu deployt wird. Prüfen Sie deshalb die tatsächlich laufende Version im Container und nicht nur das Tag im Registry-Eintrag:
docker run --rm php:8.3-fpm php -v
docker inspect php:8.3-fpm --format '{{json .Config.Labels}}'
docker scout cves php:8.3-fpm 2>/dev/null | head -40
Für Kubernetes empfiehlt sich zusätzlich eine Admission-Policy, die Images ohne aktuelles PHP-Patchlevel ablehnt. Ein einfacher, aber wirksamer Indikator ist ein verpflichtendes Label wie security.php.patchlevel=8.3.36, das die CI-Pipeline setzt und die Policy prüft. So wird verhindert, dass ein veraltetes Image unbemerkt wieder ausgerollt wird. Parallel sollte der securityContext mindestens allowPrivilegeEscalation: false, readOnlyRootFilesystem: true und capabilities.drop: ["ALL"] erzwingen.
Auch die Netzwerkseite verdient Aufmerksamkeit. Selbst nach einem erfolgreichen Exploit scheitert eine vollständige Übernahme häufig an fehlender Konnektivität. Egress-Firewalls mit Allowlist, DNS-Sperren für unbekannte Domains und NetworkPolicies reduzieren die Wahrscheinlichkeit, dass ein Angreifer Werkzeuge nachlädt oder Daten exfiltriert. Diese Maßnahmen ersetzen keinen Patch, erhöhen aber die Kosten eines Angriffs erheblich und verschaffen dem Incident-Response-Team Zeit.
Schließlich sollten Logs zentralisiert werden, bevor der Ernstfall eintritt. Lokale Nginx- und FPM-Logs werden von Angreifern häufig als Erstes gelöscht. Eine unveränderbare Senke – etwa ein SIEM mit Write-Once-Speicher – ist die Voraussetzung dafür, den Zeitpunkt der Kompromittierung und den Umfang der betroffenen Worker nachvollziehen zu können.
8. Referenzen
- php.net Security Releases vom 21. Oktober 2026
- GitHub Security Advisory GHSA-w8hw-w9fx-j79w (CVE-2026-109618)
- GitHub Security Advisory GHSA-6wmf-4rv5-p3rp (CVE-2026-109619)
- Ubuntu Security Tracker, Debian Security Tracker, Red Hat CVE Database
- Diagnosewerkzeug:
https://php2shell.run/checker/
Dieses Dokument dient ausschließlich der Verteidigung und Remediation. Exploit-Code wird nicht bereitgestellt. Änderungen an Produktionssystemen gehören in ein kontrolliertes Change-Management.