PHP2Shell: как проверить PHP-FPM после выхода исправлений критических уязвимостей
21 октября 2026 года команда PHP выпустила обновления безопасности для четырёх веток языка: 8.5.12, 8.4.27, 8.3.36 и 8.2.35. Релизы исправляют две критические уязвимости - CVE-2026-109618 и CVE-2026-109619, которые позволяют добиться удалённого выполнения кода без авторизации.
Исследователи Wiz назвали исследование PHP2Shell. В демонстрации атак использовались WordPress, Drupal и Joomla, но уязвимости находятся в PHP, поэтому привязки к конкретной CMS нет.
Для администратора есть практическая проблема: обновлённый PHP в командной строке ещё не означает, что сайт работает на исправленной версии. На одном сервере могут одновременно находиться несколько сборок интерпретатора, а PHP-FPM запускаться из отдельного каталога или управляться панелью хостинга.
Что обнаружили исследователи
CVE-2026-109618 связана с обработкой сериализованных данных в механизме отслеживания загрузок файлов - upload progress. При нехватке памяти PHP может прервать выполнение в момент, когда внутренние данные запроса ещё не полностью инициализированы. При очистке запроса движок использует некорректное состояние. Wiz продемонстрировала удалённое выполнение кода до авторизации, а также отдельный сценарий раскрытия памяти PHP-процесса.
CVE-2026-109619 затрагивает другое состояние интерпретатора. Данные, принадлежащие завершившемуся запросу, могут сохраняться после освобождения соответствующей памяти. Если тот же рабочий процесс PHP-FPM получает следующий запрос до сброса устаревшего состояния, он может обратиться к уже недействительным данным.
В исходном коде PHP исправления связаны с обработкой аварийного выхода из выполнения - bailout. Обе уязвимости относятся к внутренним механизмам движка, поэтому обновление CMS само по себе их не устраняет.
Исправленные версии PHP
Ветка | Версия с исправлениями |
|---|---|
PHP 8.5 | 8.5.12 |
PHP 8.4 | 8.4.27 |
PHP 8.3 | 8.3.36 |
PHP 8.2 | 8.2.35 |
Для PHP 8.1 и более старых веток нужно уточнять наличие исправления у поставщика ОС или хостинга: эти версии больше не получают обычные обновления от проекта PHP, хотя некоторые поставщики выпускают собственные исправленные пакеты.
Проверяем PHP-FPM на сервере
Найти службу
В Linux с systemd выполните:
//bash
systemctl list-units --type=service --all | grep -Ei 'php.*fpm|fpm.*php'В списке могут оказаться службы для разных веток PHP. Выберите ту, которая относится к нужному сайту, и посмотрите её параметры:
//bash
systemctl cat ИМЯ_СЛУЖБЫВ строке ExecStart указан исполняемый файл, запускаемый службой. Его путь может отличаться от стандартного /usr/sbin/php-fpm, особенно если PHP установлен через панель управления.
Сопоставить службу с сайтом
Если сайт работает через Nginx, найдите директиву fastcgi_pass в его конфигурации:
//bash
sudo nginx -T 2>&1 | grep -nE 'server_name|fastcgi_pass'По имени домена определите соответствующий блок server и адрес PHP-FPM. Это может быть Unix-сокет вроде /run/php/php8.4-fpm.sock или сетевой адрес.
Теперь можно сопоставить сокет с настройкой listen в конфигурации пула PHP-FPM. Путь к конфигурации зависит от способа установки PHP; его можно уточнить через параметры запуска службы и конфигурацию установленного пакета.
Проверить версию запускаемого PHP
Когда путь к бинарному файлу известен, выполните:
//bash
/ПУТЬ/К/php-fpm -vПодставьте реальный путь из ExecStart. Команда покажет версию этого бинарного файла, но окончательную проверку нужно сделать через HTTP: именно так выясняется, какая версия отвечает на запросы сайта.
Проверить версию через HTTP
Временно создайте в корневом каталоге сайта файл с непредсказуемым именем, например runtime-check-a7f3.php, со следующим содержимым:
//php
<?php
header('Content-Type: text/plain; charset=utf-8');
echo 'PHP_VERSION=', PHP_VERSION, "\n";
echo 'PHP_SAPI=', PHP_SAPI, "\n";Откройте файл через HTTPS по адресу сайта. При обработке через PHP-FPM значение PHP_SAPI обычно будет fpm-fcgi. PHP_VERSION покажет версию интерпретатора, который обработал этот запрос.
После проверки немедленно удалите файл. Не используйте для этой задачи публичный phpinfo(): он раскрывает значительно больше сведений об окружении.
Если через HTTP отображается старая версия, проверьте, какой обработчик подключён к домену и обновлён ли именно его пакет. После установки обновления повторите запрос. Для завершённой проверки результат должен соответствовать исправленному релизу или подтверждённой поставщиком сборке с backport исправления.
Если обновления ещё нет
Разработчики PHP прямо указывают: полной временной защиты от этих уязвимостей нет, безопасное решение - установить исправление. Отключение session.upload_progress.enabled, фильтрация запросов через WAF или ограничение загрузки файлов не заменяют патч и не гарантируют защиту от обоих сценариев.
Если пакет пока не появился в панели управления, проверьте уведомления поставщика и запросите срок выпуска исправленной сборки для используемой ветки. Не подменяйте PHP-FPM случайным бинарным файлом из стороннего источника: такая замена может нарушить совместимость расширений и конфигурации.
Для старых веток отдельно уточните у поставщика, выпущен ли backport. Сам номер версии иногда остаётся прежним при переносе исправления в пакет дистрибутива, поэтому ориентироваться нужно на подтверждённый статус обновления.
Проверка PHP2Shell заканчивается не после установки пакета и не после команды php -v. Критерий простой: веб-запрос обслуживается исправленной сборкой PHP, а используемый сайтом обработчик действительно обновлён.
Комментарии
За напоминание про рестарт самого демона FPM после апдейта отдельное спасибо. Сегодня с утра обновили пакеты на двух виртуалках, глянули php -v в консоли и сидели довольные, пока не проверили версию через phpinfo(), а там в памяти до сих пор крутились старые воркеры 8.3.35. А вот с отключением register_shutdown_function при жестком OOM новость неприятная - у нас как раз на шатдаунах висит снятие блокировок в Redis и отправка алертов в Sentry. Придется пересматривать логику.
Чтобы оставить комментарий, войдите в аккаунт.