Новым пользователямБесплатные тарифы DNS и CDN для каждого нового аккаунта.Создать аккаунт

PHP2Shell (CVE-2026-109618/109619): как мы закрыли уязвимость виртуальным патчем на границе сети

Два критических бюллетеня PHP позволяют выполнить код удалённо без аутентификации через аварийный выход при нехватке памяти и устаревшее глобальное состояние. Рассказываем, как работают уязвимости, что Yeap WAF блокирует на границе с первого дня и что вам всё ещё нужно исправить на своём источнике.

21 октября 2026 года проект PHP опубликовал сразу два бюллетеня безопасности уровня Critical: GHSA-w8hw-w9fx-j79w (CVE-2026-109618) и GHSA-6wmf-4rv5-p3rp (CVE-2026-109619), обе с оценкой 9.2 по CVSS v4. Каждая из них позволяет удалённо выполнить код без аутентификации. Эту пару уязвимостей назвали PHP2Shell.

Затронуты все четыре поддерживаемые ветки (PHP 8.2, 8.3, 8.4 и 8.5), а команда PHP подтвердила, что mod_php эксплуатируем при настройках по умолчанию. Для любого сайта на WordPress, Laravel или другом PHP-приложении одного анонимного POST-запроса может оказаться достаточно, чтобы захватить сервер.

В тот же день, когда вышли бюллетени, мы развернули виртуальный патч против публично известного вектора атаки на всех граничных узлах Yeap CDN. В этой статье мы расскажем, как устроены уязвимости, что блокируют наши правила, чего они заблокировать не могут и что вам всё ещё нужно сделать на своём источнике.

Цепочки атаки PHP2Shell: аварийный выход при нехватке памяти, после которого наполовину инициализированная память считается доверенной, и устаревшее глобальное состояние, повторно используемое между запросами как use-after-free
Обе ошибки находятся в жизненном цикле запроса движка Zend, а не в отдельном расширении.

Что это за уязвимости

CVE-2026-109618: повреждение памяти при аварийном выходе по OOM

Когда PHP исчерпывает память, он вызывает longjmp(), чтобы прервать текущий запрос. В некоторых местах память запроса становится доступной ещё до полной инициализации. Если выделение памяти завершится неудачей именно в этот момент, досрочный выход оставит после себя некорректную память, а завершение запроса позже прочитает её и выполнит ветвление по её содержимому.

Злоумышленник может надёжно вызвать OOM в рамках обычных лимитов PHP с помощью некорректного запроса multipart/form-data: без пригодной длины содержимого, с частью, содержащей огромное число заголовков, с пустыми полями файлов, которые обходят max_file_uploads, или с глубоко вложенными именами полей. Официальное исправление полностью убирает longjmp() при OOM. Теперь PHP корректно завершает работу в следующей безопасной точке и немедленно вызывает _exit(), если потребление памяти превышает более высокий порог.

CVE-2026-109619: устаревшее глобальное состояние между запросами

Глобальное состояние, принадлежащее запросу (состояние ошибок, сессий, объектов и расширений), может сохраняться в рабочем процессе после того, как память этого запроса уже освобождена. Некоторый код читает это состояние до того, как следующий запрос будет корректно инициализирован, и в результате переходит по указателю в освобождённую память: это use-after-free.

  • Производители (запросы, оставляющие после себя устаревшее состояние): фатальные ошибки, превышение времени выполнения, неудачный require, нехватка памяти, а также fatal_error_backtraces в PHP 8.5.
  • Потребители (запросы, которые его читают): диагностика INI, применяемая до запуска запроса, и обработка session.upload_progress, которая включена по умолчанию.

Когда производитель и потребитель попадают на один и тот же рабочий процесс, злоумышленник может сформировать кучу так, чтобы превратить use-after-free в выполнение кода. Команда PHP подтвердила работоспособность пути через upload progress как для mod_php, так и для PHP-FPM.

Затронутые версии

ВеткаУязвимыИсправлено в
PHP 8.5< 8.5.128.5.12
PHP 8.4< 8.4.278.4.27
PHP 8.3< 8.3.368.3.36
PHP 8.2< 8.2.358.2.35

Эксплуатируемость mod_php подтверждена. По результатам анализа исходного кода, FPM, FrankenPHP и LSAPI также уязвимы. Версии с истёкшим сроком поддержки не получат официального патча, поэтому защита перед ними становится ещё важнее.

Что может заблокировать WAF

Публично известный эксплойт по сути представляет собой один неаутентифицированный multipart POST-запрос. Он содержит поле PHP_SESSION_UPLOAD_PROGRESS и загрузку файла, чтобы попасть в обработчик upload progress, а также большое количество полей формы, которые распыляют кучу и занимают освобождённую память. Такая форма запроса видна на уровне HTTP, поэтому его можно остановить ещё до того, как он дойдёт до PHP.

Мы добавили в движок OWASP CRS в Yeap WAF набор самостоятельных правил виртуального патча. Они распознают сочетание триггера upload progress и распыления кучи, на котором держится эксплойт, и возвращают 403 ещё до того, как PHP разберёт запрос.

  • Они блокируют самостоятельно. Правила не зависят от оценки аномалий, поэтому уровень паранойи сайта и порог оценки их не ослабляют.
  • Они смотрят на поведение, а не на фиксированную сигнатуру. Переименование полей или изменение формы нагрузки не помогает их обойти.
  • Они не мешают настоящим загрузкам. Легитимные формы загрузки, в том числе с индикатором прогресса, продолжают работать.
  • Они работают на границе сети. На источнике ничего не нужно устанавливать и не нужно менять ни одной строки конфигурации.
Уровни защиты на границе Yeap CDN: терминирование TLS и скрытый источник, виртуальный патч PHP2Shell, управляемые правила OWASP CRS, ограничение частоты запросов и списки блокировки
Попытки эксплуатации останавливаются на границе. Обычный трафик проходит дальше к вашему источнику.

От бюллетеня до защиты на каждом узле

Хронология: бюллетени опубликованы 21 октября, правила проверены и включены на всех граничных узлах в 23:34 того же дня, 22 октября поставлены в составе пакета OWASP CRS v4.30.0

Перед выпуском мы проверили правила на вариантах атакующего трафика и на нескольких видах легитимных загрузок: все варианты атаки были заблокированы, а все легитимные загрузки прошли. Затем правила были скомпилированы в наш пакет CRS в виде плагина и включены на всех граничных узлах в 23:34 (UTC+8) 21 октября. Ранним утром 22 октября мы обновили весь пакет до OWASP CRS v4.30.0, и виртуальный патч вошёл в его состав.

Такая скорость обеспечивается конвейером обновлений Yeap WAF. Новый пакет компилируется и проверяется в фоновом режиме, затем попадает на канареечные узлы, где мы следим за состоянием загрузки и долей блокировок. Повсеместно развёртывается только исправный пакет. Граничные узлы заменяют правила атомарно: старые правила продолжают работать, пока новые не будут готовы, поэтому разрывов в защите не бывает, а откатиться к последней рабочей версии можно одним щелчком.

WAF — это не патч: что вам всё ещё нужно сделать

Скажем прямо: WAF может остановить только ту часть атаки, которая передаётся в теле HTTP-запроса. У CVE-2026-109619 есть также производители и потребители, которые вообще не связаны с multipart, например fatal_error_backtraces в PHP 8.5 или предупреждения INI при запуске, а освобождение и использование памяти могут быть разнесены по двум запросам, каждый из которых выглядит совершенно обычно. Это можно исправить только внутри движка PHP. Кроме того, варианты, основанные на времени, например медленные POST-запросы, контентный WAF увидеть не может.

Рассматривайте правила на границе как первую линию обороны, которая даёт вам время, и как можно скорее выполните следующие шаги:

  1. Обновите PHP до 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 или новее. Согласно бюллетеням, это единственное полное исправление.
  2. Ужесточите php.ini до обновления, затем перезапустите все рабочие процессы PHP:
    ; Отключите, если вы не используете индикаторы прогресса загрузки
    ; (бюллетень рекомендует держать параметр выключенным и после установки патча)
    session.upload_progress.enabled = 0
    
    ; PHP 8.5: устраняет подтверждённый источник RCE
    fatal_error_backtraces = 0
    
    ; Консервативные ограничения на тело запроса и входные данные
    post_max_size = 8M
    max_input_vars = 1000
    max_input_nesting_level = 16
    
  3. Для PHP-FPM рассмотрите pm.max_requests = 1. Каждый рабочий процесс перезапускается после одного запроса, что разрывает повторное использование состояния между запросами. Это снижает производительность, поэтому используйте эту меру как краткосрочную экстренную.
  4. Отклоняйте multipart там, где загрузки не нужны. В консоли Yeap CDN перейдите в раздел Межсетевой экран → Пользовательские правила и создайте правило блокировки из условий «метод — POST», «заголовок запроса Content-Type содержит multipart/form-data» и ваших путей, разрешив только те конечные точки, которые действительно принимают загрузки.
  5. Ограничьте частоту POST-запросов, чтобы замедлить сканирование и повторные зондирования.

Чтобы проверить своё окружение:

php -v
php -i | grep -E "session.upload_progress.enabled|fatal_error_backtraces"

CLI и веб-сервер могут загружать разные файлы php.ini. Самый надёжный способ проверки — временная страница с phpinfo() на самом сайте. Удалите её сразу после просмотра.

Защитите свои PHP-сайты с Yeap CDN и WAF

PHP2Shell не будет последней критической уязвимостью PHP. Между публикацией бюллетеня и установкой патча на каждый сервер всегда есть окно, а злоумышленники обычно начинают сканирование в течение нескольких часов. Разместите сайт за Yeap CDN, и мы будем удерживать это окно за вас на границе сети:

  • Управляемые правила, которые всегда актуальны: полный набор правил OWASP CRS v4 в 14 категориях, включая SQL-инъекции, XSS, удалённое выполнение команд, PHP-инъекции и веб-шеллы. Вы включаете и выключаете категории вместо настройки отдельных правил, а новые версии из upstream автоматически собираются, проходят канареечную проверку и развёртываются.
  • Виртуальные патчи для критических уязвимостей: как и в этот раз, целевые правила включаются на границе в день выхода бюллетеня без каких-либо изменений на вашем источнике.
  • Скрытый источник: злоумышленники могут добраться только до граничных узлов. Разрешите на источнике только трафик CDN, и поверхность прямой атаки сократится практически до нуля.
  • Пользовательские правила и ограничение частоты запросов: комбинируйте IP, страну, путь, заголовок и метод, чтобы блокировать трафик, отправлять проверку или ограничивать частоту.
  • Бесплатный HTTPS и глобальное ускорение: сертификаты выпускаются и продлеваются автоматически, а граничные узлы в нескольких регионах отвечают вашим посетителям из ближайшей точки.

Подключение занимает несколько минут: добавьте домен, направьте его DNS-запись на CNAME, который выдаст Yeap CDN, и включите защиту в настройках WAF домена. Пошаговое руководство см. в статье Подключите сайт к Yeap CDN с бесплатным HTTPS за 10 минут, а подробности о продуктах — на страницах Yeap CDN и Безопасность.

Мы включаем движок управляемых правил OWASP CRS поэтапно, домен за доменом. Если вы хотите получить этот виртуальный патч PHP2Shell для своего сайта прямо сейчас, создайте обращение в службу поддержки в консоли, и мы включим его для вашего домена.

Ссылки

Создавайте проекты на Yeap Cloud

Бесплатные тарифы DNS и CDN для каждого нового аккаунта.

Зарегистрироваться бесплатно

Читать дальше

Новые пограничные узлы Yeap CDN: почему мы выбрали Rust

Мы заменили пограничный компонент CDN собственной реализацией на Rust и Pingora. Что это даёт вашему сайту: более быстрое подключение, применение конфигурации за секунды, усиленную изоляцию и безопасность.

Начало работы с Yeap LLM API через OpenAI SDK

Yeap LLM API совместим с OpenAI: используйте привычный SDK, указав https://llm.yeap.cloud/v1 в base_url. Создание ключа, примеры на Python и Node.js, потоковые ответы, эмбеддинги, квоты и ограничения моделей и IP для ключей.

Практическое руководство по очистке кэша: от ключей до отдельных вариантов

Очистили кэш, но по-прежнему получаете попадания? Чаще всего причина в ключе кэша. Как Yeap CDN формирует ключи, как работают режимы строки запроса и что именно удаляет очистка по URL с параметрами и без них.