PHP2Shell (CVE-2026-109618, CVE-2026-109619): analiza krytycznej podatności RCE w PHP i co zrobić teraz

Dawid Bakaj
Utworzone przez Dawid Bakaj • czwartek, 22.10.2026, 11:18 • Bezpieczeństwo aplikacji webowych


PHP2Shell - krytyczne podatności CVE-2026-109618 i CVE-2026-109619 umożliwiające zdalne wykonanie kodu w silniku PHP

PHP2Shell to zbiorcza nazwa dwóch krytycznych podatności w samym silniku PHP – CVE-2026-109618 i CVE-2026-109619 – które pozwalają nieuwierzytelnionemu atakującemu wykonać dowolne polecenia systemowe na serwerze przez pojedyncze żądanie HTTP. Oba błędy mają ocenę CVSS v4.0 9.2 i dotyczą każdej wersji PHP od 5.4 w górę. Poprawki wyszły 21 października 2026 roku w wersjach 8.5.12, 8.4.27, 8.3.36 i 8.2.35, a aktualizacja jest jedynym pełnym zabezpieczeniem.

To nie jest kolejna podatność w pluginie do WordPressa. Luka siedzi w warstwie, która parsuje żądanie HTTP zanim uruchomi się pierwsza linia kodu aplikacji. Oznacza to jedną, niewygodną konsekwencję: perfekcyjnie utrzymywana aplikacja jest narażona dokładnie w tym samym stopniu co zaniedbana. PHP napędza około 70 procent stron w internecie, dlatego 21 października rządy Finlandii, Francji i Holandii wyłączały swoje serwisy, a Wikimedia, Internet Archive i 4chan zdejmowały usługi offline.

Zanim przejdziemy do tego, co robić, warto zrozumieć, dlaczego ta luka jest inna niż wszystko, co znasz z biuletynów o wtyczkach. Jej mechanika zaczyna się od jednej funkcji języka C, która siedzi w PHP od dwudziestu lat.

TL;DR – kluczowe fakty o PHP2Shell

  • Co to jest: dwie podatności memory safety w rdzeniu PHP – CVE-2026-109618 (RCE przez uszkodzenie pamięci po błędzie OOM) i CVE-2026-109619 (RCE przez przeterminowany stan globalny).
  • Ocena: CVSS v4.0 9.2 (krytyczna) według zespołu PHP, klasa CWE-824: Access of Uninitialized Pointer. Firma watchTowr oceniła je na pełne 10.0.
  • Kto jest podatny: wszystkie wersje PHP od 5.4 do 8.5 przed łatką, w konfiguracji domyślnej. Najwyższe ryzyko: Apache z mod_php. Podatne są też PHP-FPM, php-cgi, FrankenPHP i LiteSpeed.
  • Co może zrobić atakujący: uruchomić dowolne polecenie z uprawnieniami użytkownika serwera WWW (www-data, apache, nginx) bez logowania, bez sesji i bez błędu w kodzie aplikacji. Druga ścieżka pozwala czytać pamięć procesu PHP – hasła, tokeny, klucze API i certyfikaty z innych żądań.
  • Łatka: PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 z 21 października 2026. Dla 7.4, 8.0 i 8.1 opublikowano jedynie minimalne backporty źródłowe. PHP 5 nie dostał poprawki.
  • Czy jest wykorzystywana: tak. Amazon Threat Intelligence zarejestrował próbę eksploatacji już 17 października, cztery dni przed ujawnieniem. Cloudflare, watchTowr i Hadrian potwierdzają ataki na szeroką skalę.
  • Atak jest cichy: proces roboczy nie pada, serwer zwraca HTTP 200, a logi aplikacji nie zapisują niczego nietypowego.

Czym dokładnie jest PHP2Shell?

Nazwa nie pochodzi od badaczy. Tak nazywało się narzędzie exploitacyjne, które wyciekło do sieci 20 października 2026 roku, dzień przed planowaną publikacją poprawek. Autorstwo przypisuje się firmie Calif, a jej exploit łączył oba błędy w jeden atak niewymagający logowania. Stąd skrót, który przylgnął do całej sprawy: „z PHP do shella”.

Technicznie mamy do czynienia z rodziną błędów bezpieczeństwa pamięci o jednej wspólnej przyczynie. Kiedy PHP napotyka warunek krytyczny – wyczerpanie memory_limit, przekroczenie max_execution_time albo utratę połączenia z klientem – nie zwraca błędu w górę stosu wywołań. Zgłasza błąd krytyczny i używa funkcji longjmp(), aby porzucić aktualny kontekst wykonania.

I tu zaczyna się problem. Funkcja w C przerwana w połowie budowania struktury danych zostaje po prostu porzucona. Nie uruchamiają się destruktory, nie cofa się żadna operacja, nigdzie nie zapisuje się informacja, że struktura jest niekompletna. Chwilę później PHP wchodzi w rutynowe sprzątanie po żądaniu, które z góry zakłada, że wszystko jest w porządku. Nie jest.

Oba CVE opisują miejsca, w których to założenie się załamuje. I w obu przypadkach atakujący kontroluje zarówno moment wywołania błędu, jak i dane, które PHP później źle zinterpretuje.

CVENazwa oficjalnaMechanizmPotwierdzony wpływ
CVE-2026-109618RCE via OOM corruptionBłąd braku pamięci przerywa żądanie, gdy wewnętrzne dane są zainicjalizowane tylko częściowo. Procedura porządkowania tego samego żądania traktuje je jako prawidłowe.Pre-auth RCE na WordPress, Drupal, Joomla. Zdalne odczytanie pamięci procesu PHP, niezależne od aplikacji.
CVE-2026-109619RCE via stale global stateStan globalny należący do żądania przetrwa zwolnienie pamięci, na którą wskazuje. Kolejne żądanie obsłużone przez ten sam proces roboczy korzysta z niego przed normalną inicjalizacją.Pre-auth RCE na Drupal (backtrace błędu krytycznego) i WordPress (type confusion w OPcache).
Źródło: oficjalne advisory GHSA-w8hw-w9fx-j79w i GHSA-6wmf-4rv5-p3rp projektu PHP oraz analizy Wiz Research i Calif.

Chronologia: od 2004 roku do wycieku exploita

W tej historii najbardziej uderza nie technika, lecz kalendarz. Sama klasa błędów nie jest nowa. Nowa jest dopiero umiejętność jej wykorzystania.

DataWydarzenie
2004Stefan Esser publikuje pierwszą zdalną podatność PHP opartą o memory_limit. Uznaje ją za tak groźną, że nie udostępnia exploita publicznie.
2020Zgłoszenie bug #78876: długie zmienne w multipart/form-data powodują OOM i brak usunięcia plików tymczasowych. Potraktowane jako błąd niegroźny.
2024Audyt PHP wykonany przez OSTIF i Quarkslab odnajduje pokrewny problem OOM. Eksploatacja nie zostaje udowodniona, więc błąd nie jest naprawiony.
30.07.2026OpenAI zaprasza firmę Calif do inicjatywy „Patch the Planet”. PHP zostaje wybrane jako cel o wysokim wpływie.
01.08.2026Calif (badacz Ryan Austin) znajduje pierwszy punkt przerwania i składa działający łańcuch RCE przeciwko WordPressowi.
11-15.08.2026Calif zgłasza pierwszy błąd do PHP, przekazuje PoC RCE, zespół PHP potwierdza jego działanie.
19-21.08.2026Wiz Research niezależnie odkrywa podatność. 20 sierpnia potwierdza pre-auth RCE na Drupalu, 21 sierpnia na WordPressie. Tego samego dnia Calif zgłasza drugi błąd.
24.08.2026Wiz raportuje podatności do zespołu bezpieczeństwa PHP.
21.09.2026PHP potwierdza zgłoszenia i rozpoczyna pracę nad skoordynowaną poprawką.
17.10.2026Amazon Threat Intelligence rejestruje w systemie MadPot próbę eksploatacji – cztery dni przed publicznym ujawnieniem.
20.10.2026Wyciek: wpis na Hacker News, post watchTowr na X, omyłkowo udostępnione wideo PoC od Calif. Chainguard jednostronnie łamie embargo, publikując załatane obrazy sześć godzin przed czasem, co pozwala atakującym przeanalizować różnice w kodzie. PHP przesuwa wydanie o dzień wcześniej.
21.10.2026, 13:34 UTCPublikacja advisory na GitHubie, 26 minut przed zapowiedzianą godziną. Wydanie PHP 8.5.12, 8.4.27, 8.3.36 i 8.2.35. CERT Polska publikuje komunikat 196/2026.

Z tej osi czasu płyną dwa niewygodne wnioski. PHP wiedziało o problemie już w 2024 roku. A ataki ruszyły, zanim ktokolwiek opublikował szczegóły. Dzień wydania łatki nie był więc początkiem zagrożenia. Był momentem, w którym stało się masowe.

Wektor ataku – analiza techniczna krok po kroku

Żeby zrozumieć, dlaczego PHP2Shell jest tak groźne, trzeba prześledzić łańcuch ataku. Składa się on z dwóch elementów: wywołania błędu krytycznego na żądanie oraz punktu przerwania, który zostawia proces w stanie nadającym się do wykorzystania.

Krok 1: wymuszenie błędu braku pamięci (OOM-fatal)

Aby cokolwiek przerwać, atakujący musi najpierw na żądanie doprowadzić do wyczerpania memory_limit. Problem w tym, że domyślny post_max_size (8 MB) normalnie nie pozwala dostarczyć tylu danych, by zapełnić domyślny 128-megabajtowy stos PHP. Badacze Calif znaleźli dwa obejścia.

Pierwsze: PHP porównuje post_max_size z zadeklarowanym Content-Length przed rozpoczęciem parsowania, ale nie egzekwuje tego limitu wobec bajtów, które faktycznie konsumuje. Żądanie chunked w HTTP/1.1 lub bezdługościowe w HTTP/2 omija więc barierę.

Drugie, sprytniejsze: część uploadu RFC1867 z filename="" nie zawiera danych pliku i nie jest liczona do max_file_uploads, ale PHP i tak tworzy dla niej sześć wpisów w $_FILES (name, full_path, type, tmp_name, error, size). Gdy nazwa pola jest zagnieżdżona – files[a][b][c]... – PHP buduje tę hierarchię osobno dla każdego z sześciu wpisów. Jeden krótki, pusty rekord uploadu rozrasta się w setki natywnych tablic haszujących, kubełków i alokacji kluczy. Setki takich rekordów przekraczają 128 MB sterty, choć całe ciało żądania mieści się poniżej 8 MB.

Krok 2: punkt przerwania pozostawiający nieprawidłowy stan

Mając kontrolę nad momentem wywołania OOM, badacze szukali kodu, który po przerwaniu zostawia konsumowalny stan. Pierwsze znalezisko to funkcja _zend_hash_str_add_or_update_i. PHP inkrementuje w niej licznik elementów tablicy przed pełną inicjalizacją nowego kubełka:

idx = ht->nNumUsed++;
ht->nNumOfElements++;

p = ht->arData + idx;
p->key = zend_string_init(str, len, persistent); /* tutaj może nastąpić zend_bailout() */

p->h = ZSTR_H(p->key) = h;
ZVAL_COPY_VALUE(&p->val, pData);

Zwiększenie nNumUsed sprawia, że kubełek staje się widoczny dla procedury porządkowania – nawet jeśli następna alokacja klucza spowoduje błąd krytyczny. Przepływ sterowania nigdy nie dociera do przypisania klucza i wartości, ale licznik pozostaje zwiększony. W efekcie procedura zend_array_destroy() konsumuje później przeterminowane bajty sterty jako żywy kubełek. To daje RCE na dowolnych skryptach PHP działających na Apache mod_php przy PHP >= 7.3.

Krok 3: Session upload progress – uniwersalny punkt wejścia

Najważniejszy element łańcucha to funkcja session upload progress. Pozwala ona otworzyć i aktualizować sesję, podczas gdy PHP nadal parsuje ciało żądania – zanim uruchomi się kod aplikacji. Parsowanie multipart może wejść do rozszerzenia sesji, zanim PHP uzna swoje moduły za aktywowane (flaga PG(modules_activated) jest wciąż fałszem).

Jeśli parsowanie zakończy się błędem krytycznym, pomijany jest callback MULTIPART_EVENT_END oraz RSHUTDOWN sesji – ale sterta żądania zostaje zwolniona. Proces roboczy Apache przeżywa z PS(id) i PS(http_session_vars) wciąż wskazującymi na zwolnioną pamięć. Kolejne żądanie – multipart z identyfikatorem sesji i polem PHP_SESSION_UPLOAD_PROGRESS, ale bez części plikowej – dociera do ścieżki czyszczenia, która ufa przeterminowanym wskaźnikom. To daje RCE na mod_php przy PHP >= 5.4.0.

Krok 4: dlaczego mod_php i PHP-FPM reagują inaczej

Kluczowa różnica to decyzja o losie procesu roboczego po błędzie startu żądania:

  • Apache mod_php uruchamia zarejestrowane czyszczenie żądania nawet po nieudanym starcie – php_request_shutdown(NULL) niszczy zniekształcone $_POST/$_FILES, a worker jest potem użyty ponownie. To tu stary stan zostaje skonsumowany.
  • PHP-FPM przy błędzie php_request_startup() wybiera gałąź wyjścia procesu (return FPM_EXIT_SOFTWARE). Worker kończy działanie i nie ma drugiego żądania w tym samym procesie, które mogłoby skonsumować stan.

Właśnie dlatego oficjalne advisory oznacza mod_php jako najwyższe ryzyko. Nie znaczy to jednak, że PHP-FPM jest bezpieczny. Calif znalazł osobną ścieżkę przez generyczny deserializer PHP (php_var_unserialize_init()): błąd krytyczny po udanym starcie żądania, podczas session_start(), session_decode() lub unserialize() (w tym przez wrapper maybe_unserialize() WordPressa), zostawia przeterminowaną księgowość deserializera. Kolejne żądanie multipart konsumuje ją – co daje RCE zależne od aplikacji na obu SAPI.

Kluczowe wnioski techniczne

  • Atak działa poniżej warstwy aplikacji. PHP parsuje dane żądania zanim zainicjalizują się rozszerzenia i zanim skompiluje się jakikolwiek kod aplikacji. Nawet „Hello World” jest podatny.
  • Atak jest cichy. Worker nie pada, serwer zwraca HTTP 200, a logi aplikacji nie zapisują niczego nietypowego. Polecenia wykonują się jako www-data, apache lub nginx.
  • Exploit jest przenośny. CrowdStrike potwierdził działanie na architekturach x86-64 i ARM, odporność na restarty workerów oraz pokonanie ASLR na hostach ARM wyłącznie za pomocą żądań HTTP.
  • Osobna ścieżka to wyciek pamięci. Bez osiągania RCE atakujący może odczytać region pamięci workera i zakodować jego zawartość w ciasteczku PHPSESSID – nawet gdy aplikacja nigdy nie wywołuje session_start(). Wiz porównał to do Heartbleed.

Rola AI – punkt zwrotny w wykrywaniu i eksploatacji podatności

PHP2Shell wyróżnia nie tylko skala, lecz także sposób odkrycia. Podatny kod leżał w repozytorium od ponad dekady. Zmieniło się co innego: realna możliwość jego wykorzystania. I tę zmianę napędziły modele AI.

Ryan Austin z Calif korzystał z modelu GPT-5.6 Sol podczas audytu kodu PHP. Zespół Wiz używał Gemini 4 Argon, GPT-5.6 Sol oraz własnego narzędzia Wiz Atlas. Budowa exploita wymagała połączenia wielu błędów i dostosowania się do układu pamięci każdego celu przez wielokrotne testowanie i debugowanie – pracy, która przed erą AI zajęłaby światowej klasy zespołowi miesiące. Wiz opisuje, że pojedynczy badacz wykonał ją w tydzień.

Nie przesadzajmy jednak z tą narracją. Austin sam zwraca uwagę, że nie użył żadnego tajnego oprzyrządowania ani modeli niedostępnych dla innych. Kluczowa była ludzka wiedza: skupienie się na celu o znanej historii podatności i postawienie właściwej hipotezy. Modele w domyślnym wariancie skłaniają się ku analizie najnowszego, najbardziej widocznego kodu. To badacz świadomie skierował je ku dwudziestoletnim prymitywom. „Znaj swój cel” działa nawet w epoce LLM.

Dla obrońców to miecz obosieczny. Ta sama technologia, która obniża koszt ataku, pozwala też wykrywać i łatać błędy, które przetrwały lata ludzkich przeglądów. Zmienia się za to ekonomia: luki uznawane wcześniej za „teoretycznie niewykorzystywalne” stają się realnymi celami. Dlatego warto, by regularne testy penetracyjne zakładały przeciwnika z takim samym oprzyrządowaniem, jakiego użyli badacze PHP2Shell.

Strukturalny problem PHP: luka znana od 2024 roku

Fundacja PHP w swoim oświadczeniu z 21 października przyznała się do czegoś rzadkiego w branży: strukturalnej porażki. Zewnętrzny audyt Quarkslab z 2024 roku odnalazł wczesne oznaki podatności OOM. Teoretyczny exploit był rozważany, ale nie powstał konkretny wektor ataku, więc problem przegrał z innymi o jaśniejszym wpływie.

Dlaczego nie naprawiono? Każda opcja oznaczała bolesny kompromis: złamanie wstecznej kompatybilności, nowy potencjał ataków DoS albo konieczność skoordynowania zmian w wielu rozszerzeniach firm trzecich. Zespół bezpieczeństwa działał przez konsensus i utknął między wadliwymi opcjami, a mała grupa deweloperów znających głęboko silnik była zajęta czym innym.

Dla kontekstu: Fundacja PHP – utrzymująca język napędzający 70 procent internetu – zatrudnia 13 osób na pełny i częściowy etat i opiera się na datkach. Komentatorzy „The Guardian” zestawili to z miliardami dolarów inwestowanymi w badania nad AI, które pomogły odkryć lukę. W odpowiedzi Fundacja powołała w maju 2026 Ecosystem Security Team, zatrudniła nowych deweloperów i zmieniła proces decyzyjny z wymagającego pełnego konsensusu na oparty o większość.

Kto jest zagrożony? Skala i realny wpływ

Łatwo niedoszacować zasięgu tej luki, bo PHP to nie tylko strony WWW. Podatne są również:

  • Systemów CMS i e-commerce: WordPress, Drupal, Joomla, MediaWiki, Magento, WooCommerce, Shopware, PrestaShop.
  • Aplikacji PHP: Laravel, Symfony, Nextcloud, Roundcube, phpMyAdmin, WHMCS.
  • Paneli hostingowych: cPanel i Plesk.
  • Urządzeń i appliance: sprzęt sieciowy i aplikacje dystrybuowane jako obrazy (np. Docker), które pakują własne PHP.

Calif potwierdził pre-auth RCE między innymi na: WordPress 7.1.2, Drupal 11.4.3, Joomla 6.1.4, MediaWiki 1.46.2, Roundcube 1.7.4, Magento 2.4.9, phpMyAdmin 5.2.3, Nextcloud 35.0.1, Laravel 13.11, Symfony 8.1 oraz WHMCS. Co najważniejsze – podatny kod jest w PHP, nie w tych aplikacjach. Lista to demonstracja, a nie wymóg.

Reakcja na świecie pokazała powagę sytuacji. Idąc za zaleceniami CERT-EU i brytyjskiego NCSC, wiele organizacji w Europie wyłączyło serwisy prewencyjnie: holenderski portal rządowy Overheid.nl, duńską krajową platformę komunikacji szkolnej, wszystkie publiczne usługi rządu Finlandii i wszystkie strony francuskiego Ministerstwa Spraw Wewnętrznych. Amerykańska NSA zaleciła wyłączenie stron, których nie da się natychmiast zaktualizować. W Japonii offline poszły między innymi platformy gier Umamusume, Granblue Fantasy i serwis hostingowy Sakura, a także BASE i Codmon.

Jak się zabezpieczyć? Runbook na pierwsze 24 godziny

Zespół PHP, CERT Polska i wszyscy dostawcy zabezpieczeń są zgodni w jednym: jedyną pełną ochroną jest aktualizacja. Łagodzenia opisane niżej redukują ekspozycję na konkretne ścieżki ataku, ale nie czynią instalacji bezpieczną. Poniższa kolejność działań odzwierciedla priorytety z oficjalnych rekomendacji.

Krok 1: ustal, co masz podatne

Sprawdź wersję i konfigurację PHP na każdym serwerze dostępnym z internetu:

php -i | grep -E "^(memory_limit|post_max_size|upload_max_filesize|Loaded Configuration File)"
php -v

Priorytetyzuj według ryzyka: najpierw Apache z mod_php dostępny z internetu, potem PHP-FPM, php-cgi, FrankenPHP i LiteSpeed. Pamiętaj o instancjach ukrytych w kontenerach, urządzeniach i panelach hostingowych.

Krok 2: aktualizuj do załatanej wersji

Gałąź PHPZałatana wersjaStatus
PHP 8.58.5.12Pełne wydanie
PHP 8.48.4.27Pełne wydanie
PHP 8.38.3.36Pełne wydanie
PHP 8.28.2.35Pełne wydanie
PHP 8.1 / 8.0 / 7.4tylko backport źródłowyEnd of life – brak oficjalnych binariów
PHP 7.3 i starsze, PHP 5brak poprawkiKonieczna migracja na wspieraną gałąź

W praktyce poprawki dostarcza dostawca. Dla większości systemów Linux będą to repozytoria dystrybucji, dla appliance i obrazów Dockera – producent. Jeśli korzystasz z hostingu współdzielonego, zmianę wersji PHP znajdziesz w panelu (DirectAdmin, cPanel) – ustaw najnowszą dostępną wersję z danej gałęzi i potwierdź u dostawcy, że zawiera ona łatkę z 21 października.

Krok 3: tymczasowe łagodzenia (jeśli nie możesz załatać od razu)

CERT Polska zaleca ustawienie w php.ini następujących wartości jako pierwszej linii obrony przed masowymi próbami:

  • memory_limit na -1, jeśli pozwalają na to zasoby (w przeciwnym wypadku 128M lub więcej),
  • post_max_size: 8M lub mniej,
  • max_input_vars: 1000 lub mniej,
  • session.upload_progress.enabled na Off,
  • na PHP 8.5 dodatkowo fatal_error_backtraces=0.

Ustawienia stosuj przez php.ini, pulę FPM lub konfigurację serwera – nie przez ini_set() ani .user.ini, bo muszą zadziałać zanim rozpocznie się parsowanie żądania. Po zmianach zrestartuj workery. Jeśli uploady multipart nie są potrzebne, zablokuj żądania multipart/form-data POST na poziomie proxy, zanim dotrą do PHP.

Ostrzeżenie: ustawienie memory_limit=-1 usuwa limit pamięci PHP i zwiększa ryzyko jej wyczerpania (DoS). Traktuj je jako awaryjne, z kontrolą zasobów na poziomie kontenera lub cgroup. Uwaga techniczna: ochrona typu RASP czy wbudowane agenty WAF mogą nie zadziałać, bo podatność wyzwala się podczas parsowania żądania, zanim takie narzędzia je zobaczą.

Wykrywanie i wskaźniki kompromitacji (IOC)

Tej części brakuje w większości polskich komunikatów, a jest kluczowa. Skoro atak nie zostawia śladu w logach aplikacji, obrona musi opierać się na wzorcach ruchu i zachowaniu procesów.

Sygnatura ruchu sieciowego

Najbardziej charakterystyczny wskaźnik eksploatacji to wartość PHPSESSID i pole PHP_SESSION_UPLOAD_PROGRESS przesłane razem w jednym uploadzie. Na to nakładają się objawy pośrednie:

  • nietypowe żądania multipart, po których następują błędy limitu pamięci lub powtarzające się odpowiedzi HTTP 500,
  • nadmiernie duże lub zniekształcone ciasteczka PHPSESSID w odpowiedziach serwera (objaw ścieżki wycieku pamięci),
  • niewyjaśniony churn – częste restarty procesów roboczych PHP.

Detekcja na poziomie procesów (threat hunting)

Ponieważ celem jest wykonanie poleceń, najskuteczniejsze są indicators of attack – procesy potomne zrodzone przez PHP lub serwer WWW. Szukaj sytuacji, w której php-fpm, apache2, httpd, nginx lub php-cgi uruchamiają powłokę lub narzędzia takie jak sh, bash, curl, wget, python, nc, ncat, socat czy powershell.exe. Przykładowe zapytanie KQL (Microsoft Defender):

DeviceProcessEvents
| where Timestamp > ago(30d)
| where InitiatingProcessFileName in~ ("php","php-cgi","php-fpm","apache2","httpd","nginx")
    or InitiatingProcessFileName startswith "php-fpm"
| where FileName in~ ("sh","bash","dash","zsh","curl","wget","python","python3","perl","nc","ncat","socat")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName,
    InitiatingProcessCommandLine, FileName, ProcessCommandLine, FolderPath, SHA1
| order by Timestamp desc

Technika mapuje się na MITRE ATT&CK T1505.003 (Web Shell). Zbuduj linię bazową normalnych procesów potomnych PHP w swoim środowisku – każde odchylenie od niej warto zweryfikować.

Czego szukać po włamaniu

  • web shelle, nieoczekiwane pliki i zmodyfikowane pliki PHP,
  • nowi użytkownicy administracyjni w CMS lub systemie,
  • nietypowe połączenia wychodzące (beaconing do C2),
  • w razie wykrycia śladów – zachowaj logi serwera WWW i PHP oraz odizoluj serwer.

Ponieważ ścieżka wycieku pamięci mogła ujawnić hasła, tokeny, klucze API i certyfikaty z innych żądań, po załataniu rozważ rotację sekretów na systemach PHP dostępnych z internetu. W Polsce wykrycie śladów eksploatacji warto zgłosić do CERT Polska przez formularz na incydent.cert.pl.

Obowiązki prawne po PHP2Shell – NIS2, RODO i KSC

PHP2Shell to nie tylko problem techniczny. Jeśli ścieżka wycieku pamięci ujawniła dane osobowe, albo atakujący uzyskał RCE na systemie przetwarzającym takie dane, uruchamiają się konkretne obowiązki prawne.

Z perspektywy RODO: nieautoryzowany dostęp do pamięci procesu zawierającej dane osobowe to naruszenie ochrony danych. Jeśli ryzyko dla praw i wolności osób jest realne, administrator ma 72 godziny na zgłoszenie naruszenia do Prezesa UODO. Problem z PHP2Shell polega na tym, że atak jest cichy – brak śladów w logach nie jest dowodem braku naruszenia, a jedynie konsekwencją charakteru podatności. Dlatego ocena musi opierać się na analizie ekspozycji i śladów opisanych wyżej.

Z perspektywy NIS2 i polskiej ustawy o krajowym systemie cyberbezpieczeństwa (KSC): podmioty kluczowe i ważne mają obowiązek zarządzania podatnościami i obsługi incydentów. Krytyczna, aktywnie wykorzystywana luka w komponencie tak powszechnym jak PHP jest modelowym przykładem zagrożenia, które wymaga udokumentowanej reakcji – od inwentaryzacji, przez łatanie, po zgłoszenie poważnego incydentu do CSIRT w wymaganych terminach. Dla sektora finansowego analogiczne wymogi odporności operacyjnej nakłada DORA.

Praktyczny wniosek: udokumentuj cały proces reakcji. Kiedy wykryto ekspozycję, kiedy nałożono łagodzenia, kiedy zainstalowano łatkę i jaką analizę śladów przeprowadzono. Ta dokumentacja jest zarówno dowodem należytej staranności, jak i podstawą ewentualnego zgłoszenia regulacyjnego. Jeśli potrzebujesz uporządkować te obowiązki, pomocny będzie audyt zgodności obejmujący NIS2 i RODO.

Wnioski dla branży – czego uczy nas PHP2Shell

PHP2Shell stanie obok Heartbleed i Log4Shell jako luka, która podważa coś fundamentalnego w tym, jak myślimy o bezpieczeństwie. Zostają po niej trzy wnioski warte zabrania na dłużej.

Po pierwsze: higiena wersji to nie formalność. Organizacje, które utrzymywały PHP w gałęziach EOL (7.4, 8.0, 8.1 i starszych), nie dostały oficjalnych binariów z łatką. Dług technologiczny w warstwie runtime zamienia się w tym momencie w bezpośrednie ryzyko RCE.

Po drugie: bezpieczeństwo łańcucha dostaw sięga do rdzenia języka. Zabezpieczenie własnego kodu nie wystarczy, jeśli interpreter pod nim jest dziurawy. Inwentaryzacja komponentów (SBOM) musi obejmować runtime, a nie tylko biblioteki aplikacji.

Po trzecie: AI zmieniło ekonomię ataku. Założenie „to zbyt trudne do wykorzystania” przestało być wiarygodną obroną. To, co kiedyś wymagało miesięcy pracy eksperta, dziś zajmuje tydzień. Modele zagrożeń trzeba zaktualizować o przeciwnika, który tanio skaluje złożone exploity na różne wdrożenia.

Dla zespołów bezpieczeństwa oznacza to przesunięcie akcentu z reaktywnego łatania na proaktywną weryfikację. Realistyczne ćwiczenia Red Team i regularne testy penetracyjne, które symulują przeciwnika dysponującego nowoczesnym oprzyrządowaniem, są dziś lepszą miarą odporności niż sama lista zainstalowanych poprawek.

Podsumowanie

PHP2Shell (CVE-2026-109618 i CVE-2026-109619) to dwie krytyczne podatności RCE w rdzeniu PHP o ocenie CVSS 9.2, dotyczące każdej wersji od 5.4 w górę i aktywnie wykorzystywane w atakach. Umożliwiają nieuwierzytelnionemu atakującemu wykonanie poleceń na serwerze oraz odczyt pamięci procesu, niezależnie od jakości kodu aplikacji. Jedynym pełnym zabezpieczeniem jest aktualizacja do PHP 8.5.12, 8.4.27, 8.3.36 lub 8.2.35.

Najważniejsze liczby do zapamiętania: 2 podatności, 9.2 w CVSS v4.0, 70 procent stron w internecie korzysta z PHP, podatność istniała od wersji 5.4 (ponad dekadę), a eksploatacja zaczęła się już 17 października – cztery dni przed ujawnieniem.

Checklist: reakcja na PHP2Shell

  • ☐ Zinwentaryzowano wszystkie instancje PHP (serwery, kontenery, appliance, panele hostingowe)
  • ☐ Zidentyfikowano i priorytetyzowano systemy z Apache mod_php dostępne z internetu
  • ☐ Zaktualizowano PHP do 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 lub potwierdzono łatkę u dostawcy hostingu
  • ☐ Na systemach EOL (7.4/8.0/8.1) zastosowano backport lub zaplanowano migrację
  • ☐ Tam, gdzie nie można łatać od razu, nałożono tymczasowe łagodzenia (session.upload_progress.enabled=Off, post_max_size, max_input_vars)
  • ☐ Zrestartowano workery po zmianach konfiguracji
  • ☐ Wdrożono detekcję: sygnatura PHPSESSID + PHP_SESSION_UPLOAD_PROGRESS oraz procesy potomne PHP
  • ☐ Przeszukano środowisko pod kątem web shelli, nowych kont admin i połączeń wychodzących
  • ☐ Rozważono rotację sekretów (hasła, tokeny, klucze API, certyfikaty) na systemach dostępnych z internetu
  • ☐ Oceniono obowiązki RODO/NIS2 i udokumentowano cały proces reakcji

FAQ – najczęstsze pytania o PHP2Shell

Czy moja strona jest podatna, jeśli używam tylko WordPressa z aktualnymi wtyczkami?

Tak, jeśli serwer działa na niezałatanym PHP od wersji 5.4 w górę. Podatność znajduje się w samym silniku PHP, który parsuje żądanie zanim uruchomi się kod WordPressa. Aktualne wtyczki i motywy nie chronią przed PHP2Shell – liczy się wyłącznie wersja PHP na serwerze.

Jak sprawdzić, jaką wersję PHP mam na serwerze?

Na serwerze z dostępem do powłoki użyj polecenia php -v oraz php -i, aby zobaczyć wersję i konfigurację. Na hostingu współdzielonym wersję PHP znajdziesz w panelu (cPanel, DirectAdmin, Plesk). Jeśli nie masz dostępu, zapytaj dostawcę hostingu, czy zainstalował łatkę z 21 października 2026.

Które wersje PHP są bezpieczne?

Bezpieczne są PHP 8.5.12, 8.4.27, 8.3.36 i 8.2.35 oraz nowsze w tych gałęziach. Dla PHP 7.4, 8.0 i 8.1 opublikowano jedynie minimalne backporty źródłowe, bez oficjalnych binariów, ponieważ te wersje są end of life. PHP 7.3 i starsze oraz cała linia PHP 5 nie otrzymały poprawki – wymagają migracji na wspieraną gałąź.

Czy PHP-FPM jest bezpieczniejszy niż mod_php?

PHP-FPM jest trudniejszy do wykorzystania przez ścieżkę session upload progress, bo worker kończy działanie po błędzie startu żądania. Oficjalne advisory oznacza mod_php jako najwyższe ryzyko. PHP-FPM nie jest jednak bezpieczny – istnieje osobna ścieżka przez deserializer PHP (np. session_start, unserialize), która daje RCE zależne od aplikacji na obu SAPI. Aktualizacja jest konieczna niezależnie od SAPI.

Czy tymczasowe łagodzenia wystarczą, jeśli nie mogę od razu zaktualizować?

Nie. Zespół PHP wprost stwierdza, że nie istnieją pełne łagodzenia, a aktualizacja jest jedynym bezpiecznym wyborem. Ustawienia takie jak session.upload_progress.enabled=Off, ograniczenie post_max_size i max_input_vars redukują ekspozycję na pierwszą falę masowych ataków, ale nie zamykają wszystkich ścieżek. Traktuj je jako rozwiązanie awaryjne do czasu załatania.

Jak rozpoznać, że ktoś próbował wykorzystać PHP2Shell?

Najbardziej charakterystyczny wskaźnik to wartość PHPSESSID i pole PHP_SESSION_UPLOAD_PROGRESS przesłane razem w jednym uploadzie. Dodatkowe objawy to nietypowe żądania multipart, po których następują błędy limitu pamięci lub HTTP 500, zniekształcone ciasteczka PHPSESSID oraz częste restarty workerów PHP. Na poziomie systemu szukaj procesów powłoki uruchamianych przez php-fpm, apache czy nginx (MITRE ATT&CK T1505.003).

Czy po załataniu muszę rotować hasła i klucze API?

Powinieneś to rozważyć dla systemów PHP dostępnych z internetu. Jedna ze ścieżek PHP2Shell pozwala odczytać pamięć procesu PHP, w której mogły znaleźć się hasła, tokeny sesyjne, klucze API i certyfikaty z innych żądań. Ponieważ atak nie zostawia śladów w logach aplikacji, nie można wykluczyć wycieku na podstawie samego braku alertów – rotacja sekretów jest rozsądnym środkiem ostrożności.

Czy PHP2Shell rodzi obowiązki wynikające z RODO lub NIS2?

Tak, jeśli doszło do nieautoryzowanego dostępu do danych osobowych. Z perspektywy RODO administrator ma 72 godziny na zgłoszenie naruszenia do UODO, gdy ryzyko dla osób jest realne. Podmioty objęte NIS2 i ustawą o KSC mają obowiązek obsługi incydentu i jego zgłoszenia do właściwego CSIRT. Kluczowe jest udokumentowanie całego procesu reakcji, bo cichy charakter ataku utrudnia udowodnienie braku naruszenia.

Źródła

Artykuł opiera się na oficjalnych komunikatach i pierwotnych analizach technicznych opublikowanych przez zespół PHP oraz zespoły badawcze, które odkryły i skoordynowały ujawnienie podatności:

Potrzebujesz pewności, że Twoja infrastruktura jest odporna?

PHP2Shell pokazało, że pojedyncza luka w warstwie runtime potrafi obejść lata starań o bezpieczny kod aplikacji. Jeśli chcesz zweryfikować, jak Twoja infrastruktura i aplikacje wytrzymują realistyczny scenariusz ataku – z wykorzystaniem podatności w rdzeniu, a nie tylko w kodzie – skontaktuj się z zespołem VIPentest. Przeprowadzimy testy penetracyjne i audyt zgodności, które odpowiedzą na pytanie, czy Twoja organizacja przetrwa następne PHP2Shell.

Gotowy zabezpieczyć swoją infrastrukturę?

Skontaktuj się z nami i otrzymaj bezpłatną konsultację. Nasi certyfikowani eksperci pomogą dobrać optymalny zakres testów penetracyjnych dla Twojej organizacji.

    Wyrażam zgodę na przetwarzanie moich danych osobowych przez VIPentest sp. z o.o. w celu odpowiedzi na zapytanie. Szczegóły w Polityce Prywatności.

    Bez zobowiązań. NDA przed rozmową o zakresie.