⚡️ Кратко: ключевые факты и быстрый ответ
- PHP Armageddon — это две критические уязвимости в ядре PHP: CVE-2026–109618 и CVE-2026–109619 с рейтингом 9.2 из 10, исправления вышли внепланово 21 октября 2026 года.
- Исследователи назвали связку PHP2Shell: она позволяет удалённо выполнить код на сервере без логина, без пароля и без ошибок в коде самого сайта , только за счёт разбора входного запроса интерпретатором.
- До установки обновления рабочий минимум , закрыть на уровне веб-сервера приём составных запросов (multipart) и открыть его точечно только на эндпоинтах загрузки файлов.
- Главный подводный камень: патч закрывает вектор, но не стирает следы. Если сервер был доступен из сети всё это время, логи и каталоги загрузок нужно проверить отдельно.
- Что случилось: две критические уязвимости в ядре PHP
- Как ИИ нашёл дыры, которые жили десятилетиями
- Под капотом PHP2Shell: как работает удалённое выполнение кода
- Сравнение способов защиты: патч, nginx, WAF и изоляция
- Как закрыть сервер до патча: блокируем multipart на nginx
- Что делать после обновления: аудит логов и поиск веб-шеллов
- Кто под ударом: оценка рисков для сайтов Рунета
- Чек-лист: что сделать в первые 24 часа
- Часто задаваемые вопросы (FAQ)
- Что именно взломали — мой сайт на WordPress или сам язык PHP?
- Как за пять минут понять, под ударом ли мой сервер?
- Обновление страшно ставить в прод, как не уронить сайт?
- Можно ли прикрыться nginx и WAF и спокойно жить до обновления?
- Как понять, что сервер уже скомпрометировали?
- 💡 В сухом остатке: главное
Что случилось: две критические уязвимости в ядре PHP
21 октября 2026 года команда PHP выпустила внеплановые патчи, закрывающие две критические уязвимости в ядре языка — CVE-2026–109618 и CVE-2026–109619. Обе получили 9.2 балла из 10 по шкале CVSS, то есть формально это «критично» с минимальным зазором до максимума.
Внеплановый релиз для PHP — событие редкое. Обычно ветки обновляются по календарю, с бета-версиями и предупреждениями за месяцы. Здесь же от публикации информации до выхода исправлений прошли считаные дни.
Суть проблемы исследователи упаковали в имя PHP2Shell — «из PHP в шелл». Речь об удалённом выполнении кода на сервере: без логина, без пароля и без единой ошибки в вашем прикладном коде. Дыра сидит в самом ядре интерпретатора, поэтому типовой сайт на фреймворке с аккуратной валидацией ничем не защищён.
⚠️ Подводный камень: «У меня же всё на ORM и никаких eval» здесь не аргумент. Уязвимость отрабатывает раньше, чем управление доходит до вашего кода — на этапе разбора входящего запроса. Отсюда и скорость: единственная реальная мера — обновление самого интерпретатора.
Масштаб оценивают сдержанно и всё равно тревожно. Аналитики MWS AI и Positive Technologies после публикации патчей заговорили о десятках тысяч сайтов в Рунете под потенциальным ударом; официальная рекомендация у обеих сторон одна , ставить обновления немедленно, не дожидаясь планового окна обслуживания.
Отдельная линия этой истории , источник находки. Обе бреши вылезли при анализе исходников ядра с привлечением ИИ-инструментов: модели прошлись по ветвям обработки входных данных и вытащили конструкции, которые годами жили незамеченными. Подробную методику команда PHP не раскрывала, но сам факт показателен — то, что не находили глазами десятилетиями, машина нашла пачкой. Как агент вообще перемещается по чужой кодовой базе, мы разбирали в материале про токены, контекст и MCP на пальцах.
Слово Armageddon в названии дня тоже не случайно. В пентест-сообществе оно давно занято — ещё в 2021 году так называлась машина на Hack The Box, где привилегии поднимали через нашумевший Dirty Sock; тот разбор до сих пор читается как учебник по локальному повышению прав. Нынешняя история масштабнее: там нужен был доступ к машине, здесь , только сеть и уязвимый PHP.
📌 Важно: 9.2 из 10 — это оценка не «сложности эксплуатации», а последствий. Эксплойт не требует учётной записи, значит периметр, закрытый авторизацией, здесь не прикрытие. Считать часы до патча стоит по количеству публичных IP с открытым PHP, а не по важности данных внутри.
В сухом остатке факты простые: две уязвимости, один внеплановый релиз, дата — 21 октября. Что делать дальше и как выиграть время, если обновиться прямо сейчас нельзя, разберём ниже.
Как ИИ нашёл дыры, которые жили десятилетиями
Методика выглядит буднично: языковые модели читают код интерпретатора и историю коммитов, выдвигают гипотезы об опасных путях исполнения, а мутационные фаззеры проверяют каждую гипотезу потоком входных данных. Ничего мистического, просто два инструмента наконец научились разговаривать друг с другом.
Раньше эти два лагеря жили отдельно. Фаззеры вроде AFL++ или libFuzzer отлично отрабатывали на бинарниках, где покрытие измеряется сантиметрами машинного кода. Но у интерпретатора вход — это не байты, а текст программы. Чтобы добраться до интересной ветки, фаззеру нужно сгенерировать синтаксически валидный скрипт, который пройдёт парсер и вызовет нужную функцию ядра. Слепые мутации до таких глубин почти не доходят.
Статический анализ страдал от зеркальной проблемы. CodeQL, Semgrep и компиляторные предупреждения ищут по правилам, а правила кто-то должен написать руками. Если разработчик не подозревает, что обработка входящего запроса где-то теряет проверку границ, то и соответствующего правила в базе не появится. Дыра спокойно живёт десятилетиями — до первого, кто догадается посмотреть именно в это место.
| Этап конвейера | Классический подход | С участием LLM |
|---|---|---|
| Поиск подозрительных мест | Правила, написанные вручную | Модель читает диффы и старые коммиты, ранжирует участки по риску |
| Гипотеза об уязвимости | Опыт и интуиция аудитора | Модель описывает сценарий эксплуатации словами и кодом |
| Проверка гипотезы | Слепой фаззинг с покрытием | Фаззер получает валидные затравки под конкретную ветку |
| Отсев мусора | Ручной разбор срабатываний | Модель второго прохода объясняет, почему путь недостижим |
Ключевой сдвиг произошёл на стыке: модели научились генерировать не только рассуждения, но и рабочие затравки для фаззера. Плюс они неплохо восстанавливают неявные инварианты по истории изменений — видят, что проверку когда-то добавили в одну ветку обработки и забыли продублировать в соседнюю. Человек такое находит выборочно, машина — за прогон.
Судя по первым рекомендациям по смягчению последствий, проблемный путь шёл через обработку составных запросов на загрузку данных. Отсюда и совет закрывать такие запросы на уровне веб-сервера целиком, оставляя их только на явно нужных точках приёма файлов — разбор ранних мер защиты от Мэттиаса Геннарта как раз об этом.
⚠️ Подводный камень: модель охотно рассказывает красивую историю эксплуатации там, где путь на самом деле недостижим. Без второго прохода , с фаззером и ручной валидацией , такой аудит превращается в фабрику ложных срабатываний и сожжённых часов команды.
Так что ИИ здесь не «нашёл» в смысле озарения. Он сыграл роль очень начитанного напарника, который прочитал все диффы за последние годы и подсказал, куда смотреть. Проверял всё равно инструмент. Если хотите понять, как устроена работа таких моделей с контекстом и внешними инструментами, у нас есть отдельный разбор, как работает ИИ-агент: токены, контекст и MCP на пальцах.
📌 Важно: связка «LLM + фаззинг» снижает порог входа в аудит сложных кодовых баз, но не отменяет правило: находка считается находкой только после воспроизводимого падения с понятным стеком вызовов.
Под капотом PHP2Shell: как работает удалённое выполнение кода
PHP2Shell — это цепочка из двух дыр в ядре интерпретатора, где разбор входящего запроса приводит к выполнению чужого кода с правами веб-сервера. Логин не нужен: уязвим сам слой, который принимает данные ещё до вашего скрипта.
Самое неприятное тут — момент срабатывания. Код приложения ещё не начал выполняться, а интерпретатор уже разбирает тело запроса и заголовки. Всё, что вы написали в index.php, в этот момент вообще не имеет значения.
Давайте разберём цепочку по шагам, без готовых эксплойтов — сути это не меняет, а копировать рабочие полезные нагрузки из статьи всё равно не стоило бы.
Шаг 1. Разведка. Атакующий ищет, где вообще живёт PHP: заголовки ответа, характерные страницы ошибок, поведение при кривых запросах. Задача — понять версию и то, как запросы доходят до интерпретатора: напрямую, через обратный прокси или через отдельный пул PHP-FPM.
Шаг 2. Формирование запроса. Собирается составной запрос с нестандартной структурой: необычные границы частей, вложенные метаданные, несоответствие заявленной длины реальному телу. Ничего экзотического — обычный HTTP, который пройдёт через любой роутер.
Шаг 3. Триггер парсера. Интерпретатор начинает разбор тела запроса и попадает в уязвимый участок ядра. Здесь и срабатывает первая дыра: логика разбора выходит за границы ожидаемого буфера.
Шаг 4. Управление памятью. Вторая уязвимость превращает повреждение в контролируемое: подменяются внутренние структуры, и дальнейшее исполнение идёт по сценарию атакующего. Именно связка двух багов даёт название «из PHP в шелл».
Шаг 5. Выполнение. Полезная нагрузка исполняется с правами пользователя, под которым работает веб-сервер или пул обработчиков. Оттуда — чтение конфигураций, доступ к базе, запись файла в каталог загрузок для закрепления.
Обратите внимание на масштаб: приложение может быть написано идеально, с подготовленными выражениями и валидацией. Дыра всё равно сработает, потому что она этажом ниже. Это ровно та ситуация, когда защита периметра важнее чистоты кода , тот же принцип минимальных привилегий, что мы разбирали в материале про права доступа ИИ-агента: разбор, почему 120 вместо 100.
⚠️ Подводный камень: главное ограничение PHP2Shell , запрос обязан дойти до интерпретатора в составном виде (multipart/form-data). Рекомендации по экстренному смягчению, разлетевшиеся по инженерным чатам 21–22 октября, сходятся на одном: резать такие тела на веб-сервере и разрешать их только на маршрутах загрузки файлов. Если перед PHP стоит прокси, отбрасывающий составные тела на всех остальных путях, атакующий остаётся ни с чем.
Второе ограничение — сетевая доступность. Сервис за NAT, без внешнего маршрута к уязвимому обработчику, эксплуатировать снаружи не получится. Но это слабое утешение для публичных сайтов.
Что это даёт на практике? Оборона сводится к двум действиям: как можно быстрее обновить интерпретатор и поставить фильтр на составные запросы. Подробный разбор инцидента и официальные рекомендации команды PHP собраны в материале «PHP взломали! Обороняемся» — там же указаны конкретные ветки, для которых вышли внеочередные сборки.
Сравнение способов защиты: патч, nginx, WAF и изоляция
Быстрее всего закрывает дыру правило на веб-сервере: 15–30 минут и перезагрузка конфигурации. Надёжнее всего — обновление ядра PHP, потому что оно убирает саму уязвимость, а не её проявления. WAF и изоляция работают как страховка на время, пока патч не доехал до всех серверов.
Именно поэтому вопрос «что выбрать» обычно ставится неправильно. Выбирать нужно не одну меру, а порядок действий. Сначала жгут, потом лечение, и только затем , антибиотики на постоянку.
| Мера | Время внедрения | Что именно закрывает | Цена ошибки | Остаточный риск |
|---|---|---|---|---|
| Патч ядра PHP | 2–4 часа на тестовом контуре, 1–3 дня на парке серверов | Корень проблемы: сам механизм удалённого выполнения кода | Ломается совместимость сторонних расширений, нужен откат и повторное тестирование | Низкий по конкретной уязвимости, но остаются старые сборки и забытые тестовые стенды |
| Правило в nginx | 15–30 минут | Вектор доставки вредоносного запроса , например, точечная блокировка составных запросов | Отваливаются загрузки файлов, аватарки и приёмы вложений через API | Средний: обход через разрешённые точки приёма файлов и другие протоколы |
| WAF | 30 минут на включение, от суток на настройку правил | Сигнатуры известных атак и аномальное поведение запросов | Ложные срабатывания на легитимном трафике, блокировка живых клиентов | Средний: обфускация запросов и внутренний трафик вне зоны фильтрации |
| Изоляция (контейнер, непривилегированный пользователь, read-only файловая система) | Недели: меняется архитектура и права | Не саму уязвимость, а последствия: размах доступа после пробития | Рост сложности эксплуатации, проблемы с правами на запись в кэш и логи | Уязвимость остаётся, но превращается из «сервер наш» в «упал один контейнер» |
Обратите внимание на асимметрию в последнем столбце. Патч закрывает причину, всё остальное — только окно возможностей. Это не значит, что остальное не нужно. Это значит, что остальное не заменяет обновление.
⚠️ Подводный камень: самое популярное правило «запретить все составные запросы целиком» ломает половину сайта. Формы с файлами, редакторы в админке, мобильные клиенты с загрузкой фото — всё это уходит в ошибку. Правило нужно ставить в режим логирования, собрать реальные точки приёма файлов за сутки и только потом запрещать остальное.
На практике выяснилось ещё одно неочевидное место: WAF часто ставят перед балансировщиком, а внутренние сервисы ходят друг к другу напрямую, минуя фильтр. В итоге внешний периметр чистый, а между сервисами летает что угодно.
С изоляцией та же история. Контейнер с правами root внутри и смонтированным сокетом оркестратора даёт ровно ноль выигрыша. Прежде чем гордиться контейнеризацией, проверьте, от какого пользователя стартует процесс и что висит в томах , мы разбирали похожую логику ограничения прав в материале про права доступа ИИ-агента.
💡 Инсайт: рабочий порядок такой , сегодня правило в nginx и включённый WAF в режиме наблюдения, на этой неделе патч на канареечную группу серверов, в течение месяца изоляция для самых публичных морд. Патч обязан быть первым в очереди по срокам, а не последним по важности.
И да, про самую дешёвую меру забывают чаще всего: инвентаризация. Пока вы не знаете, на каких хостах вообще крутится интерпретатор, никакой график обновлений не сработает.
Как закрыть сервер до патча: блокируем multipart на nginx
Полный запрет составных запросов на nginx делается одной проверкой заголовка Content-Type в директиве map и возвратом кода 403, а точечное разрешение — узким белым списком адресов загрузки, где multipart остаётся рабочим.
Логика простая. Разбор составного тела — отдельный парсер внутри интерпретатора, и он включается ровно в тот момент, когда в заголовке стоит multipart/form-data. Нет заголовка — нет парсера. Значит, резать надо на входе, ещё до того, как тело дочитается до конца и попадёт во временный файл.
Собираем три карты: признак составного запроса, список доверенных точек загрузки и итоговое правило запрета.
# 1. Признак составного тела — только по заголовку
map $http_content_type $is_multipart {
default 0;
"~*^multipart/form-data" 1;
}
# 2. Белый список точек загрузки — строго по $uri
map $uri $is_upload_zone {
default 0;
"/api/v1/avatar" 1;
"/api/v1/attachments" 1;
}
# 3. Запрет срабатывает только там, где multipart не ждут
map "$is_multipart$is_upload_zone" $deny_multipart {
default 0;
"10" 1;
}
server {
listen 443 ssl;
server_name example.com;
client_max_body_size 1m;
if ($deny_multipart) {
return 403;
}
}
Конструкция с `if` в контексте server выглядит подозрительно, но здесь это единственный безопасный сценарий: внутри блока ровно один `return`, никакой другой логики. Проверка отрабатывает в фазе server rewrite, то есть раньше, чем nginx вообще начнёт читать тело запроса. Мусорный поток от бота отваливается на первом же пакете.
📌 Важно: Регулярка ~* нечувствительна к регистру, поэтому MultiPart/Form-Data тоже отсекается. А вот параметр boundary в заголовке проверке не мешает — якорь стоит только на начале строки.
Теперь исключение. Точка загрузки должна совпадать с `location =` побайтово, иначе белый список разъедется с реальной маршрутизацией.
location = /api/v1/avatar {
if ($is_multipart = 0) { return 415; }
limit_except POST { deny all; }
client_max_body_size 2m;
client_body_buffer_size 128k;
client_body_timeout 20s;
include fastcgi_params;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
Обратная проверка на 415 необязательна, но полезна: точка загрузки должна принимать только то, ради чего её открыли. Лимит размера и таймаут тела закрывают второй сценарий , медленную отправку, которая держит воркер открытым часами.
⚠️ Подводный камень: Заголовок , не единственный вход в парсер. Если ваш код или сторонняя библиотека сами разбирают php://input как составное тело, не глядя на Content-Type, защита не сработает. Проверяйте гипотезу на стенде, а не на продакшене.
Перед включением соберите карту загрузок по логам. Добавьте `$content_type` в формат и прогоните историю за пару недель.
log_format with_ct '$remote_addr "$request" "$http_content_type" $status';
awk -F'"' '$4 ~ /multipart/ {print $2}' /var/log/nginx/access.log \
| sort | uniq -c | sort -rn | head -40
💡 Инсайт: Тот же принцип минимальных привилегий, что мы разбирали в материале про права доступа ИИ-агента и разницу между 120 и 100, работает и здесь: не «разрешить всем, кроме плохих», а «разрешить ровно двум адресам из тысячи». Список из двух строк проще проверить глазами, чем конфиг на три экрана.
И трезвая мысль напоследок. Блокировка на nginx — это жгут, а не лечение: она выигрывает часы или сутки, пока выкатывается обновление интерпретатора. Ломается при этом многое — визуальные редакторы CMS, формы с вложениями, вебхуки платёжек. Поэтому включайте в режиме наблюдения, сверяйтесь с логами и снимайте правило сразу после установки патча.
Что делать после обновления: аудит логов и поиск веб-шеллов
Аудит после обновления — это три обязательных шага: поиск следов эксплуатации в журналах веб-сервера, охота за веб-шеллами в каталогах загрузок и полная ротация всех секретов, до которых мог дотянуться чужой код на сервере.
Патч закрывает вход, но не отменяет того, что произошло до него. Если уязвимость эксплуатировали в промежутке между публикацией информации о ней и установкой исправлений, на диске уже лежит чужой код. Дальше вопрос только в том, заметите вы его или нет.
Начните с журналов доступа. Нам нужны записи минимум за две–четыре недели до даты выхода исправлений, включая архивные и сжатые файлы — их читают через zgrep, иначе картина будет неполной.
Ищите запросы методом POST с типом содержимого multipart на адреса, где загрузки никогда не планировались: главная, страницы каталога, обработчики форм обратной связи. Отдельный признак — ответы с кодом 200 на запросы к файлам .php внутри папок для картинок и документов. Нормальный сайт так себя не ведёт.
Дальше — файловая система. Сортируйте файлы по времени изменения и смотрите всё, что появилось в каталогах загрузок и кэша. Опыт показывает, что веб-шеллы почти всегда маскируются под картинку или безобидный скрипт с коротким случайным именем.
| Маркер в коде | О чём говорит |
|---|---|
| eval, assert, create_function | Выполнение кода из строки, типичная обвязка шелла |
| base64_decode, gzinflate, str_rot13 | Скрытие полезной нагрузки от глаз администратора |
| $_POST, $_REQUEST с длинными именами | Приём команд извне под видом обычного поля формы |
| .user.ini, .htaccess с auto_prepend_file | Автоподключение чужого файла ко всем страницам сайта |
Файлы нашли — не спешите радоваться. Удаление шелла без ротации секретов бессмысленно: злоумышленник уже прочитал .env, доступы к базе данных и ключи внешних интеграций.
⚠️ Подводный камень: смена пароля администратора ничего не даёт, если остались живыми ключи платёжного шлюза, токены CI/CD и секрет подписи сессий. Меняйте всё сразу и принудительно завершайте активные сессии — иначе чужой вход восстановится за минуты.
Теперь точки загрузки. Запретите исполнение PHP в каталогах для пользовательских файлов на уровне веб-сервера, храните вложения вне корня сайта и проверяйте двойные расширения вроде image.php.jpg. Контейнеры проще пересобрать из чистого образа, чем вычищать вручную.
И последнее: сверьте список выданных доступов с реальными задачами. Принцип минимальных прав здесь работает лучше любого сканера — мы разбирали механику на примере прав доступа ИИ-агента, и для сервисных ключей логика ровно та же.
Кто под ударом: оценка рисков для сайтов Рунета
Под ударом оказались десятки тысяч сайтов Рунета на PHP без свежих патчей: такую оценку потенциального охвата дали эксперты MWS AI, а Positive Technologies призвали пользователей немедленно установить обновления ядра языка.
Цифра «десятки тысяч» звучит солидно, но на практике это скорее нижняя граница, чем потолок. PHP держит на себе огромный пласт сайтов с готовыми системами управления контентом, и далеко не все владельцы вообще знают, какая версия интерпретатора крутится у них на сервере.
Причина проста: обновление ядра — это не кнопка «Обновить» в панели. Кто-то должен зайти по SSH, проверить совместимость расширений, прогнать регрессию и перезапустить сервисы. У команд из двух человек на это обычно нет ни времени, ни свободного окна в графике релизов.
⚠️ Подводный камень: «Мы обновились» почти никогда не означает «мы обновились везде». Забытые копии на тестовом контуре, старые образы в реестре контейнеров, замороженные проекты клиентов и сайты на общем хостинге, где версию интерпретатора задаёт провайдер, , вот где дыра живёт месяцами после официального патча.
Отдельная история , массовый хостинг. Администратор такого сайта физически не может выбрать версию PHP: за него это решает тарифный план и политика провайдера. Пока хостинг не раскатит обновление, клиент уязвим, и никакие локальные меры ему не помогут.
| Сегмент | Реальный уровень риска | Что делать первым делом |
|---|---|---|
| Собственный сервер, свой DevOps | Средний: патч доступен, всё зависит от скорости реакции | Обновить ядро, проверить логи на аномальные запросы |
| Общий хостинг | Высокий: версию задаёт провайдер | Написать в поддержку, забрать письменный ответ со сроками |
| Корпоративный портал на legacy-стеке | Критический: старые расширения не собираются на новом ядре | Временная блокировка обработки составных запросов на веб-сервере |
| Замороженные и тестовые копии | Критический: о них просто забыли | Инвентаризация, затем выключение или изоляция от сети |
💡 Инсайт: для небольшого проекта самый быстрый выигрыш — не ждать патча, а закрыть обработку составных запросов там, где вы не принимаете файлы. Это занимает минуты и не требует пересборки приложения. Логика ИИ-сканеров, которые ищут подобные бреши по шаблонам, разобрана в материале как работает ИИ-агент: токены, контекст и MCP на пальцах — полезно, чтобы понимать, по каким признакам вас находят.
Наш опыт показывает: при массовых уязвимостях в ядре языка страдают не самые крупные, а самые незаметные. Крупные компании хотя бы имеют регламент обновлений, а небольшой проект держится на человеке, который в отпуске.
Вывод простой: посчитайте не сайты, а копии своего кода в продакшене. Если ответ вас удивил, начинать нужно не с патча, а с инвентаризации.
Чек-лист: что сделать в первые 24 часа
Первые сутки решают исход: нужно закрыть внешний вектор на периметре, обновиться до собранного патча и проверить, не залили ли веб-шелл раньше. Патч лечит уязвимость, но не стирает следы компрометации — это две разные задачи.
| Окно | Действие | Критерий готовности |
|---|---|---|
| 0–2 ч | Инвентаризация: php -v на каждом хосте, внутри контейнеров и на сборках из CI |
Есть список «хост , ветка , владелец» |
| 2–4 ч | Сузить внешний вектор на nginx до обновления | Загрузка файлов разрешена только на явных эндпоинтах |
| 4–8 ч | Обновление из репозитория дистрибутива или официальной сборки, перезапуск php-fpm | php -v показывает нужную сборку, OPcache сброшен |
| 8–16 ч | Аудит логов и файловой системы на следы закрепления | Нет свежих файлов в каталогах загрузок, нет странных вызовов |
| 16–24 ч | Ротация секретов, урезание прав, план миграции старых веток | Доступы обновлены, отставшие ветки в плане |
Самая частая ошибка , «обновили пакет и забыли». На практике выяснилось: в контейнерной среде apt upgrade на хосте не меняет слой образа, а старый процесс php-fpm продолжает крутить уязвимый код в памяти.
Поэтому перезапуск php-fpm и сброс OPcache — не формальность, а обязательный шаг. Проверяйте сборку изнутри окружения, а не по статусу пакетного менеджера.
⚠️ Подводный камень: репозитории дистрибутивов и зеркала синхронизируются с задержкой, а часть веток PHP уже вне поддержки и патча для них не будет вовсе. Не ориентируйтесь на «пакет обновился без ошибок» , сверяйте реальные номера сборок на php.net, там же видно, какие ветки ещё получают исправления безопасности.
Отдельная строка расходов — зависимости. Фреймворки и CMS тянут свой рантайм, и иногда прод тянет устаревшую ветку через композер, а не через систему. Пробегитесь по манифестам и образам: расхождение версий между хостами — норма для легаси-парков, но не в день инцидента.
Заодно урежьте права пользователя, под которым работает php-fpm: логика та же, что и с доступами ИИ-агентов — лишние разрешения просто расширяют зону поражения (у нас был подробный разбор минимальных привилегий).
💡 Инсайт: заведите привычку хранить в заметках раннера прямую ссылку на страницу релизов php.net и checksum-суммы сборок. В момент паники вы не будете искать, какая версия считается закрытой, — вы просто откроете официальный список и сравните с выводом php -v.
И последнее: сутки — это не дедлайн, а старт. Проверку логов и файлов имеет смысл повторить через 48 и 72 часа, потому что закрепление в системе редко бывает одноразовым.
Часто задаваемые вопросы (FAQ)
Что именно взломали — мой сайт на WordPress или сам язык PHP?
Сам интерпретатор. Речь о двух критических уязвимостях в ядре языка — CVE-2026–109618 и CVE-2026–109619, обе по 9.2 балла из 10. Исследователи дали им имя PHP2Shell: сценарий разворачивается от「входной запрос」до「шелл на сервере」.
Ключевой момент — удалённое выполнение кода проходит без логина, без пароля и без единой ошибки в вашем коде. Ни свежий движок сайта, ни аккуратные плагины тут не защищают: дыра лежит ниже, на уровне разбора входящих данных.
Внеочередной релиз с исправлениями команда PHP выпустила 21 октября 2026 года — само по себе событие редкое, обычно патчи ждут планового окна. То есть чинили в режиме пожара.
Как за пять минут понять, под ударом ли мой сервер?
Начните с фактов, а не с догадок. На хосте — php -v, в панели управления — селектор версии, в контейнере — тег в Dockerfile и вывод docker inspect. Смотрите не на то, что «должно стоять», а на то, что реально исполняет запросы.
Классическая ловушка: на сервере три версии PHP, сайт крутится на самой старой, а обновляли вы вторую. Проверяйте каждое приложение отдельно, включая тестовые контуры, legacy-проекты и старый VPS, куда год никто не заходил.
И заодно уберите заголовок X-Powered-By — он бесплатно рассказывает сканерам, чем вы дышите.
Обновление страшно ставить в прод, как не уронить сайт?
Патч безопасности не откладывают на «после праздников», но и не заливают вслепую. Схема простая: сначала тестовый контур с копией боевых данных, затем прогон ключевых сценариев — вход в аккаунт, оплата, загрузка файлов, отправка форм.
Дальше канареечный выпуск: один узел за балансировщиком получает обновление, остальные работают на прежней сборке. Держите под рукой сохранённый предыдущий пакет или образ — откат должен занимать минуты, а не часы.
⚠️ Подводный камень: пока вы согласовываете окно, уязвимость уже описана публично. Каждая неделя промедления — это неделя, когда сканеры перебирают ваш диапазон адресов. Первые 30–60 минут после выпуска следите за ошибками 5xx и временем ответа, дальше будет спокойнее.
Можно ли прикрыться nginx и WAF и спокойно жить до обновления?
Частично. Компенсирующие меры реально снижают риск и покупают время: заблокируйте составные запросы с файлами (multipart) на всех адресах, где загрузка файлов не предусмотрена, ограничьте максимальный размер тела запроса, включите виртуальные правила в WAF.
Полезно и сузить последствия: изоляция пулов процессов, ограничение доступных функций, запрет исходящих соединений с сервера наружу. Тогда даже при пробитии атакующий останется в тесной комнате.
Но честно: это выигрыш времени, а не решение. Универсальное регулярное выражение, которое «отсечёт всё», обязательно обойдут — не сегодня, так через неделю.
Как понять, что сервер уже скомпрометировали?
Смотрите на три вещи. Первая — файлы: свежие скрипты в каталогах загрузок и кэша, внутри которых eval, base64_decode или длинные строки без пробелов. Вторая — процессы: оболочка, запущенная от пользователя веб-сервера, которого там быть не должно.
Третья — связи и закрепление: исходящие соединения на незнакомые адреса, правки в планировщике задач, новые ключи в ~/.ssh/authorized_keys, изменения в .htaccess, записи в логах о составных запросах на индексный файл.
Если хоть что-то совпало — изолируйте узел, снимите образ диска для разбора, смените пароли и ключи доступа к базе, пересоберите сервер из чистого образа. Искать malicious-файлы вручную по всей файловой системе смысла мало: заражённый сервер проще пересоздать.
💡 В сухом остатке: главное
Рынок технологий движется с бешеной скоростью. Не ведитесь на маркетинговый хайп: всегда тестируйте модели на реальных сценариях вашей команды и замеряйте финальную окупаемость.
Чек-лист для внедрения на практике:
- ✅ Уточните на официальном сайте PHP точные версии с исправлением для вашей ветки и обновите интерпретатор, а не только код проекта
- ✅ До обновления заблокируйте multipart-запросы на nginx или другом фронтенде, оставив исключения лишь для реальных точек загрузки файлов
- ✅ Проверьте логи доступа за последние сутки на подозрительные составные запросы, а также каталоги uploads на посторонние исполняемые файлы
- ✅ После патча смените секреты приложения, ключи API и пароли сервисных учётных записей, которые могли быть доступны с сервера
- ✅ Зафиксируйте в регламенте срок реакции на критический патч и владельца этой процедуры, иначе следующее обновление снова пройдёт мимо
Обсудить материал и поделиться своими бенчмарками можно в комментариях к блогу.







