Show the full transcript (1,446 words)
PHP-to-shell ist der Name für diese zwei Sicherheitslücken hier, die das PHP-Team am 21. Oktober mit einem Notfall-Update geschlossen hat. Willkommen zurück bei Hood Informatik.
Beide haben einen CVSS-Score von 9,2 von 10. Das ist das Standard-Punktesystem, mit dem Schwachstellen nach ihrer Schwere bewertet werden. Beide erlauben im schlimmsten Fall Remote Code Execution ohne Authentifizierung. Das bedeutet, ein Angreifer kann über das Internet eigenen Code auf deinem Server ausführen, ohne irgendein Passwort zu kennen.
Das Besondere ist, wo dieser Fehler liegt. Er steckt nicht in WordPress oder irgendeinem Plugin, was man sonst so kennt, sondern im PHP-Interpreter selbst, also in dem Programm, das dein PHP-Code ausführt. In der schlimmsten Variante passiert der Angriff, bevor eine einzige Zeile deiner Anwendung läuft. Dein eigener Code kann also fehlerfrei sein und der Server ist trotzdem angreifbar.
PHP läuft auf Webservern, meistens in einer von zwei Varianten. Bei mod_php ist PHP direkt als Modul in den Apache-Webserver eingebaut. Bei PHP-FPM läuft PHP als eigener Dienst mit mehreren Prozessen und der Webserver reicht die Anfrage dorthin weiter. In beiden Fällen werden die PHP-Prozesse wiederverwendet. Ein Prozess bearbeitet eine Anfrage, räumt auf und nimmt dann die nächste an. Für jede Anfrage bekommt er einen eigenen Speicherbereich und der wird am Ende komplett freigegeben. Das funktioniert nur so sicher, solange danach nichts mehr auf diesen freigegebenen Speicher verweist.
Jede Anfrage läuft dabei in drei Phasen ab, die du dir jetzt merken solltest. Beim Startup liest PHP die Daten der Anfrage ein, zum Beispiel ein Formular oder ein Datei-Upload. Danach läuft im Grunde dein Skript. Am Ende kommt der Shutdown, in dem aufgeräumt wird. Beide Lücken entstehen beim Übergang zwischen diesen Phasen.
PHP begrenzt nämlich standardmäßig den Speicher pro Anfrage, standardmäßig auf 128 Megabyte. Wenn dieses Limit überschritten wurde, hat PHP bisher nicht sauber einen Fehler zurückgegeben, sondern stattdessen einen sogenannten Bailout ausgelöst, also einen Sprungbefehl in C, der die gerade laufende Funktion sofort verlässt und direkt zur Fehlerbehandlung springt. Das Problem dabei ist, dass die Funktion ihre Arbeit nicht mehr zu Ende bringt. Sie hat vielleicht schon eingetragen, dass es eine neue Datenstruktur gibt, diese Struktur aber noch nicht vollständig befüllt. Später verlässt sich PHP darauf, dass alles, was eingetragen ist, auch gültig ist. Es bleibt also ein unvollständiger Zustand im Speicher zurück, mit dem PHP danach weiterarbeitet.
Die Entdecker von Calif oder Wiz, beziehungsweise es ist irgendwie nicht so ganz klar, wer die Lücke jetzt zuerst entdeckt hat, aber Calif zumindest beschreibt die erste Lücke an einer konkreten Stelle. Wenn PHP einen Eintrag in ein internes Array einfügt, erhöht es zuerst den Zähler der Einträge und reserviert erst danach Speicher für den Namen des Eintrags. Reißt genau diese Reservierung das Speicherlimit, bricht PHP ab. Der Zähler sagt jetzt, dass es einen Eintrag mehr gibt, aber dieser Eintrag wurde nie befüllt. Beim Aufräumen geht PHP alle gezählten Einträge durch und verarbeitet auch den unbefüllten Eintrag, in dem noch alte Daten liegen. Wer diese Daten kontrolliert, kontrolliert, was PHP damit tut. Damit das funktioniert, muss der Angreifer das Speicherlimit genau an dieser Stelle überschreiten, obwohl Uploads standardmäßig auf 8 Megabyte begrenzt sind. Laut dem offiziellen Advisory gibt es dafür mehrere Wege.
Ein Beispiel sind Dateifelder mit leeren Dateinamen. Sie zählen nicht als Upload, aber PHP legt für jedes davon trotzdem mehrere Verwaltungseinträge an. Mit verschachtelten Feldnamen wächst dieser Aufwand stark. Laut Calif reicht dadurch eine Anfrage unter 8 Megabyte, um mehr als 128 Megabyte Speicher zu belegen. Der Angreifer kann so also steuern, an welcher Stelle PHP der Speicher ausgeht.
Am stärksten betroffen ist mod_php, weil das alles passiert, während PHP die Anfrage einliest. mod_php räumt danach trotzdem auf und verarbeitet diese kaputten Daten. PHP-FPM beendet in dieser Situation den ganzen Prozess, wodurch die kaputten Daten verschwinden. Laut Advisory wurde vollständige Code-Ausführung gegen mod_php mit Standardeinstellungen gezeigt, gegen FPM bei dieser Lücke dagegen nicht.
Die zweite Lücke braucht zwei Anfragen an denselben PHP-Prozess. PHP hat globale Variablen, die zwischen Anfragen erhalten bleiben, aber während einer Anfrage auf deren Speicher zeigen. Diese Verweise müssen am Ende jeder Anfrage zurückgesetzt werden. Bricht ein Fehler die Anfrage vorher ab, bleibt der Verweis bestehen und zeigt auf Speicher, der bereits freigegeben ist. Greift die nächste Anfrage darauf zu, nennt man das Use-after-free, also die Benutzung von Speicher nach seiner Freigabe. Wenn der Angreifer vorher eigene Daten an genau diese Stelle gebracht hat, verarbeitet PHP diese Daten, als wären es seine eigenen internen Strukturen. Der wichtigste Einstiegspunkt dafür ist Session Upload Progress. Das ist eine kaum bekannte Funktion, mit der man Fortschrittsbalken für Uploads bauen kann. Sie ist standardmäßig eingeschaltet und speichert schon Daten in der Session, während PHP die Anfrage noch einliest, also bevor deine Anwendung überhaupt startet.
Der Angriff gegen mod_php läuft laut Calif so ab: In der ersten Anfrage startet ein Upload. Session Upload Progress legt Daten an und dann überschreitet der Angreifer das Speicherlimit. PHP gibt den Speicher frei, setzt dabei die Session-Verweise nicht zurück. Eine zweite Anfrage an denselben Prozess erreicht den Upload Progress Code und arbeitet mit diesen veralteten Verweisen weiter. Die Forscher von Wiz haben daraus zusätzlich ein Datenleck gebaut. PHP schickt dabei Inhalte aus dem freigegebenen Speicher als Session-Cookie an den Angreifer zurück. Darin können Passwörter oder API-Schlüssel aus fremden Anfragen stehen. Außerdem verrät das Leck, wo im Speicher welche Daten liegen, und genau diese Information braucht der Angreifer, um den Use-after-free zur Code-Ausführung zu machen.
Auch gegen PHP-FPM wurde diese Lücke ausgenutzt. Dort braucht der Angreifer laut den Forschern allerdings eine passende Stelle in der Anwendung, an der PHP zum Beispiel gespeicherte Session-Daten lädt. In geleakten Posts stand vorher oft CVSS 10. Das PHP-Team vergibt aber 9,2, weil der Angriff komplex ist und laut Advisory von PHP-Bild dem Webserver und dem Zustand des Speichers abhängt. Ein Angreifer braucht also unter Umständen viele Versuche. Trotzdem braucht er weder Login noch Mithilfe eines Nutzers und das reicht für Massenangriffe.
Bemerkenswert ist vor allem, wie alt das Grundproblem ist. Laut Calif fand Stefan Esser schon 2004 eine ähnliche Lücke über das Speicherlimit. 2020 wurde ein verwandter Fehler gemeldet und als harmlos eingestuft. 2024 fand ein Sicherheits-Audit das Problem erneut, konnte aber nicht beweisen, dass es ausnutzbar ist. 2026 haben Calif, Wiz und OpenAI mit Hilfe von KI-Modellen genau diesen Beweis geführt. Der Calif-Forscher betont, dass er die alten PHP-Lücken kannte und das Modell gezielt danach suchen ließ. Die KI hat den Fehler also nicht gefunden, sondern die aufwendige Arbeit beschleunigt und ihn ausnutzbar gemacht. Eigentlich sollte alles am 22. Oktober veröffentlicht werden. Weil aber am 20. Oktober Details, ein Screenshot des Exploit-Tools und ein kurzes Video liegten, hat PHP den Patch einen Tag früher veröffentlicht. Den vollständigen Exploit der Entdecker gibt es nicht öffentlich.
Wiz hat damit nach eigener Aussage Code-Ausführung ohne Login gegen Standardinstallation von diesen Systemen gezeigt. Wichtig: Bei solchen großen Lücken tauchen immer gefälschte Exploits auf, die den Rechner desjenigen infizieren, der sie startet. Solchen Code solltest du nur lesen oder in einer isolierten virtuellen Maschine ausführen. Ob die Lücken schon aktiv ausgenutzt werden, ist umstritten. Cloudflare hat Angriffsversuche beobachtet und Watchtower meldet Angriffe auf seine Fallenserver. Andere Stellen hatten bis zu ihrer Veröffentlichung keine bestätigten Fälle und die CISA führt auch noch keine Angriffe. Es gibt also Angriffsversuche, aber noch kein bestätigtes Bild einer Massenausnutzung. Aber was solltest du jetzt tun?
Die einzige vollständige Lösung ist ein Update auf eine dieser Versionen hier oder auf ein Paket deiner Linux-Distribution, das den Fix enthält. Danach musst du PHP-FPM neu starten, weil die laufenden Prozesse sonst weiter die alte Version ausführen. Wenn du nicht sofort patchen kannst, empfiehlt das Advisory gegen die erste Lücke das Speicherlimit pro Anfrage abzuschalten, also memory_limit gleich minus eins. Das klingt unlogisch, nimmt dem Angreifer aber genau den vorhersehbaren Abbruch, den er braucht. Den Speicherbegrenzer du dann über das Betriebssystem. Gegen die zweite Lücke hilft es, Session Upload Progress abzuschalten und danach alle PHP-Prozesse neu zu starten. Beides sind laut Advisory nur Teilmaßnahmen und kein Ersatz für das Update.
Der Patch selbst entfernt den Bailout bei Speichermangel komplett. Wird das Limit überschritten, darf die laufende Funktion ihre Arbeit sauber beenden und PHP bricht erst danach ab. Bei einem zweiten höheren Limit wird der Prozess sofort beendet ohne irgendetwas aufzuräumen. Dadurch kann kein unvollständiger Zustand mehr zurückbleiben. PHP-to-shell ist also kein Fehler in einer Anwendung, sondern ein Designfehler darin, wie PHP mit Speichermangel umgeht, und er galt 20 Jahre lang als zu kompliziert, um ihn auszunutzen. Für dich heißt das konkret, dass du deine PHP-Version prüfst und aktualisierst, auch wenn dein eigener Code sauber ist. Und für die Branche zeigt der Fall, dass ein bekannter Fehler nicht mehr als harmlos gelten kann, nur weil er schwerer auszunutzen ist. Und damit, stay safe und bis zum nächsten Mal.