GenBox Free Tools (genbox.eu)
PHP2Shell. Krytyczna dziura w każdej wersji PHP
21 października 2026 roku o 14:00 UTC zespół PHP wydał awaryjne poprawki do dwóch podatności, które pozwalają na zdalne wykonanie kodu bez logowania. Obie dostały CVSS v4.0 9.2. Obie siedzą w jądrze języka, a nie w aplikacji, więc nie da się ich załatać w WordPressie, Magento czy Laravelu, trzeba wymienić samo PHP. Exploity i opisy techniczne są już publiczne.
Co dokładnie pękło
CVE-2026-109618 to błąd use-after-free w obsłudze końca żądania. Kiedy PHP przerwie pracę z powodu braku pamięci, część wewnętrznych struktur zostaje w stanie połowicznej inicjalizacji. Mechanizm sprzątający po żądaniu traktuje potem te śmieci jak poprawne dane i potrafi wywołać kod wskazany przez atakującego. CVE-2026-109619 to drugi use-after-free, tym razem na stanie globalnym żądania. Stan zostaje po zwolnieniu pamięci i kolejne żądanie obsłużone przez ten sam proces roboczy korzysta z niego, zanim normalna inicjalizacja go wyczyści.
W obu przypadkach mówimy o kodzie, który powstał przy okazji mechanizmu session.uploadprogress, dodanego w PHP 5.4.0 w 2012 roku. Dlatego zakres obejmuje PHP 5.4 do 8.5. Domyślna konfiguracja jest podatna, bo session.uploadprogress.enabled ma wartość 1 od lat.

Osobna sprawa to wyciek pamięci. Handler postępu uploadu potrafi odesłać klientowi zwolniony fragment pamięci procesu roboczego, między innymi w ciasteczku sesji. W tej pamięci mogą leżeć hasła, tokeny sesji, klucze API, a nawet klucze prywatne TLS z innych żądań. Mechanizm działa przed kodem aplikacji, więc wyciek nie wymaga nawet wywołania session_start(). Sansec porównuje to do Heartbleeda.
Kto jest narażony
Wszystko, co obsługuje żądania HTTP przez PHP: PHP-FPM, Apache z modphp, php-cgi, FrankenPHP i LiteSpeed. PHP najwyższe ryzyko przypisuje modphp, bo tam atak odpala się przed wykonaniem jakiegokolwiek kodu aplikacji. FPM jest również podatny, choć konkretna ścieżka z brakiem pamięci jest tam trudniejsza.
Badacze z Calif potwierdzili wykonanie kodu na Magento 2.4.9, WordPress 7.1.2, Drupal 11.4.3, Joomla 6.1.4, MediaWiki 1.46.2, Roundcube 1.7.4, phpMyAdmin 5.2.3, Nextcloud 35.0.1, Laravel 13.11, Symfony 8.1 i WHMCS. To nie lista teoretycznych celów, tylko środowiska, na których exploit zadziałał.
Poprawki
Aktualizacja to jedyne pełne rozwiązanie. Nowe wersje:
| Gałąź | Wersja |
|---|---|
| PHP 8.5 | 8.5.12 |
| PHP 8.4 | 8.4.27 |
| PHP 8.3 | 8.3.36 |
| PHP 8.2 | 8.2.35 |
Dystrybucje i dostawcy LTS dostali łatki wcześniej, więc warto sprawdzić ich pakiety, bo numer wersji może zostać stary przy nowym buildzie. PHP 8.1 i starsze są poza wsparciem, ale projekt opublikował minimalne backporty źródeł dla 7.4, 8.0 i 8.1. Osobna pułapka to repozytorium Remi, popularne na RHEL i pochodnych. 21 października nie miało jeszcze poprawek i tego dnia ich nie dostało. Trzeba przejść na pakiety dystrybucji albo budować PHP ze źródeł.
Po instalacji pakietu warto sprawdzić, czy działa nowy runtime. php -v w konsoli często pokazuje inną instalację niż ta, która obsługuje ruch z sieci. Trzeba zrestartować workery i upewnić się, że żaden proces nie został na starym buildzie.

Jeśli nie możesz załatać w ciągu godziny
Oficjalne obejścia są częściowe i PHP mówi to wprost. Nie czynią instalacji bezpieczną, kupują czas.
Pierwsze to session.uploadprogress.enabled=0, ustawione administracyjnie i wczytane przed parsowaniem żądania. W php.ini, w poolu FPM przez phpadminflag albo w konfiguracji serwera. Nie przez iniset() ani .user.ini, bo aplikacja może to nadpisać, a FPM czyta własną konfigurację. To blokuje potwierdzone ścieżki sesyjne, ale nie inne warianty. Po zmianie trzeba zrestartować wszystkie workery.
Drugie to memorylimit=-1, również administracyjnie przez phpadminvalue, z kontrolą, czy żaden pool, katalog ani aplikacja nie przywraca skończonego limitu. To usuwa wywoływany przez atakującego błąd braku pamięci, ale nie chroni przed prawdziwym wyczerpaniem alokacji. I ma skutek uboczny: pojedyncze żądanie może zjeść całą pamięć serwera. Dlatego PHP zaleca w tym samym czasie niski postmaxsize, 8M tam gdzie nie ma uploadów i 32M tam gdzie są, z uploadmaxfilesize poniżej, limity rozmiaru i liczby części żądania na poziomie proxy oraz limit cgroup lub kontenera jako granicę dostępności. Nie wolno używać RLIMITAS ani RLIMIT_DATA, bo one same mogą wywołać podatną ścieżkę.
Trzecie, opcjonalne, to pm.max_requests=1 w FPM. Jeden proces obsługuje jedno żądanie, więc stan po żądaniu nie przecieka do następnego. Koszt wydajnościowy jest ogromny, a ochrona nadal częściowa.
Czwarte, doraźne, to blokada multipart/form-data na poziomie serwera WWW, jeśli aplikacja nie przyjmuje uploadów. Wszystkie znane wektory to multipart POST. W nginx:
„`nginx if ($httpcontenttype ~* „multipart/form-data”) { return 403; } „`
W Apache:
„`apache RewriteEngine On RewriteCond %{HTTP:Content-Type} multipart/form-data [NC] RewriteRule ^ – [F] „`
To psuje uploady, więc po wdrożeniu trzeba przejść ścieżkę zamówienia czy dodania produktu. Regułę zdejmuje się po aktualizacji PHP.
Jeśli serwer nie jest krytyczny, najbardziej sensowną opcją jest zatrzymanie PHP-FPM i wystawienie statycznej strony. Tryb konserwacji WordPressa czy Magento nic nie daje, bo PHP parsuje żądanie zanim aplikacja sprawdzi flagę. Holenderskie Tweakers, Tweede Kamer, NCSC i Security.NL wyłączyły się profilaktycznie 21 października.
Czego nie robić
Nie liczyć na WAF i reguły w aplikacji. Ścieżka ataku biegnie w interpreterze, przed kodem serwisu i przed większością pluginów bezpieczeństwa. Nie traktować samych ustawień ini jako rozwiązania. Gina Peter Banyard z PHP ostrzegała, że wyłączenie session.uploadprogress bez reszty nie wystarcza. Nie zostawiać memorylimit=-1 na stałe, bo to zaproszenie do wyczerpania pamięci.
Jak sprawdzić, czy ktoś próbował
Szukać w logach POST-ów z multipart i polem PHPSESSIONUPLOAD_PROGRESS, pamiętając że parser PHP jest tolerancyjny i łapie też poskładane nagłówki, brak dwukropka czy Content-Disposition bez form-data. Seria odpowiedzi 5xx z procesów PHP to sygnał próby exploita, bo zły offset lub przegrany wyścig na stercie kończy się segfaultem workera. Odpowiedź 200 przy tym samym wzorcu to przypadek udany i wtedy trzeba założyć kompromitację: rotacja haseł, tokenów, kluczy API i kluczy TLS.
Kalendarium
1 sierpnia Ryan Austin z Calif znajduje ścieżki RCE. 11 sierpnia zgłasza pierwszy błąd do PHP. 24 sierpnia robi to Wiz Research. 20 października szczegóły wyciekają i watchTowr potwierdza RCE. 21 października o 07:43 UTC Cloudflare raportuje pierwsze ataki, na sześć godzin przed wydaniem poprawek. O 14:00 PHP publikuje 8.5.12, 8.4.27, 8.3.36 i 8.2.35.
Błędy niezależnie znaleźli Calif, Wiz Research i OpenAI. Jeśli masz własny serwer, aktualizujesz PHP. Jeśli nie masz, piszesz do hostingodawcy jeszcze dziś.
Piotr Kurowski: badacz i inżynier sztucznej inteligencji, zajmuje się uczeniem maszynowym i sieciami neuronowymi. Prowadzi badania w OpenAI, wcześniej w polskim startupie AI i Google AI. Analityczny umysł, introwertyk typu INTJ. Objaśnia złożoność modeli AI w sposób zrozumiały dla każdego.