
PHP2Shell technisch erklärt: Ursache, Angriffsweg und Patch
PHP2Shell sind zwei kritische Lücken im Kern von PHP, CVE-2026-109618 und CVE-2026-109619. Dieser Ratgeber erklärt sie für Admins, Entwickler und technisch versierte Website-Betreiber. Er zeigt, wie ein Speicherfehler zu Codeausführung wird, was der Patch im PHP-Quellcode ändert und wie Sie den Patch auf Debian, Ubuntu, RHEL und Docker einspielen und kontrollieren.
Stand: 23.10.2026. Paketstände und Empfehlungen ändern sich noch. Wir aktualisieren den Artikel, die Quellen sind jeweils verlinkt. Eine Erklärung ohne Technik finden Sie im Ratgeber PHP2Shell einfach erklärt.
Was technisch hinter PHP2Shell steckt
Beide Lücken haben dieselbe Wurzel: Wie PHP einen Request abbricht, wenn ein fataler Fehler auftritt. Der häufigste Fall ist ein Speicherfehler, also das Erreichen von memory_limit. Bis zum Patch sprang PHP in diesem Moment per longjmp() direkt aus dem laufenden Code heraus, so beschreibt es das GitHub-Advisory GHSA-w8hw-w9fx-j79w des PHP-Projekts. Der unterbrochene Code konnte seine Daten nicht mehr fertig schreiben oder aufräumen.
Daraus entstehen zwei Probleme. Entweder bleiben Daten halb fertig im Speicher des aktuellen Requests. Oder ein globaler Zustand zeigt nach dem Abbruch noch auf Speicher, den PHP schon freigegeben hat. Beides lässt sich zu Speicherkorruption ausbauen, und die führt im schlimmsten Fall zu Codeausführung mit den Rechten des PHP-Prozesses.
CVE-2026-109618: Abbruch mitten im Schreiben
PHP fasst diese Lücke als „RCE via OOM corruption“ zusammen. OOM steht für „out of memory“. Laut dem Advisory auf php.net kann der Speicherabbruch PHP unterbrechen, während interne Request-Daten erst teilweise angelegt sind. Das Aufräumen am Ende des Requests behandelt diese Daten dann als gültig.
Ein Beispiel beschreibt das Forschungsteam von Calif. PHP speichert Arrays und Request-Variablen in Hashtabellen. Beim Einfügen eines Eintrags erhöht PHP zuerst den Zähler der Tabelle und füllt erst danach den neuen Eintrag. Bricht der Speicherfehler genau dazwischen ab, meldet die Tabelle einen Eintrag, den es nicht gibt. Beim Aufräumen verarbeitet PHP den leeren Platz wie einen echten Eintrag.
Wie Angreifer den Speicher gezielt überlaufen lassen
Ein solcher Fehler wird erst gefährlich, wenn ein Angreifer den Zeitpunkt des Abbruchs steuern kann. Eigentlich sollen post_max_size und memory_limit genau das verhindern. Calif zeigt, warum sie es nicht tun. PHP prüft bei post_max_size die angegebene Länge der Anfrage, nicht den Speicher, den das Zerlegen der Anfrage tatsächlich belegt.
Der Schlüssel ist das Format multipart/form-data, in dem Formulare Dateien hochladen. PHP zerlegt diesen Body, bevor eine einzige Zeile Ihrer Anwendung läuft. Leere Datei-Felder mit verschachtelten Feldnamen erzeugen dabei interne Einträge, ohne auf die Upload-Grenzen angerechnet zu werden. Das GitHub-Advisory nennt außerdem Header ohne Mengenbegrenzung. So wächst eine kleine Anfrage im Speicher auf ein Vielfaches ihrer Größe, und ein Angreifer kann den Überlauf auf eine bestimmte Stelle legen.
CVE-2026-109619: Zustand, der den Request überlebt
Die zweite Lücke nutzt aus, dass ein PHP-Worker viele Requests nacheinander bearbeitet. Das GitHub-Advisory GHSA-6wmf-4rv5-p3rp beschreibt zwei Rollen. Ein erster Request bricht ab und hinterlässt einen globalen Zeiger auf freigegebenen Speicher. Ein zweiter Request im selben Worker liest diesen Zeiger, bevor PHP den Zustand neu initialisiert. In der Fachsprache heißt das Use-after-free.
Bestätigt sind laut PHP zwei Wege. Der erste läuft über Session Upload Progress, eine Funktion, die den Fortschritt von Uploads in der Session festhält. Sie läuft vor der normalen Session-Initialisierung, also auch dann, wenn die Anwendung nie session_start() aufruft. Der zweite betrifft nur PHP 8.5 und läuft über den Backtrace des letzten fatalen Fehlers (fatal_error_backtraces). Wiz Research beschreibt zusätzlich einen Weg über OPcache, bei dem sich mehrere Worker einen beschädigten Zustand im gemeinsamen Speicher teilen.
Das Speicher-Leak über den Session-Cookie
Laut Wiz lässt sich über denselben Mechanismus Speicher auslesen, ohne Code auszuführen. Ein veralteter Zeiger auf die Session-ID führt dazu, dass PHP fremde Speicherinhalte URL-kodiert in den Cookie PHPSESSID der Antwort schreibt. Darin können Passwörter, API-Schlüssel, Tokens und private TLS-Schlüssel aus anderen Requests stehen. Wiz ordnet diesen Weg CVE-2026-109618 zu, PHP führt den Upload-Progress-Pfad unter CVE-2026-109619. Maßgeblich ist die Zuordnung von PHP.
Welche Server-Setups am stärksten betroffen sind
Betroffen sind laut PHP alle Installationen, die Web-Requests bedienen. Wie leicht ein Angriff gelingt, hängt aber von der Server-API (SAPI) ab. Mit Apache und mod_php überlebt ein Worker einen Abbruch beim Start des Requests und trägt den Zustand weiter. PHP-FPM beendet den Worker in diesem Fall, damit fällt ein Teil der Wege weg.
| SAPI | Einschätzung laut PHP-Advisories |
|---|---|
| Apache mit mod_php | Am stärksten exponiert. Beide Lücken mit Codeausführung ohne Login bestätigt, mit Standardgrenzen. |
| PHP-FPM | Weg über Session Upload Progress bestätigt. Für CVE-2026-109618 laut Quellcode-Analyse anfällig, ohne vollständigen Exploit. |
| FrankenPHP | Wahrscheinlich anfällig. Im Standard ohne bestätigten Weg für CVE-2026-109619, laut PHP aber nicht immun. |
| LiteSpeed (LSAPI) | Wahrscheinlich anfällig, anwendungsspezifische Exploits nicht bestätigt. |
Die Anwendung spielt für die Lücke keine Rolle. Calif hat Codeausführung ohne Login unter anderem an WordPress, Drupal, Joomla, MediaWiki, Roundcube, Magento, phpMyAdmin, Nextcloud, Laravel und Symfony gezeigt. Laut Wiz kann schon ein einfaches „Hello World“-Skript auf einer anfälligen PHP-Version angreifbar sein.
Warum die Lücke über 20 Jahre alt ist
Das Muster ist lange bekannt. Calif zeichnet die Geschichte nach. 2004 fand der Sicherheitsforscher Stefan Esser die erste aus der Ferne ausnutzbare Lücke rund um memory_limit, bekannt als CVE-2004-0594. 2020 meldete jemand den PHP-Bug #78876, bei dem lange Variablen einen Speicherfehler auslösten und temporäre Dateien liegen blieben. 2024 fand ein Audit von OSTIF und Quarkslab ein verwandtes Problem. Weil niemand zeigen konnte, dass es ausnutzbar ist, blieb es offen.
Der Durchbruch kam 2026 mit KI-Unterstützung. Calif fand am 1. August einen ersten Auslöser samt Unterbrechungspunkt, Wiz unabhängig davon am 19. August die erste Lücke. Laut Wiz halfen die KI-Modelle vor allem dabei, die Exploits an verschiedene PHP-Versionen und Speicherlayouts anzupassen. Diese Arbeit hätte früher ein Expertenteam Monate gekostet. Was das für die Zeit zwischen Patch und Angriff bedeutet, erklärt unser Beitrag über KI und Sicherheitslücken am Beispiel PHP2Shell.
Was der Patch im PHP-Quellcode ändert
Der Patch setzt an der Ursache an, nicht an einzelnen Angriffswegen. Für CVE-2026-109618 entfernt er laut GHSA-w8hw-w9fx-j79w den Sprung per longjmp() beim Speicherfehler. Ein „weicher“ Speicherfehler greift jetzt erst am nächsten sicheren Punkt der Ausführung, an dem keine Daten halb fertig sind. Ein „harter“ Speicherfehler oberhalb einer höheren Schwelle beendet den Prozess sofort mit _exit().
Für CVE-2026-109619 setzt der Patch alle betroffenen globalen Zustände zurück, bevor PHP den Speicher des Requests freigibt. Das betrifft Fehler-, Session-, Objekt- und Extension-Zustände. Laut Wiz schließt der Patch damit auch Varianten, die nicht einzeln gemeldet wurden.
Unsere Einschätzung für den Betrieb: Nach dem Update können PHP-Worker bei extremem Speicherbedarf häufiger beendet werden als vorher. Steigt danach die Zahl der Worker-Neustarts in Ihren Logs, ist das nicht automatisch ein Angriff. Prüfen Sie dann zuerst, ob einzelne Skripte ungewöhnlich viel Speicher brauchen.
PHP2Shell patchen: Befehle mit Quelle
Wichtiger Hinweis zu allen Befehlen: Die Befehle sind Beispiele für gängige Standard-Installationen und ohne Gewähr. Paketnamen, Versionen und Dienstnamen weichen je nach System ab. Legen Sie vor jedem Update ein Backup an, testen Sie zuerst auf einem Staging-System und gleichen Sie jeden Befehl mit der genannten Quelle ab. Wenn Sie unsicher sind, lassen Sie das Update von Ihrem Hoster oder einem Dienstleister einspielen.
Korrigiert sind laut php.net diese Versionen:
| PHP-Zweig | Fix-Version | Hinweis |
|---|---|---|
| 8.5 | 8.5.12 | offizielles Release |
| 8.4 | 8.4.27 | offizielles Release |
| 8.3 | 8.3.36 | offizielles Release |
| 8.2 | 8.2.35 | offizielles Release, Support-Ende am 31.12.2026 |
| 8.1, 8.0, 7.4 | kein Release | nur Backports im Quellcode, Pakete über Distribution oder LTS-Anbieter |
Distributionen übernehmen den Fix oft, ohne die Versionsnummer zu ändern. Ein Ubuntu-Paket mit 8.3.6 kann also gepatcht sein, obwohl 8.3.36 die offizielle Fix-Version ist. Entscheidend ist der Paketstand, nicht die Zahl hinter „PHP“. Wie Sie die Version richtig lesen, zeigt der Ratgeber PHP-Version herausfinden.
Debian und Ubuntu
Ubuntu schreibt in USN-8948-1 vom 21.10.2026, dass ein normales System-Update ausreicht. Gepatcht sind dort unter anderem 24.04 LTS mit php8.3 8.3.6-0ubuntu0.24.04.13 und 22.04 LTS mit php8.1 8.1.2-1ubuntu2.28. Für ältere Releases gibt es USN-8948-2. Bei Debian sind laut Debian Security Tracker Debian 13 mit php8.4 8.4.27-1~deb13u1 (DSA-6574-1) und Debian 12 mit php8.2 8.2.35-1~deb12u1 (DLA-4848-1) gepatcht.
sudo apt update
sudo apt upgradeQuelle: Update-Hinweis in USN-8948-1.
Danach prüfen Sie, ob das installierte Paket die CVE-Nummern im Changelog führt. Ersetzen Sie php8.3-fpm durch Ihr Paket, zum Beispiel libapache2-mod-php8.2 bei mod_php.
zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php8.3-fpm/changelog.Debian.gzQuelle: Ablageort der Changelogs laut Debian Policy Manual, Kapitel 12, CVE-Prüfung wie bei lilting.ch beschrieben. Gibt der Befehl nichts aus, ist der Fix in Ihrem Paket noch nicht enthalten.
Wer PHP aus dem Repository von Ondřej Surý (sury.org) bezieht, findet dort laut lilting.ch keine CVE-Nummern im Changelog. Prüfen Sie dann die Paketversion mit dpkg -l 'php*' gegen die Angaben des Repositorys.
RHEL, AlmaLinux und Rocky Linux
Red Hat hat am 21.10.2026 das Erratum RHSA-2026:87072 für RHEL 9 und den Modul-Stream php:8.2 veröffentlicht (Paket 8.2.35). Für andere Streams und für AlmaLinux und Rocky Linux prüfen Sie die Errata der jeweiligen Distribution.
sudo dnf upgrade --refresh 'php*'
rpm -q --changelog php-fpm | grep -E 'CVE-2026-10961[89]'Quelle: Changelog-Prüfung laut lilting.ch, Update-Ablauf laut Red Hat. Für Nutzer des Remi-Repositorys galt am 21.10.2026: Das PHP-Projekt rät laut php.net, auf Distributionspakete umzusteigen oder aus dem Quellcode zu bauen, weil das Repository an diesem Tag kein Update hatte. Prüfen Sie den aktuellen Stand direkt bei Remi.
Docker und Container
Ein Neustart des alten Containers lädt keinen neuen Code. Sie müssen das Image auf einer gepatchten Basis neu bauen und die Container neu erstellen. Die offiziellen php-Images auf Docker Hub standen am Abend des 21.10.2026 mit den Fix-Versionen bereit.
docker compose build --pull
docker compose up -d --force-recreateQuelle: Optionen --pull und --force-recreate laut Docker-Dokumentation zu docker compose build und docker compose up. Pinnen Sie im Dockerfile eine feste Version, zum Beispiel php:8.3.36-fpm, wenn Sie sicherstellen wollen, dass der Build die Fix-Version nutzt.
Plesk und andere Panels
Bei Plesk, cPanel oder CloudLinux liefert der Hersteller die PHP-Handler aus, installieren müssen Sie oder Ihr Admin sie selbst. Bei Plesk ist zusätzlich das panel-eigene PHP betroffen. Den Stand für Plesk fassen wir auf unserer Seite zur PHP2Shell-Sicherheitslücke zusammen. Für Shared Hosting gilt der Ratgeber zum Stand bei Strato, IONOS und anderen Hostern.
PHP 8.1 und älter
Für 7.4, 8.0 und 8.1 hat das PHP-Projekt nur minimale Backports im Quellcode bereitgestellt, keine Releases. Pakete gibt es über Distributionen wie Ubuntu 22.04, über sury.org oder über kommerzielle LTS-Anbieter. Für 5.4 bis 7.3 gibt es keinen Fix, obwohl Wiz diese Versionen für betroffen hält. Die Stichtage aller Zweige stehen im Überblick zum Support-Ende der PHP-Versionen.
Neustart und Kontrolle: Erst dann wirkt der Patch
Ein installiertes Paket ändert nichts an Prozessen, die schon laufen. Die Worker haben den alten Code im Speicher. Starten Sie deshalb alle PHP-Dienste neu. Die Dienstnamen unterscheiden sich je nach System, systemctl list-units '*php*' zeigt die vorhandenen.
# Debian und Ubuntu mit PHP-FPM
sudo systemctl restart php8.3-fpm
# RHEL-Familie mit PHP-FPM
sudo systemctl restart php-fpm
# Apache mit mod_php (Debian/Ubuntu: apache2, RHEL: httpd)
sudo systemctl restart apache2Quelle: Neustart nach dem Update laut lilting.ch, Befehl laut systemctl-Dokumentation. Vergessen Sie Queue-Worker, Supervisor-Prozesse und lang laufende Server wie Laravel Octane oder RoadRunner nicht.
Auf Debian und Ubuntu zeigt das Werkzeug needrestart, welche Prozesse noch alte Bibliotheken oder Programme im Speicher haben:
sudo needrestart -b -r lQuelle: Optionen -b (Batch-Ausgabe) und -r l (nur auflisten, nichts neu starten) laut needrestart-Projekt.
Zum Schluss prüfen Sie die Version, die der Webserver tatsächlich nutzt. php -v zeigt nur die Kommandozeile, die eine andere Version nutzen kann als PHP-FPM oder mod_php. Legen Sie eine Datei mit <?php phpinfo(); unter einem zufälligen Namen an, rufen Sie sie einmal im Browser auf und löschen Sie sie sofort. Achten Sie auf die Zeilen „PHP Version“ und „Server API“. Mehr Wege zeigt der Ratgeber PHP-Version herausfinden.
Was Übergangsmaßnahmen leisten und was nicht
Wenn Sie nicht sofort patchen können, nennt das PHP-Projekt Maßnahmen, die einzelne Angriffswege blockieren. PHP schreibt dazu ausdrücklich, es gebe keine vollständige Abhilfe, nur das Update sei eine sichere Wahl. Die folgende Übersicht fasst die Angaben aus dem Advisory auf php.net und den beiden GitHub-Advisories zusammen.
| Maßnahme | Wirkt gegen | Grenze |
|---|---|---|
memory_limit=-1 per php_admin_value | CVE-2026-109618 | Keine Speichergrenze pro Request mehr, Risiko für Denial of Service. Ein Limit über Container oder cgroup ergänzen, nicht über RLIMIT_AS oder RLIMIT_DATA. |
post_max_size 8M ohne Uploads, 32M mit Uploads | CVE-2026-109618 | Senkt die Angriffsfläche, verhindert den Überlauf aber nicht sicher. |
session.upload_progress.enabled=0 | CVE-2026-109619 | Blockiert nur den bestätigten Session-Weg, nicht andere Varianten. |
fatal_error_backtraces=0 | CVE-2026-109619 | Nur unter PHP 8.5, nur der Backtrace-Weg. |
pm.max_requests=1 im FPM-Pool | CVE-2026-109619 | Kostet viel Leistung, senkt nur die Erfolgsquote. |
Wichtig ist der Ort der Einstellung. Sie muss gelten, bevor PHP den Request zerlegt, also in der php.ini, im FPM-Pool oder in der Server-Konfiguration. ini_set() oder eine .user.ini reichen nicht. Ein Beispiel für einen FPM-Pool:
; Übergangslösung bis zum Update, danach wieder entfernen
php_admin_value[memory_limit] = -1
php_admin_flag[session.upload_progress.enabled] = offQuelle: Werte laut php.net-Advisory, Syntax laut PHP-Handbuch zur FPM-Konfiguration. Danach müssen Sie alle Worker neu starten. Nach dem Patch setzen Sie memory_limit wieder auf einen festen Wert.
Eine Web Application Firewall senkt das Risiko zusätzlich. Cloudflare hat am 21.10.2026 Regeln gegen PHP2Shell für alle Tarife aktiviert. Eine WAF ersetzt den Patch aber nicht, denn sie erkennt nur bekannte Muster.
Vorsicht bei Exploit-Skripten aus dem Netz
Seit dem 20.10.2026 kursieren Videos, Screenshots und angebliche Proof-of-Concepts zu PHP2Shell. Die PHP Foundation schreibt, dass sie zum Release noch keinen funktionierenden Exploit gefunden hatte, obwohl schon Proof-of-Concepts kursierten. Was ein beliebiges Skript aus dem Netz tatsächlich tut, ist also offen. Es kann wirkungslos sein oder selbst Schadcode enthalten.
Führen Sie solche Skripte nicht aus, um Ihren Server zu „testen“. Ein negativer Test beweist nichts, denn der echte Angriff hängt von Build, Extensions und Speicherlayout ab. Und ein fremdes Skript auf Ihrem Admin-Rechner kann genau die Zugangsdaten abgreifen, die Sie schützen wollen. Der verlässliche Test ist der Paketstand plus Neustart, wie oben beschrieben.
Spuren prüfen: ab dem 17. Oktober
Ein Update schließt die Lücke, entfernt aber nichts, was ein Angreifer vorher hinterlassen hat. Amazon hat den ersten Angriffsversuch schon am 17.10.2026 aufgezeichnet. Wiz nennt diese Signale: Multipart-Requests, auf die Speicherfehler oder gehäufte HTTP-500-Antworten folgen, auffällig große oder fehlerhafte PHPSESSID-Cookies in Antworten und PHP-Worker, die ohne erkennbaren Grund ständig neu starten.
Die vollständige Liste mit Prozess- und Dateiprüfung steht auf unserer Seite zur PHP2Shell-Sicherheitslücke. Beachten Sie: Saubere Logs beweisen laut PHP nicht, dass kein Angriff stattgefunden hat.
Wenn Sie Unterstützung brauchen
Wir betreuen als Digitalagentur PHP-Anwendungen, von WordPress und Shopware bis zu eigenen Laravel-Projekten. Bei PHP2Shell übernehmen wir die Bestandsaufnahme, spielen den Patch ein oder kontrollieren den Stand Ihres Hosters, starten alle Worker neu und suchen nach Spuren. Läuft Ihre Anwendung noch auf PHP 8.1 oder älter, heben wir sie auf eine unterstützte Version. Den Ablauf und die Konditionen finden Sie auf der Seite zur PHP2Shell-Bestandsaufnahme.
Häufige Fragen zu PHP2Shell aus technischer Sicht
Reicht ein normales apt upgrade gegen PHP2Shell?
Auf Debian und Ubuntu meist ja, wenn die Distribution den Fix ausgeliefert hat. Danach müssen Sie aber alle PHP-Worker und gegebenenfalls Apache neu starten. Erst dann läuft der neue Code. Prüfen Sie zusätzlich die CVE-Nummern im Changelog des Pakets.
Warum zeigt mein Server 8.3.6, obwohl 8.3.36 die Fix-Version ist?
Distributionen wie Ubuntu übernehmen Sicherheitskorrekturen als Backport und behalten die ursprüngliche Versionsnummer. Ubuntu 24.04 liefert den Fix im Paket 8.3.6-0ubuntu0.24.04.13. Entscheidend ist der vollständige Paketstand, nicht die Nummer hinter „PHP“.
Ist PHP-FPM weniger gefährdet als mod_php?
Ja, aber nicht ungefährdet. Laut PHP ist mod_php am stärksten exponiert, weil ein Worker dort einen Abbruch beim Start des Requests überlebt. Für PHP-FPM ist der Weg über Session Upload Progress bestätigt. Beide brauchen das Update.
Schützt eine Web Application Firewall vor PHP2Shell?
Eine WAF wie die von Cloudflare senkt das Risiko, weil sie bekannte Angriffsmuster blockiert. Sie ersetzt das Update nicht. Neue Varianten oder Wege, die die Regeln nicht kennen, kommen weiter durch.
Muss ich memory_limit nach dem Patch zurücksetzen?
Ja, wenn Sie memory_limit=-1 als Übergangslösung gesetzt haben. Ohne Grenze kann ein einzelnes Skript den ganzen Speicher des Servers belegen. Setzen Sie nach dem Update wieder einen festen Wert, der zu Ihrer Anwendung passt, und starten Sie die Worker neu.