21. Oktober, 14:00 UTC. Diesen Termin hat das PHP-Security-Team für sein außerplanmäßiges Notfall-Release gewählt, einen Tag nachdem Details zu CVE-2026-109618 und CVE-2026-109619 vor der koordinierten Veröffentlichung durchgesickert waren. Beide haben einen CVSS-v4.0-Score von 9.2, und die Threat-Feeds haben das Duo längst „php2shell“ getauft. watchTowr hat die erste Lücke im Labor nachgestellt. Zum Zeitpunkt des Leaks hatte niemand eine großflächige Ausnutzung in freier Wildbahn bestätigt. Fixes gab es für 8.2, 8.3, 8.4 und 8.5. Wenn dein Server auf 7.4, 8.0 oder 8.1 läuft, kommt von upstream niemand, um dir zu helfen.

Die meisten Triage-Anleitungen, die ich diese Woche gelesen habe, auch der Medium-Artikel, der mich überhaupt zum Schreiben gebracht hat, nehmen die EOL-Gruppe ernst und liefern ihr einen sauberen Härtungsplan: allow_url_fopen abschalten, open_basedir setzen, eine lange Liste in disable_functions eintragen, .php im Upload-Ordner per Nginx blockieren und den Origin hinter die CIDR-Bereiche der WAF sperren. Das alles hätte ich gern auf jeder Kiste. Mein Problem ist die Beruhigung, die gleich mitgeliefert wird, also die Vorstellung, disable_functions würde eine Shell stoppen, bevor sie den Kernel erreicht. Wir reden hier über eine Lücke in der Request-Verarbeitung der Runtime selbst. Sie ist ohne Authentifizierung ausnutzbar und schlägt zu, bevor dein Router, deine Auth-Middleware oder deine ACLs überhaupt geladen sind. Eine php.ini-Direktive wird von genau dem C-Code durchgesetzt, den der Angreifer gerade kaputt macht.

Das ist keine theoretische Sorge. disable_functions hat eine lange und ziemlich peinliche Geschichte von Bypasses, und die stammen von Angreifern, die nur Userland-PHP zur Verfügung hatten. Sobald jemand Speicher im Interpreter korrumpieren kann, ist er an der Schicht vorbei, die prüft, ob ein Funktionsname erlaubt ist. Die Funktionsliste lässt die faulen Payloads scheitern, die irgendwo von einem Pastebin kopiert wurden und einfach system() aufrufen. Gegen jemanden, der den Diff ordentlich liest, hilft sie kaum. Laut den Zahlen der Anleitung selbst bauen Scanner aus Upstream-Diffs innerhalb von zwei bis sechs Stunden nach einem Commit funktionierende Probes. Das ist lange bevor das Change-Approval-Meeting für deinen 7.4-Cluster überhaupt im Kalender steht.

Hier das beste Gegenargument, und ich will es ordentlich vortragen. Viele Betriebe können nicht von jetzt auf gleich upgraden. Manche betreiben ein Abrechnungssystem von 2019, das an elf Stellen each() benutzt. Manche haben ein mit ionCube verschlüsseltes Vendor-Modul, das nur unter 7.4 lädt. Manche hängen an einem Hosting-Vertrag fest, der ihnen genau die Version gibt, die das Control Panel eben mitbringt. Für sie ist mehrschichtiges Härten plus Überwachung ausgehender Sockets von www-data heute Nacht ehrlich das Beste, was sie tun können, und das sinnlos zu nennen, wäre grausam. Da stimme ich voll zu. Heute Nacht ist es der richtige Schritt. Ich will nur nicht, dass daraus der Plan fürs nächste Quartal wird.

Nützlich an diesem Vorfall ist, dass er einer Entscheidung, die du längst getroffen hast, ein Preisschild verpasst. 8.1 über das Supportende hinaus zu betreiben, war immer eine Wette darauf, dass im Core nichts Kritisches auftaucht, bevor du migriert hast. Meistens geht die Wette auf, und niemand erinnert sich, dass sie überhaupt abgeschlossen wurde. Diesen Monat ging sie für viele Flotten nicht auf, und die Rechnung kam in Form eines Wochenendes: Web-Roots nach base64_decode und gzinflate durchgreppen, Crontabs lesen, prüfen, ob /dev/shm mit noexec gemountet ist. Schreib diese Stunden in die Migrationsschätzung, denn sie sind die Zinsen dafür, dass du auf einer alten Version bleibst.

Ein unspektakulärer Teil der Anleitung verdient mehr Aufmerksamkeit, als er bekommen wird: die Inventur. which -a php, ein Durchgang durch /opt/cpanel/ea-php* und /opt/plesk/php, und docker exec in jeden Container, weil der Host sie nicht auflistet. Ich wette einen Kaffee, dass die Hälfte der Teams, die diese Woche im Panikmodus waren, ein PHP-Binary gefunden hat, von dem sie nichts wussten. Mein Tipp: ein Queue-Worker auf einem anderen Build als der FPM-Pool, oder ein Sidecar-Image, das jemand 2022 auf php:8.0 gepinnt und dann vergessen hat. Die Go-Leute sagen gern, ein statisches Binary habe keine Runtime, die man patchen müsste. Stimmt ja auch, bis sie vierzig Services neu bauen müssen, weil die Toolchain eine CVE hatte. Jeder Abhängigkeitsgraph ist größer, als man denkt. Ein Core-Advisory macht unseren nur auf einen Schlag sichtbar.

Also, wenn der Patch draußen und die Checkliste abgehakt ist: Bring jede Runtime, die du betreibst, auf einen unterstützten Branch, und behandle das Härten der php.ini als zusätzlichen Sicherheitsgurt, nicht als Grund, das Upgrade auszulassen. Eine Minor-Version hinterherzuhinken sind Schulden, die du im Griff behalten kannst. Auf einem EOL-Branch zu sitzen heißt, deine Sicherheit darauf zu verwetten, dass im Core nichts Ernstes gefunden wird, und diese Woche ist die Wette verloren gegangen.

Was ich wirklich von Leuten hören will, die echte Flotten betreiben: Wie bekommt ihr EOL-Runtimes ins Budget, bevor ein Vorfall euch dazu zwingt? Gab es bei euch ein Argument, eine Kennzahl oder einen Monatsbericht, der das Management tatsächlich dazu gebracht hat, eine 7.4-Migration zu finanzieren? Oder brauchte es jedes Mal erst einen Schreck wie php2shell?