PHP2Shell: CVE-2026-109618 и CVE-2026-109619 — что делать за первый час
21 октября 2026 опубликованы две критические уязвимости ядра PHP, CVE-2026-109618 и CVE-2026-109619 (CVSS v4.0 9.2): удалённое выполнение кода без входа в систему. Затронуты любые версии PHP, а не отдельные CMS. Исправления вышли в PHP 8.5.12, 8.4.27, 8.3.36 и 8.2.35; для 8.1 и старше официального патча нет. За первый час: найти весь PHP, обновить пакеты, перезапустить сервисы и включить временные меры там, где обновление невозможно.
PHP2Shell на 21 октября 2026: что известно и кого касается
Две уязвимости в ядре PHP, получившие общее имя PHP2Shell, опубликованы 21 октября 2026. Это CVE-2026-109618 и CVE-2026-109619, обе с оценкой CVSS v4.0 9.2 (Critical) по версии PHP. Атака идёт по сети, без аутентификации, на конфигурации по умолчанию. Исправленные релизы вышли 21 октября в 14:00 UTC: PHP 8.5.12, 8.4.27, 8.3.36 и 8.2.35. Раскрытие ускорили из-за утечки деталей 20 октября, поэтому патч, разборы и инструмент эксплуатации уже публичны.
Суть в двух словах. В первом случае нехватка памяти прерывает PHP в момент, когда внутренние данные запроса инициализированы лишь частично, а очистка запроса считает их валидными. Sansec описывает это как use-after-free в десериализаторе upload-progress. Следствия: утечка содержимого освобождённой памяти воркера (в заголовке Set-Cookie с PHPSESSID могут вернуться пароли, токены сессий, API-ключи, приватные ключи TLS, причём без вызова session_start()) и выполнение кода. Второй случай: состояние запроса переживает освобождение памяти, и следующий запрос на том же воркере использует устаревшее состояние. Sansec связывает это с обработчиком backtrace при фатальной ошибке и type confusion в OPcache. Итог тоже выполнение кода.
Запускает цепочку фатальная ошибка во время запроса, чаще всего исчерпание memory_limit. Все известные на сегодня триггеры используют запрос multipart/form-data: PHP разбирает его тело ещё до кода вашего приложения. Поэтому режим обслуживания в CMS, фильтры в плагинах и аккуратный код сайта ничего не меняют: запрос обрабатывается интерпретатором раньше. Это важное отличие от привычных историй про «дырявый плагин».
Статья горячая, картина меняется по часам. Что надо проверять заново в день, когда вы читаете текст: появились ли исправленные пакеты в вашем дистрибутиве (на момент проверки пакет для Debian 12 у одного из авторов обзоров был ещё в статусе «not yet»), вышли ли сборки Sury для 7.4 и 8.1 (подтверждения на 21 октября нет), и что пишут вендоры ваших панелей и продуктов. По 1С-Битрикс, ISPmanager, HestiaCP, cPanel, Plesk, mailcow, Zabbix, GLPI, FreePBX и Windows-сборкам PHP заявлений вендоров на момент проверки найти не удалось: на 21 октября не подтверждено, проверьте у вендора. По Patchstack, к 13:57 по телеметрии наблюдалось только зондирование без подтверждённых взломов, но Sansec ждёт массовой эксплуатации.
Уязвимый код присутствует с PHP 5.4.0 (2012 год). По разбору Wiz, все версии начиная с 5.4 затронуты хотя бы одной из двух уязвимостей, а NCSC Великобритании формулирует ещё шире: затронуты любые версии PHP. Уязвимы mod_php, PHP-FPM, php-cgi, FrankenPHP и LiteSpeed (по обзорам BleepingComputer и других изданий). Конфигурация по умолчанию тоже уязвима, то есть «мы ничего не трогали» не защита.
Раз ошибка в интерпретаторе, значит, уязвимо любое приложение, которое на нём работает. Sansec подтвердил выполнение кода без входа в систему на 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 и WHMCS. Это актуальные версии приложений, и именно в этом смысл: обновление плагинов, тем и самой CMS до последней версии от PHP2Shell не защищает. Нужно обновлять PHP.
Что обычно забывают при подсчёте. Корпоративный сайт и интернет-магазин помнят все. Хуже с внутренними сервисами, которые «никому не видны», но доступны из офисной сети или через проброшенный порт: система учёта техники, мониторинг, веб-интерфейс телефонии, почтовый клиент, phpMyAdmin на сервере баз данных. NCSC прямо просит включать в инвентаризацию весь PHP, в том числе встроенный в продукты и аппаратные решения. Если вы поддерживаете такие системы сами, подробнее об учёте активов у нас в материале как провести инвентаризацию IT-активов.
Для групп систем мы разобрали отдельные статьи серии: Debian и Ubuntu: репозитории Sury и PPA, CentOS 7, RHEL, Alma и Rocky: Remi и EOL, панели с несколькими версиями PHP, 1С-Битрикс и BitrixVM, WordPress, Joomla, OpenCart, Docker-образы, Nextcloud, mailcow, Zabbix, GLPI, FreePBX, Windows, IIS и FastCGI. Эта статья головная: здесь порядок действий на первый час и общая таблица.
Первый час: инвентаризация PHP на всех серверах (минуты 0–15)
Порядок такой, как мы строим его у клиентов: сначала узнать, где вообще есть PHP и какой версии, потом решать по каждому узлу. Нельзя начинать с обновления одного известного сайта: при пятнадцати узлах легко пропустить забытый тестовый сервер или контейнер. Для каждого сервера запишите: версию, способ запуска (mod_php, FPM, FrankenPHP, LiteSpeed), доступен ли он из интернета, где хранит секреты.
Первая команда показывает версии, установленные из пакетов. На Debian и Ubuntu:
dpkg -l | grep -E '^ii\s+php'
apt list '?installed ?name(^php[0-9.]+$)'На RHEL, Alma, Rocky и CentOS:
rpm -qa | grep -i '^php'Пакеты — только часть картины. Работающий процесс важнее установленного пакета, а на сервере бывает несколько версий сразу (панели хостинга ставят их рядом). Поэтому дополнительно смотрим, что реально запущено, и ищем бинарники вне пакетов:
ps -eo pid,user,args | grep -E 'php-fpm|apache2|httpd|lsphp|frankenphp|php-cgi' | grep -v grep
find / -xdev -type f \( -name 'php' -o -name 'php-fpm*' -o -name 'php-cgi' -o -name 'lsphp' \) 2>/dev/nullДля каждого найденного бинарника выполните его с ключом -v: у сервера может быть системный PHP одной версии, а сайт работает на версии из каталога панели или из каталога /opt. Контейнеры инвентаризируются отдельно, потому что внутри образа своя версия независимо от хоста:
docker ps --format '{{.Names}} {{.Image}}'
docker exec ИМЯ_КОНТЕЙНЕРА php -vОтдельная строка в списке — внешний периметр. Определите, какие из найденных узлов принимают HTTP из интернета, какие только из офисной сети, а какие закрыты. Порядок обновления вытекает из этого: сначала доступные из интернета, потом внутренние, но внутренние без проверки не оставляем. Если вы уже ведёте реестр в системе учёта, вынесите в него столбец «версия PHP»: для этого подходят и Snipe-IT в Docker, и регламент эксплуатации Snipe-IT.
Мини-кейс. Возьмём условную транспортную компанию «Северный Путь» на 28 рабочих мест. Ситуация (описываем подход, а не результат): публичный сайт с формой заявки на перевозку, внутренний портал диспетчеров, система учёта техники и мониторинг на отдельных виртуальных машинах, плюс забытая тестовая копия сайта. Мы бы не стали сразу обновлять сайт. Сначала запускаем одну и ту же инвентаризацию на всех машинах, фиксируем версию и способ запуска, отмечаем, какие узлы видны из интернета, и только потом выстраиваем порядок: публичный сайт и тестовая копия первыми, внутренние сервисы следом, система учёта и мониторинг после проверки их версии у вендора. Тестовую копию, если она не нужна, лучше отключить совсем: она увеличивает поверхность атаки и ничего не даёт.
Таблица: версия PHP, статус, что делать
Статус привязан к данным на 21 октября 2026. Исправленные версии upstream: 8.5.12, 8.4.27, 8.3.36 и 8.2.35. Для PHP 8.1 и старше официального исправления нет, потому что ветки закрыты. Patchstack отмечает, что минимальные бэкпорты для 7.4, 8.0 и 8.1 существуют, но только для сборки из исходников.
| Версия PHP | Статус на 21.10.2026 | Что делать |
|---|---|---|
| 8.5 (до 8.5.12) | Исправление есть: 8.5.12 | Обновить пакет, перезапустить сервисы, для 8.5 при временных мерах добавить fatal_error_backtraces=0 |
| 8.4 (до 8.4.27) | Исправление есть: 8.4.27 | Обновить пакет или пересобрать образ, перезапустить |
| 8.3 (до 8.3.36) | Исправление есть: 8.3.36 | Обновить пакет, перезапустить PHP-FPM или Apache |
| 8.2 (до 8.2.35) | Исправление есть: 8.2.35 | Обновить пакет, перезапустить |
| 8.1 | Исправления upstream нет, ветка закрыта | Перейти на поддерживаемую ветку; пока не перешли, пакет дистрибутива (Ubuntu 22.04 имеет свой php8.1) и временные меры |
| 8.0, 7.4 и старше | Исправления upstream нет | Срочно планировать миграцию; пакет дистрибутива, если он есть, иначе временные меры и изоляция |
| 5.x и 7.x на EOL-системах | Официальных обновлений не ожидается (вывод: EOL-системы их не получают) | Вынести из интернета, закрыть доступ, планировать замену |
Для систем с пакетами дистрибутива смотрите версию пакета, а не номер upstream. Ubuntu выпустила исправления (USN-8948-1 и USN-8948-2): 22.04 — php8.1 8.1.2-1ubuntu2.28; 24.04 — php8.3 8.3.6-0ubuntu0.24.04.13; 26.04 — php8.5 8.5.4-0ubuntu1.5; 26.10 — php8.5 8.5.9-0ubuntu2.1. Для 20.04 (php7.4 7.4.3-4ubuntu2.29+esm5), 18.04, 16.04 и 14.04 исправления доступны только по Ubuntu Pro (ESM): sudo pro fix CVE-2026-109618. Номер пакета с суффиксом ubuntu при этом ниже upstream, и это нормально: сравнивать нужно с версией из бюллетеня.
| Дистрибутив | Пакет с исправлением | Примечание |
|---|---|---|
| Debian 13 | 8.4.27-1~deb13u1 (DSA-6574-1) | Проверить через apt-cache policy |
| Debian 12 | 8.2.35-1~deb12u1 (DLA-4848-1) | На момент проверки у одного из обзоров пакет значился как «not yet» |
| Debian 11 | Исправления нет | LTS закончился 31 августа 2026 |
| Ubuntu 22.04 и 24.04 | php8.1 8.1.2-1ubuntu2.28, php8.3 8.3.6-0ubuntu0.24.04.13 | Обычное обновление |
| Ubuntu 20.04 и старше | Только через Ubuntu Pro (ESM) | sudo pro fix CVE-2026-109618 |
| RHEL, Alma, Rocky | Версии пакетов в источниках не названы | Смотреть dnf updateinfo, Remi 21 октября обновлений не выпускает |
| CentOS 7 | EOL | Вывод: официальных обновлений не ожидается |
Особый случай — Debian и Ubuntu с репозиторием Sury. Ондржей Сури заявил, что backport будет для каждой версии PHP в его репозитории (5.6–8.1) на всех поддерживаемых Debian и Ubuntu. Пакеты 8.2.35, 8.3.36, 8.4.27 и 8.5.12 уже вышли, для 7.4 и 8.1 подтверждения на момент проверки нет. Поэтому для старых веток проверяйте apt-cache policy php7.4-fpm и сравнивайте версию с changelog. Подробности — в статье обновление PHP из Sury и PPA на Debian и Ubuntu.
Обновление и перезапуск: минуты 15–40
Обновить PHP — это два действия: поставить пакет и перезапустить процессы. Вторую часть забывают чаще всего, и сервер остаётся уязвимым при «зелёных» логах обновления. Unattended-upgrades сам не перезапускает PHP-сервисы, а процессы, запущенные до обновления, продолжают выполнять старый код из памяти.
Debian и Ubuntu:
sudo apt update && sudo apt install --only-upgrade '?name(^php[0-9.]+$)'
sudo systemctl restart php8.3-fpmИмя сервиса зависит от ветки: php8.2-fpm, php8.3-fpm, php8.4-fpm. Для PHP-FPM подходит и reload, но мы берём restart, чтобы не гадать. Если сайт работает через mod_php, нужен именно systemctl restart apache2: reload и graceful недостаточны. LiteSpeed: обновить lsphpXY и выполнить pkill lsphp. FrankenPHP не лечится через apt или dnf, нужен новый релиз или образ. Для очередей Laravel выполните php artisan queue:restart; для Octane нужен перезапуск процесса, octane:reload недостаточно.
На RHEL-совместимых системах версии исправленных пакетов в источниках не названы, поэтому сначала смотрим, что предлагает дистрибутив:
dnf updateinfo list --security | grep php
rpm -q --changelog php-fpm | headЕсли ваша версия PHP — модуль из AppStream, при необходимости перейти на поддерживаемую ветку используется переключение модуля:
dnf module reset -y php && dnf module enable -y php:8.2 && dnf distro-sync -yПеред такой командой проверьте, что приложение запускается на выбранной ветке: переход с 7.4 на 8.2 ломает код с устаревшими функциями. Remi 21 октября обновлений для этого случая не выпускает и рекомендует пакеты дистрибутива или сборку из исходников; разбор этого сценария и работа с EOL — в статье PHP2Shell на CentOS 7, RHEL, Alma и Rocky.
Docker. Образ docker-library/php обновлён в репозитории, но на Docker Hub он появляется после отдельного запроса в official-images и сборки. Теги 8.5.12RC1 и 8.4.27RC1 исправления не содержат. Свои образы пересобирайте с ключом --pull и пересоздавайте контейнеры, иначе работает старый слой:
docker build --pull -t myapp:php-fixed .
docker run --rm php:8.4-fpm php -vЧто делать с панелями, где несколько версий PHP на одном сервере, в чём разница между системным PHP и версией сайта, разобрано в статье HestiaCP и ISPmanager с несколькими версиями PHP. Для 1С-Битрикс и BitrixVM смотрите отдельный материал по Битриксу: статус вендора на 21 октября не подтверждён, проверьте у вендора.
Если обновить нельзя прямо сейчас: временные меры
Меры из этого раздела частичные и обновление не заменяют. Gina Peter Banyard из команды PHP прямо пишет: одного отключения upload-progress мало, надёжных обходных путей по сути нет, единственное исправление — патч. Мы используем их, чтобы закрыть окно между «узнали» и «обновили», и не больше.
Первая мера: отключить session.upload_progress.enabled=0 в php.ini, в конфигурации пула FPM или сервера. Не через ini_set() и не через .user.ini. После этого нужно перезапустить все воркеры. Для PHP 8.5 дополнительно задаётся fatal_error_backtraces=0. Вторая мера по Sansec: memory_limit = -1. Риск понятен: один запрос может съесть всю память сервера, поэтому следите за RAM. В пулах FPM:
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[memory_limit] = -1Значения прописываются в каждом пуле через php_admin_*, чтобы приложение не могло их переопределить, затем reload. Patchstack для CVE-2026-109618 добавляет: post_max_size 8M при отсутствии загрузок и 32M при наличии, upload_max_filesize ниже, лимиты размера запроса, числа полей и multipart на веб-сервере или балансировщике, ограничения контейнеров и cgroup. Использовать RLIMIT_AS и RLIMIT_DATA не нужно. Для CVE-2026-109619: убрать настройки, которые создают диагностику до инициализации, и чинить доступные атакующему фатальные ошибки и таймауты.
Более жёсткая мера — запретить multipart/form-data на веб-сервере (вариант Sansec). Для nginx:
if ($http_content_type ~* "multipart/form-data") { return 403; }Для Apache используется условие по заголовку Content-Type с отказом:
RewriteCond %{HTTP:Content-Type} multipart/form-data [NC]
RewriteRule ^ - [F]Цена такой меры: ломаются загрузки файлов и часть форм, включая корзину и оформление заказа. Обязательно проверьте тестовый заказ и форму заявки, прежде чем оставить правило. Ещё более грубый вариант — пропускать только GET и HEAD (в nginx отвечать 503 на остальные методы) или остановить PHP-FPM и отдавать статическую страницу. Режимы обслуживания CMS (Magento, WordPress) не помогают, потому что PHP разбирает запрос раньше.
Cloudflare выкатил аварийные WAF-правила для всех тарифов, включая бесплатный. Это тоже лишь временная мера, и работает она только если ваш сервер принимает трафик исключительно от Cloudflare. Sansec Shield выполнение кода и утечку не закрывает. Не ставьте «плагины-заплатки» и сниппеты с форумов: Patchstack отдельно предупреждает об этом. По CMS у нас есть материал WordPress, Joomla и OpenCart под PHP2Shell.
Проверка, признаки взлома и чек-лист
После обновления проверяем не пакет, а процессы. Первая проверка показывает, что запущенные процессы не используют удалённые библиотеки (пустой вывод означает, что всё в порядке):
sudo grep -lE ' /(usr|lib|opt).*\(deleted\)$' /proc/[0-9]*/maps
sudo needrestart -b -r lВторая проверка: версия в changelog. На Ubuntu это обычно видно по номеру CVE, на Debian и Sury changelog может быть без номеров, тогда сравниваем версию с бюллетенем:
zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php8.3-fpm/changelog.Debian.gzПризнаки эксплуатации по Patchstack (они не доказывают ни взлом, ни его отсутствие): необычные multipart-запросы с последующей ошибкой memory_limit или повторяющимися HTTP 500, аномально большие или битые куки PHPSESSID, необъяснимые перезапуски воркеров PHP. Как искать это в журналах nginx и Apache, написано в статье признаки взлома PHP2Shell в логах nginx и Apache.
При признаках действуем так. Обновляем PHP и считаем сервер возможно скомпрометированным. Составляем перечень секретов, которые на нём хранились: ключи API, пароли баз данных, ключи TLS, токены. Этот перечень мы передаём владельцу на ротацию; сами пароли живых учётных записей мы не меняем, решение о смене принимает владелец. Для утечки через память это принципиально: ключи могли уйти до обновления, и патч сам по себе их не отзывает.
Чек-лист на первый час, который мы используем как основу:
Чек-лист на первый час (ядро закрыто, когда PHP обновлён до исправленной версии или пакета дистрибутива и перезапущены все процессы, включая mod_php, LiteSpeed, FrankenPHP и очереди; иначе должны стоять временные меры с записанным сроком):
- инвентаризация выполнена на всех серверах, включая контейнеры и тестовые копии;
- для каждого узла записаны версия, способ запуска и доступность из интернета;
- выбран порядок: сначала публичные узлы, затем внутренние;
- пакеты обновлены, процессы перезапущены (restart, а не graceful для mod_php);
- проверка needrestart и /proc/PID/maps пройдена;
- для узлов без исправления включены session.upload_progress.enabled=0 и ограничения запросов;
- проверены форма заявки, загрузка файла и оформление заказа;
- журналы просмотрены на признаки из Patchstack;
- при подозрении составлен список секретов для ротации и передан владельцу;
- узлы на EOL-системах вынесены в план замены.
Что делать после первого часа
Первый час закрывает самые опасные узлы, но не работу целиком. В ближайшие дни: повторить инвентаризацию через сутки (за это время вендоры публикуют обновления продуктов, и картина по Bitrix, панелям и веб-интерфейсам меняется), проверить репозитории для старых веток и вернуть к обновлению те узлы, где ждали пакет. Статус по Zabbix, GLPI и FreePBX мы разбираем отдельно: PHP-веб-интерфейсы Zabbix, GLPI и FreePBX; для Windows-серверов с IIS — PHP и FastCGI на Windows. Если у вас учёт техники и заявок в GLPI, посмотрите и GLPI: учёт техники и заявки пользователей.
Системные выводы. Любой сервер на PHP 8.1 и старше стоит в плане миграции: такие ветки не получили исправления upstream и после следующей громкой уязвимости история повторится. Реестр версий PHP должен жить постоянно, а не собираться в день аварии. Внешние сервисы должны быть закрыты по IP либо стоять за единой точкой входа, чтобы быстрые меры включались в одном месте.
Если у вас нет времени или специалиста, мы берём это на себя: инвентаризация, обновление, временные меры, проверка и отчёт владельцу. Описание формата работ — на странице обслуживание серверов и сайтов.
Частые вопросы
Что такое PHP2Shell и чем он опасен?
PHP2Shell — общее имя двух уязвимостей ядра PHP, CVE-2026-109618 и CVE-2026-109619, с оценкой CVSS v4.0 9.2. Они позволяют без входа в систему вызвать утечку памяти воркера и выполнение кода. Триггер — фатальная ошибка, обычно исчерпание memory_limit, при запросе multipart/form-data. Конфигурация по умолчанию уязвима.
Защитит ли обновление WordPress, Битрикса или плагинов?
Нет, обновление приложения не защищает. Ошибка находится в интерпретаторе PHP, который разбирает запрос multipart/form-data раньше кода сайта. Sansec подтвердил выполнение кода без логина на актуальных версиях WordPress, Joomla, Drupal, Magento и других. Нужно обновить сам PHP и перезапустить процессы, режим обслуживания CMS тоже не помогает.
Какие версии PHP исправлены?
Upstream исправлены PHP 8.5.12, 8.4.27, 8.3.36 и 8.2.35, релиз 21 октября 2026. Для PHP 8.1 и старше официального исправления нет, ветки закрыты. Дистрибутивы выпускают свои пакеты: Ubuntu — USN-8948-1 и USN-8948-2, Debian 12 и 13 — DLA-4848-1 и DSA-6574-1. Сравнивайте версию пакета с бюллетенем.
Что делать, если обновить PHP сейчас нельзя?
Включите временные меры, понимая, что они частичные. Отключите session.upload_progress.enabled в конфигурации (не через ini_set), для 8.5 добавьте fatal_error_backtraces=0, задайте лимиты запросов или заблокируйте multipart/form-data на веб-сервере, предварительно проверив формы. Если система некритична и мер мало, рассмотрите её отключение.
Как понять, что сервер уже взломали?
Достоверного признака нет. Patchstack называет косвенные: необычные multipart-запросы с последующей ошибкой memory_limit или повторяющимися HTTP 500, аномально большие или битые куки PHPSESSID, необъяснимые перезапуски воркеров PHP. При подозрении обновите PHP, считайте сервер возможно скомпрометированным и передайте владельцу список секретов для ротации.
Источники
- Sansec — PHP2Shell — Разбор механизма, список подтверждённых приложений, временные меры: https://sansec.io/research/php2shell
- NCSC UK — Critical security issue affecting PHP — Рекомендации по инвентаризации, обновлению и отключению систем: https://www.ncsc.gov.uk/news/critical-security-issue-affecting-php
- Patchstack — PHP major vulnerability alert — Нейтральное описание уязвимостей, признаки, меры по лимитам: https://patchstack.com/articles/php-major-vulnerability-alert-10-2026/
- Ubuntu — PHP2Shell fixes available — USN-8948-1, USN-8948-2, версии пакетов, Ubuntu Pro: https://ubuntu.com/blog/php2shell-vulnerability-fixes-available
- JFrog Research — PHP2Shell — Обзор CVE-2026-109618 и CVE-2026-109619: https://research.jfrog.com/post/php2shell-all-you-need-to-know-about-cve-2026-109618-and-cve-2026-109619/
- BleepingComputer — PHP warns admins of two critical flaws — Сроки выпуска патчей и затронутые среды выполнения: https://www.bleepingcomputer.com/news/security/php-warns-admins-of-two-critical-flaws-emergency-patches-coming-tomorrow/
- GitHub Security Advisories php/php-src — GHSA-w8hw-w9fx-j79w (CVE-2026-109618) и GHSA-6wmf-4rv5-p3rp (CVE-2026-109619): https://github.com/NCSC-NL/php2shell


