PHP2Shell: panika miała rację co do wagi, ale nie co do szczegółów
21 października 2026 PHP wydał awaryjne poprawki dwóch krytycznych luk, nazwanych zbiorczo PHP2Shell. Obie pozwalają przejąć serwer bez logowania, a siedzą w samym interpreterze, więc dotyczą WordPressa, sklepów i paneli tak samo jak każdej innej aplikacji w PHP. Dzień wcześniej internet żył zrzutami ekranu z wycieku: CVSS 10.0, „70% internetu”, jedna flaga w php.ini jako remedium. Panika miała rację co do wagi problemu i myliła się w większości szczegółów, które mówią, co właściwie zrobić. Ten wpis rozdziela jedno od drugiego. Ciekawsza jest jednak druga warstwa: błąd ma ślady sprzed lat, a dopiero zespoły pracujące z modelami AI doprowadziły go do działającego ataku.
Teza
Waga jest realna: zdalne wykonanie kodu bez uwierzytelnienia, w kodzie, przez który przechodzi niemal każde zapytanie. Ale z czterech najczęściej powtarzanych „faktów” jeden był po prostu błędny, jeden był skrótem myślowym, jeden się bronił, a jeden pomijał najważniejsze zastrzeżenie. Kto działał na podstawie zrzutów ekranu, mógł załatać nie tę lukę albo uznać serwer za bezpieczny, choć wcale nie był.
Druga część tezy: AI nie wymyśliło nowej klasy błędów. Skróciło drogę od „to miejsce w kodzie wygląda podejrzanie” do „mam działający exploit”. Ta droga przez lata była barierą, która chroniła stary kod. Teraz ta bariera słabnie, a koszt jej utraty ponoszą głównie obrońcy i mali opiekunowie projektów open source.
Co jest faktem
Na podstawie komunikatu PHP Foundation (thephp.foundation), ogłoszenia na php.net (stąd wersja CVSS) i CERT Polska (moje.cert.pl):
| CVE-2026-109618 | CVE-2026-109619 | |
|---|---|---|
| Mechanizm | uszkodzenie pamięci po przekroczeniu memory_limit w złym momencie | nieaktualny stan globalny po błędzie krytycznym, use-after-free w kolejnym zapytaniu tego samego workera |
| Co potwierdzono | RCE na Apache z mod_php przy domyślnych ustawieniach, przed wykonaniem kodu aplikacji; RCE na PHP-FPM przez ścieżki w aplikacji | use-after-free i crash workera; reporter pokazał RCE na realnej aplikacji (Apache + mod_php) |
| CVSS v4.0 (zespół PHP) | 9.2 | 9.2 |
Wersje z poprawką: 8.5.12, 8.4.27, 8.3.36, 8.2.35. Dla gałęzi 7.4–8.1 zespół PHP opublikował minimalne łatki źródłowe, ale nie wyda dla nich oficjalnych wersji (tenable.com). Starsze gałęzie nie dostaną nic od projektu PHP. Zostają poprawki dystrybucji, które często przenoszą łatkę do starszego numeru wersji (np. AlmaLinux). Dlatego sam numer z php -v niczego nie rozstrzyga.
Co media przekręciły
„70% internetu”
Wiz zatytułował swój wpis „affecting 70% of the Internet”, a w treści pisze, że PHP „napędza 70% wszystkich stron na świecie” (wiz.io). To udział rynkowy PHP: W3Techs podaje 69,3% stron o znanym języku serwera (za Tenable). Nie jest to liczba stron potwierdzonych jako podatne. Tenable cytuje dwa szacunki pojedynczych badaczy: ponad 1,3 mln potencjalnie podatnych hostów wg Silasa Cutlera i ponad 1,9 mln hostów z PHP w Shodanie wg Henka Poleya. Insurance Business przytacza dużo wyższy szacunek Palo Alto Unit 42: ponad 22,6 mln systemów, które mogą być podatne. To deklaracja dostawcy ochrony, bez opisanej metody. Rząd wielkości jest poważny, ale „70% internetu do przejęcia” to skrót myślowy.
CVSS 10.0
Identyfikatory CVE, które krążyły przed publikacją, miały ocenę 10.0. PHP Foundation nazywa ją wprost błędną, a zespół PHP ocenia obie luki na 9.2 w CVSS v4.0. Alexandre Daubois z zespołu bezpieczeństwa PHP opisuje, że 10.0 szło od postu Floriana Rotha (w przekazie Phoenix Security), a według Cyber Daily watchTowr mówił to samo (daubois.dev). Praktycznie różnica nie zmienia priorytetu. Pokazuje natomiast, ile informacji przyszło z drugiej ręki.
„Wszystko od PHP 5.4”
Ten fakt akurat się broni: Wiz i Calif wskazują PHP 5.4 jako najstarszą podatną wersję. Daubois dodaje dwa zastrzeżenia. Po pierwsze, watchTowr wymieniał wersje 5, 6, 7 i 8, a PHP 6 nigdy nie wyszło. Po drugie, mechanizm sięga dalej niż plotka, bo ten sam skok jest w alokatorze PHP 5.3, choć Daubois nie widział exploita pokazanego na tak starych wersjach.
Jedna flaga w php.ini
Tu pomyłka była najbardziej szkodliwa. Najczęściej powtarzana rada brzmiała session.upload_progress.enabled = Off. Według Daubois ta flaga dotyczy wyłącznie CVE-2026-109619. Advisory dla CVE-2026-109618 w ogóle nie wspomina o sesjach. Kto ją ustawił i uznał sprawę za zamkniętą, zostawił otwartą drugą lukę.
Obejście, które advisory PHP stawia na pierwszym miejscu, wygląda za to jak antywzorzec: wymusić memory_limit=-1 (żeby aplikacja nie mogła go nadpisać) i nie używać RLIMIT_AS. Daubois pisze, że nie znalazł go w żadnym przeglądanym omówieniu. Sens tej rady widać dopiero, gdy zna się mechanizm. Calif opisuje dwie drogi do przekroczenia memory_limit (calif.io):
- Obejście
post_max_size. PHP porównuje limit z zadeklarowanymContent-Length, a nie z bajtami, które faktycznie zużywa. Zapytanie chunked w HTTP/1.1 albo bez długości w HTTP/2 przechodzi kontrolę. - Wyczerpanie pamięci poniżej
post_max_size. Pusty upload (filename="") nie liczy się domax_file_uploads, a i tak tworzy sześć wpisów w$_FILES. Przy zagnieżdżonych nazwach pól każdy krótki rekord rozrasta się do wielu tablic haszujących.
Skoro błąd odpala się w momencie przekroczenia limitu pamięci, zdjęcie limitu usuwa ten moment. W zamian trzeba ograniczyć pamięć z zewnątrz: limitem rozmiaru zapytań na serwerze lub proxy oraz limitem pamięci kontenera albo cgroup. CERT Polska podaje swój zestaw wartości tymczasowych (memory_limit -1 lub co najmniej 128M, post_max_size ≤ 8M, max_input_vars ≤ 1000, upload progress off) i zastrzega wprost, że żadna z nich nie wyklucza ataku.
Słaby punkt tej sekcji: opieram się tu na relacji jednej osoby z zespołu PHP i na opisie Calif. Treści samych advisory na GitHubie nie analizowałem linijka po linijce.
Czy ktoś już atakuje? Źródła się nie zgadzają
| Kto | Co twierdzi |
|---|---|
| PHP Foundation | analizowała PoC krążące po wycieku i „nie zidentyfikowała działających exploitów w chwili wydania” |
| Amazon Threat Intelligence (za Tenable) | próba ataku na honeypot już 17 października, 4 dni przed ujawnieniem; „szeroko wykorzystywana” |
| Cloudflare (CTO, za Tenable) | „pojawiają się pierwsze ataki”, reguły WAF aktualizowane na bieżąco |
| watchTowr (za Tenable) | odtworzył obie luki, obserwuje próby wykorzystania |
Te twierdzenia nie muszą się wykluczać. „Brak działającego exploita w chwili publikacji” i „próby ataku” to różne rzeczy. Próba na honeypot nie mówi, czy atak zadziałałby na prawdziwym serwerze. Do tego Calif miał działający PoC od sierpnia i według PHP Foundation pokazał go w usuniętym potem nagraniu. Uczciwe podsumowanie: na 22 października mamy deklaracje firm, które sprzedają ochronę, i ostrożny komunikat projektu, który odpowiada za kod. Potwierdzonego publicznie włamania nie znalazłem.
Jak pękło embargo
Według Daubois i PHP Foundation embargo pękło jednego dnia w kilku miejscach. 20 października na Hacker News pojawił się anonimowy post, który zniknął, ale zrzuty zdążyły trafić na X i Mastodona. Wyciekł zrzut ekranu narzędzia PHP2Shell przypisanego Calif i krótkie nagranie z exploitem. watchTowr publicznie potwierdził, że luki są prawdziwe, i podał numery CVE. 21 października o 07:41 UTC Chainguard, który dostał łatkę z wyprzedzeniem jak inni dystrybutorzy, opublikował obrazy z poprawką ponad sześć godzin przed skoordynowanym wydaniem. PHP przesunęło publikację o dzień do przodu.
Po publikacji poprawek brytyjskie NCSC zaleciło, żeby systemy, których nie da się szybko załatać, rozważyć wyłączenie. Według Insurance Business offline poszły m.in. holenderskie DigiD i MijnOverheid, usługi fińskiego Valtori, część serwisów ITZBund, brytyjskie rady miejskie i Met Police. Przy holenderskich serwisach źródło pisze wprost o ostrożności. Przy brytyjskich podaje tylko, że były niedostępne, bez przyczyny. Doniesień o włamaniu do któregokolwiek z nich nie znalazłem.
Wątek AI: nie nowy błąd, tylko krótsza droga
Oś czasu z opisu Calif (calif.io) jest tu ważniejsza niż sama nazwa luki:
- 2004: Stefan Esser opisuje pierwszą zdalną podatność PHP związaną z limitem pamięci.
- 2020: zgłoszenie #78876 w bugtrackerze PHP.
- 2024: audyt bezpieczeństwa PHP (OSTIF, Quarkslab; finansowanie niemieckiej Sovereign Tech Agency wg PHP Foundation) wydobywa powiązany błąd. Calif pisze, że audyt go „odkrył na nowo”, a PHP Foundation, że pierwsze ślady znalazł deweloper rdzenia przy naprawie innego zgłoszenia. Nie udowodniono wtedy, że da się go wykorzystać.
- sierpień 2026: Calif znajduje kilka niezależnych ścieżek do RCE. Badacz pisze, że punktem wyjścia było szukanie „zaginionego rodzeństwa” błędu z 2004 roku z pomocą swojego „LLM companion”. 11 sierpnia Calif zgłasza pierwszy błąd do PHP, 15 sierpnia PHP potwierdza działający PoC.
- 11 sierpnia 2026: według PHP Foundation niezależnie tę samą przyczynę zgłasza też OpenAI (zespół Codex Security), a kolejne wektory 18 września.
- 19–24 sierpnia 2026: Wiz niezależnie znajduje luki, wg własnej osi czasu z użyciem m.in. Gemini i GPT, potwierdza RCE na Drupalu i WordPressie i zgłasza je do PHP (wiz.io).
Na błąd z 2004 roku istniały exploity, choć niepubliczne. Za to od zgłoszenia z 2020 roku problem był znany i opisany, a mimo to przez sześć lat nikt publicznie nie przeszedł całej drogi do działającego ataku. Wiz pisze, że gdy maleje nakład pracy potrzebny do zbudowania exploita, „złożoność może przestać być znaczącą barierą”. To jest moim zdaniem najważniejsze zdanie całej historii. Dużo starego kodu było bezpieczne nie dlatego, że nie miał błędów, ale dlatego, że ich wykorzystanie było zbyt drogie. Ta ochrona tanieje.
Druga strona medalu jest w komunikacie PHP Foundation. Od 1 lipca zespół opublikował 15 CVE i przerobił ponad 100 zgłoszeń, które okazały się nieważne, zduplikowane lub nie do odtworzenia. Fundacja pisze, że AI pomaga walidować i grupować raporty, ale każdą decyzję i każdą łatkę robi człowiek. Kończy apelem o finansowanie do firm, hostingodawców i instytucji publicznych, których usługi stoją na PHP.
To samo narzędzie przyspiesza więc obie strony, ale nierówno. Atakującemu wystarczy jeden działający łańcuch. Obrońca musi przesiać setkę zgłoszeń, napisać poprawkę, która nie zepsuje wydajności ani zewnętrznych rozszerzeń, i doczekać, aż hostingodawcy ją wdrożą. Wiz zauważa przy tym, że zgłoszone cztery błędy to nie wszystko, bo problem jest „głęboko zakorzeniony w kodzie PHP” i inne warianty mają podpadać pod te same dwa CVE.
Słaby punkt: „AI znalazło lukę” to skrót z nagłówków. We wszystkich trzech zgłoszeniach (Calif, OpenAI, Wiz) pracowali doświadczeni badacze, a model był narzędziem. Udziału AI nie da się z zewnątrz zmierzyć i opieram się tu na deklaracjach samych firm, z których co najmniej dwie (Wiz, OpenAI) mają interes w eksponowaniu roli swoich narzędzi.
Co z tego wynika w praktyce
Malcolm McDonald w Grokking Web Application Security zauważa, że podatności nisko w stosie, w runtime albo w OpenSSL, są rzadsze, ale „often more severe”. O Heartbleed z 2014 roku pisze, że łatka była dostępna od razu, a mimo to „the sheer number of servers that had to be updated meant that chaos reigned for months” (s. 277). PHP2Shell wygląda na powtórkę tego wzorca. Poprawka jest od pierwszego dnia, a wąskim gardłem jest wdrożenie na milionach serwerów, w tym na hostingach współdzielonych, gdzie właściciel strony nie ma wpływu na wersję PHP.
W innym miejscu (s. 99) McDonald przestrzega przed „busywork” przy alertach ze skanowania zależności i radzi patrzeć, czy podatny kod jest w ogóle osiągalny. Tutaj ta furtka praktycznie się zamyka. Podatny jest sam interpreter, który obsługuje każde zapytanie, a na mod_php atak działa, zanim ruszy kod aplikacji. Wyjątkiem może być PHP uruchamiane tylko z CLI, bez ruchu WWW.
- Zaktualizuj PHP i zweryfikuj to u dostawcy, nie po numerze wersji. Na hostingu współdzielonym zapytaj support wprost o oba numery CVE.
- Jeśli stosujesz obejścia, stosuj komplet dla obu CVE, nie samą flagę od sesji. Traktuj je jako tymczasowe i wróć do skończonego
memory_limitpo aktualizacji. - WAF kupuje czas, ale nie naprawia. Reguły Cloudflare i innych dostawców łapią znane warianty, a Wiz uprzedza o kolejnych.
- PHP 8.1 i starsze to dług z terminem płatności. Minimalne łatki źródłowe dla 7.4–8.1 nie zastąpią migracji.
- Patrz, kto mówi. W tej historii dostawca kodu, firmy badawcze, dostawcy ochrony i media podawali różne liczby z różnych powodów. Przed decyzją warto sprawdzić źródło pierwotne.
Źródła
- PHP Foundation: Today's PHP Security Release, and How We're Strengthening PHP Security
- php.net: News Archive 2026
- CERT Polska: Krytyczne podatności w PHP umożliwiające zdalne wykonanie kodu – php2shell
- Alexandre Daubois: What the PHP2Shell rumors got wrong, from inside the PHP security team
- Calif: php2shell – A tale of two PHP remote vulnerabilities
- Wiz Research: PHP2Shell
- Tenable: php2shell FAQ
- Insurance Business: UK councils and Met Police among sites pulled offline after NCSC alert