PHP2Shell: sprawdź i załataj luki RCE w PHP na serwerze
21 października 2026 roku projekt PHP wydał wersje 8.5.12, 8.4.27, 8.3.36 i 8.2.35, które łatają dwie luki w samym PHP, nazwane PHP2Shell. Obie pozwalają, by żądanie od kogoś niezalogowanego uruchomiło kod jako worker PHP. Błąd tkwi w środowisku uruchomieniowym, a nie w WordPressie, Drupalu czy Joomli, więc aktualizacja CMS-a lub jego wtyczek go nie usuwa. Ten poradnik pokazuje, kogo to dotyczy, jak sprawdzić serwer jednym poleceniem, co zrobić już dziś, jeśli nie możesz jeszcze zaktualizować, i jak bezpiecznie przeprowadzić aktualizację.
Czym są te dwie luki
- CVE-2026-109618, uszkodzenie pamięci przy jej braku - gdy alokacja pamięci się nie powiedzie, PHP może przerwać żądanie w chwili, gdy jego wewnętrzne dane są przygotowane tylko w połowie, a następujące potem sprzątanie ufa tym uszkodzonym danym. Spreparowane żądanie multipart może to wywołać nawet w granicach skonfigurowanych limitów rozmiaru.
- CVE-2026-109619, nieaktualny stan globalny - stan należący do jednego żądania może przeżyć pamięć, na której się opiera. Kolejne żądanie obsługiwane przez ten sam worker może użyć tej zwolnionej pamięci, zanim zostanie zresetowana (use-after-free). Potwierdzona ścieżka prowadzi przez funkcję session upload progress i błędy krytyczne.
Obie mają ocenę 9.2 (krytyczna) w CVSS 4.0. Według ogłoszenia PHP podczas badań zbudowano działający exploit, a ryzyko jest największe dla Apache z mod_php, gdzie atak wykonuje się przed jakimkolwiek kodem aplikacji. W ciągu kilku dni pojawiło się kilka publicznych exploitów proof-of-concept; Rapid7 podaje, że każdy działa tylko dla jednej kombinacji systemu, wersji PHP i serwera WWW, i odnotował próby wykorzystania. Traktuj to jako pilną łatkę.
Kogo to dotyczy
Każdej instalacji PHP, która obsługuje żądania WWW: PHP-FPM, Apache z mod_php, php-cgi, FrankenPHP i LiteSpeed. To niemal każdy serwer z WordPressem, WooCommerce, Drupalem, Joomlą, Magento, Laravelem i Nextcloudem.
| Gałąź PHP | Podatne | Pierwsza poprawiona wersja |
|---|---|---|
| 8.5 | 8.5.0 - 8.5.11 | 8.5.12 |
| 8.4 | 8.4.0 - 8.4.26 | 8.4.27 |
| 8.3 | 8.3.0 - 8.3.35 | 8.3.36 |
| 8.2 | 8.2.0 - 8.2.34 | 8.2.35 |
| 7.4, 8.0, 8.1 | wszystkie | brak wydania na php.net; backporty w kodzie źródłowym, pakiety dystrybucji lub dostawcy LTS |
| 7.3 i starsze | wszystkie | brak poprawki |
Dystrybucje często zostawiają stary numer wersji i przenoszą poprawkę wstecz (na przykład pakiet Debiana lub Ubuntu, który nadal pokazuje 8.2.x), więc przy PHP z pakietów sprawdzaj pakiet w security trackerze swojej dystrybucji, a nie tylko numer.
Sprawdź serwer jednym poleceniem
Zapisz to jako php2shell-check.php i uruchom tym samym PHP, który obsługuje twoją stronę. Skrypt wypisuje wersję, informację, czy jest starsza od poprawki, oraz dwa ustawienia, które zmieniają opisane niżej doraźne środki.
<?php
// PHP2Shell check: is this PHP build older than the October 21, 2026 fixes?
$fixed = ['8.5' => '8.5.12', '8.4' => '8.4.27', '8.3' => '8.3.36', '8.2' => '8.2.35'];
$branch = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;
echo "PHP " . PHP_VERSION . " (" . PHP_SAPI . ")\n";
if (!isset($fixed[$branch])) {
echo "Branch $branch gets no php.net release: check your distro or LTS vendor, or upgrade to 8.4.\n";
} elseif (version_compare(PHP_VERSION, $fixed[$branch], '<')) {
echo "VULNERABLE: upgrade to {$fixed[$branch]} or later (or a distro build with the backport).\n";
} else {
echo "Patched upstream version ({$fixed[$branch]}+).\n";
}
echo "session.upload_progress.enabled = " . (ini_get('session.upload_progress.enabled') ? 'On' : 'Off') . "\n";
echo "post_max_size = " . ini_get('post_max_size') . ", memory_limit = " . ini_get('memory_limit') . "\n";
php php2shell-check.php
Wynik sprawdzony 2026-10-24 w oficjalnych obrazach Docker php:
PHP 8.3.30 (cli)
VULNERABLE: upgrade to 8.3.36 or later (or a distro build with the backport).
session.upload_progress.enabled = On
post_max_size = 8M, memory_limit = 128M
PHP 8.4.27 (cli)
Patched upstream version (8.4.27+).
PHP 7.2.34 (cli)
Branch 7.2 gets no php.net release: check your distro or LTS vendor, or upgrade to 8.4.
php z wiersza poleceń może być innym buildem niż ten, który stoi za stroną. Aby sprawdzić stronę WWW, uruchom php-fpm -v (lub php-fpm8.3 -v w Debianie i Ubuntu) albo umieść skrypt w katalogu głównym serwisu na jedno żądanie i od razu go usuń.
Jeśli nie możesz dziś zaktualizować: środki doraźne
Zespół PHP mówi jasno, że pełnego obejścia nie ma, a aktualizacja to jedyny bezpieczny wybór. Te ustawienia zawężają pole ataku na czas, gdy planujesz aktualizację. Ustaw je tam, gdzie aplikacja nie może ich nadpisać - w php.ini lub w puli FPM przez php_admin_value - bo ini_set() i .user.ini działają za późno. Potem zrestartuj wszystkie workery.
; FPM pool, e.g. /etc/php/8.3/fpm/pool.d/zz-php2shell.conf (the [www] section of your pool)
[www]
php_admin_value[session.upload_progress.enabled] = 0
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 30M
php-fpm8.3 -t && systemctl restart php8.3-fpm
Sprawdziliśmy ten plik puli poleceniem php-fpm -t na PHP 8.4 (configuration test successful). Co robi każda linia:
session.upload_progress.enabled = 0blokuje potwierdzoną ścieżkę CVE-2026-109619, ale nie każdy wariant. Wyłącz to, chyba że zależy od tego pasek postępu wysyłania plików.post_max_size8M bez uploadów albo 32M, jeśli strona przyjmuje pliki, zupload_max_filesizeponiżej tej wartości, jak zaleca zespół PHP. Ogranicz też rozmiar żądania w nginx (client_max_body_size 32m;) lub Apache (LimitRequestBody).- Tylko w PHP 8.5 dodaj
fatal_error_backtraces = 0. - PHP sugeruje też
memory_limit = -1ustawione przez administratora, aby samego limitu pamięci nie dało się użyć do wywołania CVE-2026-109618. Rób to tylko z limitem pamięci kontenera lub cgroup wokół PHP, inaczej jedno złośliwe żądanie może zająć cały RAM serwera. Nie używaj do tegoRLIMIT_ASaniRLIMIT_DATA: mogą one wywołać lukę.
Ukrywanie błędów (display_errors, error_reporting, @) nie pomaga, a pusty log błędów nie dowodzi, że serwer nie został zaatakowany.
Jak zaktualizować
- PHP z pakietów (Debian, Ubuntu, RHEL, AlmaLinux). Zainstaluj aktualizację bezpieczeństwa (
apt update && apt upgradelubdnf upgrade 'php*'), a potem zrestartuj PHP-FPM lub Apache, bo działające workery trzymają stary kod. Upewnij się, że changelog pakietu wymienia CVE-2026-109618. - Obrazy Docker. Przebuduj na poprawionym tagu (
php:8.4-fpmwskazuje teraz na 8.4.27) poleceniemdocker compose build --pull, a potem odtwórz kontenery. Działający kontener zachowuje stare PHP, dopóki nie zostanie zastąpiony. - PHP 7.4 - 8.1. Użyj pakietu z backportem od swojego dostawcy albo przejdź na 8.4. PHP 7.3 i starsze nigdy nie dostaną poprawki: schowaj stronę za listą dozwolonych adresów lub VPN, dopóki nie zostanie zmigrowana.
- Po aktualizacji uruchom ponownie skrypt sprawdzający i przejrzyj log serwera WWW pod kątem nietypowych żądań POST multipart i awarii workerów PHP od 21 października.
Jeśli potrzebujesz pomocy, zarządzana administracja serwerami obejmuje takie łatanie, a nasz poradnik o serwerze cloud dla WordPressa pokazuje konfigurację PHP-FPM, która trzyma te ustawienia w puli. Przed aktualizacją strony produkcyjnej zrób snapshot: kopia zapasowa i przywracanie VM wyjaśnia, jak to zrobić.
Co zrobiliśmy
W tym samym tygodniu sprawdziliśmy każdą usługę DCXV działającą na PHP i wdrożyliśmy działania z tego poradnika. Serwerami klientów zarządzają ich właściciele: jeśli używasz PHP na serwerze cloud lub dedykowanym w DCXV, wykonaj powyższe sprawdzenie jeszcze dziś. Nowy serwer cloud dostaje aktualne pakiety przy pierwszym apt upgrade.
Źródła (sprawdzone 2026-10-24): ogłoszenie wydań bezpieczeństwa PHP 8.x z 21 października 2026 roku, biuletyny PHP GHSA-w8hw-w9fx-j79w i GHSA-6wmf-4rv5-p3rp oraz analiza Rapid7.
