21 октября 2026 года в 14:00 UTC команда PHP опубликовала исправления двух критических уязвимостей, CVE-2026-109618 и CVE-2026-109619, известных как PHP2Shell. Мы начали примерно через час. Около 17:00 UTC были закрыты все серверы, которые мы обслуживаем: 88 проектов на нашей поддержке. Здесь рассказываем, как мы это сделали и что нас тормозило, потому что те же препятствия стоят на многих серверах, которые ещё никто не обновил.
Если вам нужно только понять, затронут ли ваш сайт и что спросить у хостинга, прочитайте нашу первую статью о PHP2Shell.
Первый час: закрыть путь атаки везде
Установка исправленного PHP на десятки серверов требует времени. Отключить уязвимый механизм можно за минуты. Поэтому сначала мы сделали это, на каждом сервере, и только потом стали что-то собирать.
В бюллетене PHP session.upload_progress.enabled назван одним из путей для CVE-2026-109619. Мы выключили его в основной конфигурации PHP для каждой версии PHP на каждом сервере и перезапустили воркеры PHP. В бюллетене предупреждают, что .user.ini и ini_set() не в счёт, поэтому мы правили файлы на уровне сервера. На PHP 8.5 мы также отключили fatal_error_backtraces, как советует бюллетень.
Так закрылся только подтверждённый путь CVE-2026-109619 через сессии. Для CVE-2026-109618 нужно было само обновление.
Три вида серверов, три способа обновить
Наши 88 проектов работают на разных конфигурациях, и для каждой понадобился свой путь.
Серверы с PHP из пакетов дистрибутива. Здесь исправление приходит от сопровождающих пакетов. Ubuntu выпустила исправленные пакеты в день релиза. Одна ловушка для тех, кто проверяет такой сервер: после обновления php -v может по-прежнему показывать старый номер, например 8.3.6, потому что Ubuntu исправляет пакет, а версию оставляет. Проверяйте версию пакета.
Серверы под панелью управления хостингом. На нескольких серверах стоит aaPanel, а она собирает свой PHP. В день релиза обновлённого PHP в панели не было. Ждать панель значило оставить эти серверы открытыми неизвестно на сколько, поэтому мы собрали PHP сами.
Docker-контейнеры. Часть проектов запускает PHP в контейнерах, собранных из готовых образов. Пересобирать и заново выкатывать целое приложение посреди инцидента рискованно. Вместо этого мы обновили PHP внутри работающих контейнеров, а полноценную пересборку образов запланировали на потом.
Собрать PHP самим и не сломать панель
Сборка PHP в панели отличается от стандартной. Если собрать PHP с параметрами по умолчанию и просто подложить, пропадут расширения, а панель перестанет узнавать собственный PHP.
Мы написали один скрипт сборки и запускали его для каждой версии PHP на каждом сервере с панелью:
- он читает точные параметры configure из уже установленного PHP, чтобы у новой сборки были те же расширения и пути;
- собирает исправленную версию из официальных исходников;
- проверяет, с какими библиотеками OpenSSL и curl слинкован новый бинарник. Панель линкует некоторые версии PHP со своими более старыми копиями этих библиотек, и скрипт следит, чтобы новая сборка использовала те же;
- сохраняет копию старых бинарников, ставит новые и перезапускает PHP;
- если PHP не поднялся, сам возвращает старые бинарники.
Со скриптом мы обновляли одну версию PHP на одном сервере, проверяли сайты и повторяли на следующем, без ручной работы каждый раз.
PHP 7.4, 8.0 и 8.1: официального релиза нет
Команда PHP больше не выпускает релизы этих веток. Для PHP2Shell она опубликовала только изменения исходного кода для 7.4, 8.0 и 8.1. Часть наших проектов всё ещё работает на этих версиях.
Для них мы наложили исправления команды PHP на последний релиз каждой ветки и собрали тем же скриптом. Опубликованные изменения затрагивают ещё файлы версий и журналы изменений, которые на релиз чисто не накладываются, поэтому мы взяли только изменения кода.
На одном сервере работал PHP 7.4 из пакетов Ubuntu 20.04. Для этого выпуска Ubuntu исправление приходит только через расширенную поддержку безопасности Ubuntu (ESM), а на том сервере её нет. Мы собрали PHP 7.4 с теми же флагами сборки, что использует Ubuntu, и заменили только бинарник PHP-FPM, оставив оригинал рядом. Следующее обновление пакета перезапишет нашу сборку, и мы отметили это в записях по проекту.
Контейнеры: обновили сейчас, пересоберём позже
Для каждого контейнера мы собирали исправленный PHP в чистой копии официального образа на той же операционной системе, а потом копировали в работающий контейнер только бинарники PHP и нужные ему расширения, сохранив внутри копию оригиналов.
Одному образу на Alpine понадобились те же дополнительные патчи исходников, что применяет официальный Docker-образ PHP, иначе сборка падала на более новом компиляторе.
Подвох этого подхода: исправление живёт только до тех пор, пока кто-нибудь не пересоздаст контейнер из старого образа. Если ваша команда обновляла контейнеры так же, поставьте пересборку образов в план, иначе уязвимость вернётся со следующим деплоем.
После обновления: логи
Когда на всех серверах заработал исправленный PHP, мы прошлись по логам веб-сервера и PHP на всех серверах в поисках запросов, похожих на то, как можно использовать эти уязвимости. Признаков эксплуатации не нашли.
Что мы сказали бы владельцу сайта после того вечера
- Скорость вашего хостинга и есть ваша скорость. Если PHP у вас из панели или от провайдера, который её ждёт, сайт остаётся открытым, пока они не сделают своё. Спросите у них сегодня, какая у вас версия.
- Старый PHP всё ещё обходится дорого. PHP 8.1 и старее на этот раз получили исправления только в исходном коде. В следующий раз может не быть и их. Поддержка PHP 8.2 заканчивается 31 декабря 2026 года.
- У контейнеров и своих сборок должен быть владелец. Сами они не обновляются. Кто-то должен знать, что они есть и как их пересобрать.
Наш автоматический мониторинг работает круглосуточно, а инженеры реагируют, когда он фиксирует инцидент.
Если вам нужно то же самое на ваших серверах
Проверим версию PHP и обновим её в течение одного рабочего дня. Напишите нам.
Для постоянной поддержки смотрите поддержку серверов, поддержку сайтов и DevOps. Если ваше мобильное приложение работает с бэкендом на PHP, этому бэкенду нужно то же обновление; это мы закрываем в рамках поддержки мобильных приложений. Чтобы узнать, не открыто ли что-то ещё, закажите тест на проникновение.
Источники
- Объявление команды PHP и временные меры: https://www.php.net/archive/2026.php
- Бюллетени безопасности: https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w и https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp
- Ubuntu: https://ubuntu.com/blog/php2shell-vulnerability-fixes-available