Zurück zur Übersicht

    php2shell (CVE-2026-109618, CVE-2026-109619): Hintergrund, Patches und Erkennung

    PHP hat am 21. Oktober 2026 Sicherheitsupdates für zwei Schwachstellen mit CVSS 9.2 veröffentlicht. Betroffen sind praktisch alle PHP-Versionen, Fixes gibt es nur für die Zweige 8.2 bis 8.5. Technische Details waren bereits vor dem Release öffentlich. Unter Apache mit mod_php und unter LiteSpeed reicht das Paket-Update allein nicht; die PHP-Prozesse müssen vollständig neu gestartet werden.

    Veröffentlicht am von NEOSEC
    PHPZero-DayRCEDFIRNIS2

    Am 20. Oktober 2026 kündigte das PHP-Projekt für den Folgetag ein außerplanmäßiges Sicherheitsrelease an. Noch vor dem Release veröffentlichte der Researcher J4ck3LSyN auf jackalsyn.com eine technische Analyse mit Proof-of-Concept; Beobachter gehen von rund 14 Stunden vor dem geplanten Veröffentlichungstermin aus. Das SANS Internet Storm Center hob am 21. Oktober den InfoCon auf Gelb und verwies auf Berichte von Cloudflare über erste Ausnutzungsversuche. Um 14:00 UTC erschienen die Fixes.

    Die Schwachstellen tragen die Kennungen CVE-2026-109618 und CVE-2026-109619 und werden inzwischen unter dem Namen php2shell geführt. Das PHP-Projekt bewertet beide mit CVSS 4.0 9.2. Nach Angaben eines Mitglieds des PHP-Security-Teams auf oss-security wurde unauthentifizierte Codeausführung gegen Apache mit mod_php demonstriert.

    Zur Veröffentlichung von J4ck3LSyN

    Die Analyse auf jackalsyn.com ist die meistzitierte öffentliche Quelle und der Grund, warum die Schwachstelle vor dem Patch diskutiert wurde. Zu ihrer Einordnung:

    Der veröffentlichte PoC ist gegen die LiteSpeed-SAPI (lsphp) gebaut, nicht gegen php-fpm. Er beschreibt die Lücke als Use-after-free im Handler für session.upload_progress. Laut VulnCheck trifft keiner der geprüften öffentlichen PoCs den tatsächlichen Mechanismus. Kevin Beaumont vermutet, dass die Analyse aus den php-src-Commits abgeleitet wurde. Der session.upload_progress-Pfad ist allerdings einer der bestätigten Wege, über die der Fehler ausnutzbar ist.

    Auch eine unvollständige Analyse verkürzt für Angreifer die Zeit bis zu einem funktionierenden Exploit, weil sie die relevante Codestelle benennt.

    Technischer Hintergrund

    Die folgende Beschreibung stützt sich auf den Fix-Commit in php-src (82f8f31b16a, „Avoid state corruption via bailout“) und dessen Analyse im Repository rjmendez/phpup-2026.

    Bei einem Speicherfehler, etwa wenn memory_limit überschritten wird, ruft PHP zend_mm_safe_error auf. Diese Funktion beendet den Request über zend_error_noreturn und zend_bailout(), beides longjmp-basierte Sprünge. Aufräumcode zwischen Fehlerstelle und Sprungziel wird dabei übersprungen. Dadurch können prozessweite Zustände des abgebrochenen Requests erhalten bleiben, unter anderem Error-Handler, Exception-Zustand, Objekt-Store, die Container für $_GET, $_POST und $_COOKIE sowie Authentifizierungsfelder der Request-Informationen.

    Bedient derselbe Worker-Prozess anschließend einen weiteren Request, kann dieser auf den alten Zustand zugreifen, bevor seine eigene Initialisierung ihn zurücksetzt. Es handelt sich also um eine Zustandskorruption über Request-Grenzen hinweg.

    Ein Angriff braucht demnach zwei Schritte:

    • Ein erster Request löst den Speicherfehler aus. Dafür genügte ein einzelner Multipart-Teil mit sehr vielen Header-Zeilen, da PHP jede dieser Zeilen speicherte. Im Labor von rjmendez lag der Speicherverbrauch im PHP-Prozess beim etwa 58-Fachen der übertragenen Datenmenge.
    • Ein folgender Request auf demselben Worker liest den liegengebliebenen Zustand. Bestätigt sind der session.upload_progress-Pfad in der Multipart-Verarbeitung und frühe INI-Diagnosemeldungen, etwa durch php_value in einer .htaccess unter mod_php.

    Der Fix ersetzt den Sprung durch einen sofortigen Prozessabbruch mit _exit(1), speichert bei Multipart-Teilen nur noch Content-Disposition und Content-Type und ändert den Aufbau der Superglobals so, dass freigegebener Speicher schwerer gezielt neu belegt werden kann.

    Betroffene Systeme

    Laut SANS ISC sind alle PHP-Versionen ab mindestens PHP 5 betroffen, einschließlich der aktuellen Releases. Die Schwachstelle liegt im PHP-Kern und besteht in der Standardkonfiguration. Damit sind auch alle darauf aufbauenden Anwendungen betroffen, etwa WordPress, Nextcloud, TYPO3, Shopware, Matomo, Roundcube oder das Zabbix-Frontend, ebenso intern betriebene Anwendungen.

    Das PHP-Advisory bewertet das Risiko unter Apache mit mod_php als am höchsten. Eine Erklärung liefern die Laborergebnisse von rjmendez: php-fpm beendet einen Worker, wenn der Fehler während des Request-Starts auftritt, und startet einen neuen. Der fehlerhafte Zustand verschwindet mit dem Prozess. Unter mod_php gibt es keinen vergleichbaren Mechanismus; der Worker läuft weiter und bedient den nächsten Request. Ob php-fpm in allen Konstellationen auf diese Weise geschützt ist, ist nicht belegt.

    Verfügbare Fixes

    ZweigFixSicherheitsupdates bis
    8.58.5.1231.12.2029
    8.48.4.2731.12.2028
    8.38.3.3631.12.2027
    8.28.2.3531.12.2026
    8.1 und älterkein Fix vom PHP-Projektbeendet

    Bei der Prüfung des Patchstands sind drei Punkte zu beachten:

    Backports der Distributionen. Ubuntu und Red Hat übernehmen Fixes in die bestehende Versionsnummer. Ubuntu 24.04 meldet weiterhin PHP 8.3.6; php -v sagt dort nichts über den Patchstand aus. Maßgeblich ist die Paketversion oder der Changelog, unter Ubuntu etwa mit zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php8.3-fpm/changelog.Debian.gz.

    Remi-Repository. Das Repository für RHEL, AlmaLinux und Rocky Linux hatte den Fix am 21. Oktober noch nicht. Die PHP Foundation empfiehlt in diesem Fall die Pakete der Distribution oder einen Build aus den Quellen.

    PHP in anderen Produkten. FrankenPHP, Docker-Images, Plesk, XAMPP, MAMP und Laragon bringen eigene PHP-Versionen mit. FrankenPHP ab 1.13.2, die offiziellen Docker-Images und Plesk haben den Fix ausgeliefert. XAMPP steht seit November 2023 auf PHP 8.2.12; ein Update ist nicht angekündigt.

    Neustart nach dem Update

    Ein Paket-Update ersetzt die Dateien auf der Festplatte. Laufende Prozesse verwenden das alte PHP weiter, bis sie neu gestartet werden.

    BetriebsartErforderlicher Schritt
    php-fpmsystemctl restart php8.x-fpm; ein reload lädt das neue Binary ebenfalls
    Apache mit mod_phpsystemctl restart apache2 bzw. httpd; reload und apachectl graceful laden das Modul nicht neu
    LiteSpeed / OpenLiteSpeedlsphp-Pakete aktualisieren, anschließend pkill lsphp; ein Neustart von LiteSpeed beendet die PHP-Prozesse nicht
    Docker / FrankenPHPaktualisiertes Image beziehen, Container neu erstellen
    Queue-Worker, Supervisor, Laravel OctaneProzesse neu starten; octane:reload lädt nur den Anwendungscode neu

    Ob noch Prozesse mit dem alten Binary laufen, lässt sich unter Linux über die Memory-Maps prüfen. Gelöschte, aber noch geladene Dateien erscheinen dort mit dem Zusatz (deleted):

    sudo grep -lE ' /(usr|lib|opt).*\(deleted\)$' /proc/[0-9]*/maps
    

    Ist die Ausgabe leer, laufen alle Prozesse mit dem aktualisierten PHP.

    Zusätzliche Härtung

    Laut PHP-Advisory gibt es keine Konfigurationseinstellung, die die Schwachstelle vollständig abschaltet. Zwei Einstellungen sollten dennoch dauerhaft gesetzt werden:

    session.upload_progress.enabled = Off
    session.use_strict_mode = 1
    

    Die erste deaktiviert einen der bestätigten Ausnutzungspfade; die Upload-Fortschrittsanzeige von PHP wird von kaum einer Anwendung genutzt. Die zweite empfiehlt das PHP-Projekt grundsätzlich.

    Für Systeme, die vorerst nicht aktualisiert werden können, lässt sich der zweite Angriffsschritt verhindern, indem Worker-Prozesse nicht wiederverwendet werden: pm.max_requests = 1 in php-fpm bzw. MaxConnectionsPerChild 1 in Apache. Jeder Request läuft dann in einem neuen Prozess. Das reduziert die Leistung deutlich und ist als Übergangslösung bis zur Migration gedacht.

    Vorübergehende Sperren von Multipart-Requests am Webserver oder in der WAF sollten nach dem Update entfernt werden, da sie auch legitime Datei-Uploads verhindern.

    PHP 8.1 und älter

    Für PHP 7.x und 8.1 stellt das PHP-Projekt keinen Fix bereit. Einzelne Anbieter portieren den Fix zurück: Canonical gegebenenfalls für Ubuntu 22.04 (PHP 8.1) und über Ubuntu Pro für 20.04 und 18.04, Red Hat gegebenenfalls für die eigenen Module, Freexian im kostenpflichtigen ELTS für Debian 11 (PHP 7.4). Zend gibt an, dass die kommerziellen LTS-Builds für 7.2, 7.3, 7.4 und 8.1 den Fix bereits enthalten.

    Ein Backport behebt diese beiden Schwachstellen, ändert aber nichts daran, dass der Zweig keine regulären Sicherheitsupdates mehr erhält. Migrationen sollten direkt auf PHP 8.4 oder 8.5 zielen, da die Sicherheitsunterstützung für 8.2 am 31. Dezember 2026 endet.

    Hinweise auf einen Angriff

    Ein Update beseitigt die Schwachstelle, gibt aber keine Auskunft darüber, ob sie vorher ausgenutzt wurde. Folgende Indikatoren sind belastbar:

    php-fpm: Worker beendet mit Exit-Code 70. Im php-fpm-Log erscheint child <pid> exited with code 70 after <N> seconds from start, gefolgt vom Start eines neuen Workers. php-fpm gibt Code 70 unter anderem dann zurück, wenn php_request_startup() fehlschlägt, also bei einem Fehler während der Multipart-Verarbeitung vor dem Anwendungscode. Code 70 tritt auch bei anderen Startfehlern auf und belegt für sich genommen keine erfolgreiche Ausnutzung. Er zeigt aber, dass ein Request den betroffenen Codepfad erreicht hat. Zu prüfen ist dann der unmittelbar folgende Request auf demselben Pool.

    mod_php: Speicherfehler vor dem Anwendungscode. Im Apache-Error-Log ein PHP Fatal error: Allowed memory size of ... bytes exhausted, typischerweise mit der Ortsangabe in Unknown on line 0, da noch kein Skript ausgeführt wurde. Weil der Worker unter mod_php weiterläuft, ist dies dort der wichtigste Hinweis auf dem Host.

    Prozessstarts durch den Webserver-Benutzer. Eine Shell, curl, wget oder ein Interpreter, gestartet als www-data, apache oder als Site-Benutzer unter lsphp. Im Normalbetrieb der meisten Webanwendungen ist das nicht vorgesehen.

    Neue PHP-Dateien im Webroot, insbesondere in Verzeichnissen für Uploads, Bilder oder Cache.

    Ein HTTP-Status 502 ist kein verlässliches Signal. Hatte PHP die Antwort-Header bereits gesendet, liefert nginx in den Tests von rjmendez Status 200 mit leerem Inhalt.

    Als Prüfzeitraum für Logs empfiehlt sich der Zeitraum ab dem 20. Oktober. Für den veröffentlichten PoC gibt es zusätzlich konkrete Merkmale: User-Agent php2shell-109618 bzw. php2shell-109619, Multipart-Boundaries B7kQpoc618 bzw. B7kQpoc619 und eine PHPSESSID mit dem Präfix atlas gefolgt von 24 Hex-Zeichen. Diese Merkmale identifizieren nur dieses eine Werkzeug, nicht die Ausnutzung der Schwachstelle allgemein.

    Meldepflichten

    Die Schwachstelle war vor Verfügbarkeit des Patches öffentlich beschrieben und betrifft jede aus dem Internet erreichbare PHP-Anwendung. Betreiber, deren Systeme in diesem Zeitraum verwundbar erreichbar waren, sollten die Logs auf die genannten Hinweise prüfen. Ergibt sich daraus ein erheblicher Sicherheitsvorfall bzw. eine Verletzung des Schutzes personenbezogener Daten, gelten die Fristen nach NIS2 (24 Stunden für die Erstmeldung) und nach Artikel 33 DSGVO (72 Stunden), jeweils ab Kenntnis.

    Quellen