Сколько серверов отделяет от утечки ваших секретов всего одна некорректная загрузка файла?
PHP2Shell — это пара критических уязвимостей, которые позволяют неаутентифицированным злоумышленникам удаленно выполнять код на PHP-установках, обслуживающих веб-запросы. Поскольку на PHP работает примерно 70% веб-сайтов в мире, а ошибки срабатывают до выполнения любого кода приложения, даже полностью обновленный сайт на WordPress, Drupal или Joomla остается уязвимым до тех пор, пока не будет обновлен базовый PHP, и злоумышленники активно ищут такие системы.
Calif, исследовательская компания по безопасности, работающая в рамках инициативы Patch the Planet от OpenAI, обнаружила эти уязвимости первой 1 августа и сообщила о них разработчикам PHP 11 августа. Wiz Research обнаружила их независимо.
Что нам известно на данный момент
- Две критические уязвимости в самом PHP. CVE-2026-109618 и CVE-2026-109619 находятся в ядре, поэтому даже защищенный код приложения не может защитить уязвимый сервер. Неаутентифицированный удаленный злоумышленник может прочитать память PHP-воркера (пароли, токена, API-ключи) и в некоторых случаях запустить код на сервере.
- Широкий охват. Уязвимы все версии PHP, начиная с 5.4, во всех средах: PHP-FPM, Apache modphp, php-cgi, FrankenPHP и LiteSpeed, причем наибольший риск представляет modphp.
- Подтверждено на реальных платформах. Удаленное выполнение кода было продемонстрировано на последних образах контейнеров WordPress, Drupal и Joomla. Даже простое PHP-приложение "Hello World" может быть уязвимо.
- Исправление выпущено, но утечка произошла первой. Исправленные релизы вышли 21 октября: PHP 8.5.12, 8.4.27, 8.3.36 и 8.2.35. Для PHP 8.1 и более старых версий официальных релизов не будет.
Почему это важно
Большинство команд запишут это как две уязвимости в PHP, которые теперь исправлены. Однако масштаб проблемы гораздо шире.
- Уязвимости находятся ниже уровня приложения. CVE-2026-109618 и CVE-2026-109619 расположены в среде выполнения PHP, поэтому используемый фреймворк, CMS или пользовательский код не имеют значения. Эксплуатация может произойти до того, как выполнится какой-либо код приложения, а это означает, что логи на уровне приложения могут практически ничего не зафиксировать.
- Ошибки в самом приложении не требуются. Атака не зависит от уязвимого плагина, слабого механизма входа или небрежной обработки сессий. Сайт с чистым кодом все равно может быть уязвим, если базовый PHP не обновлен.
- Атаку можно провести без аутентификации. Злоумышленнику не нужны учетная запись, пароль или первоначальный доступ — достаточно возможности отправить запрос на ваш сервер.
- Стоимость создания эксплойта снизилась. Исследователи сообщают, что модели ИИ сократили время на то, что раньше требовало месяцев специализированной работы, до нескольких дней. Десятилетние классы уязвимостей, которые когда-то считались непрактичными для превращения в оружие, теперь доступны, и злоумышленники имеют доступ к тем же инструментам.
Учитывая, что на PHP работает огромная часть интернета — от WordPress и Drupal до внутренних инструментов, к которым никто не прикасался годами, — вопрос заключается не в том, используете ли вы его. Вопрос в том, где именно и удастся ли вам обнаружить каждый экземпляр.
Что нужно предпринять на этой неделе
Обнаружение
- Ищите признаки фазы настройки. Некорректные или необычные запросы multipart-загрузки, за которыми следуют ошибки нехватки памяти (memory-limit) или всплески HTTP-ответов 500, являются паттерном для поиска.
- Проверяйте исходящие cookies. Слишком большой или некорректный PHPSESSID в ответе может указывать на то, что память процесса утекает обратно клиенту.
- Фиксируйте создание процессов во время обработки загрузок. PHP-воркер никогда не должен порождать дочерний процесс во время синтаксического анализа загружаемого файла и до выполнения кода приложения. Считайте это надежным индикатором.
Эти признаки помогают в расследовании. Они не заменяют установку патчей.
Устранение уязвимостей
- Составьте инвентаризацию всех установок PHP. Выходите за рамки очевидных веб-приложений. Учитывайте встроенное ПО, программно-аппаратные комплексы и забытые внутренние инструменты.
- Сначала исправьте системы, смотрящие в интернет. Перейдите на PHP 8.5.12, 8.4.27, 8.3.36 или 8.2.35 в зависимости от используемой ветки.
- Смените секреты на уязвимых серверах. Если злоумышленник мог прочитать память воркера до того, как вы установили патч, считайте учетные данные, токены и API-ключи, находившиеся в этой памяти, скомпрометированными.
Хотите узнать, как единичный сбой по нехватке памяти превращается в выполнение кода? Читайте дальше.
Подробный разбор того, что нам известно о PHP2Shell
В бюллетене безопасности PHP описаны четыре ошибки, классифицированные как два CVE. Вместе они составляют уязвимость PHP2Shell. Первые три имеют общую «предфазу», которая подготавливает их успех и по сути позволяет достичь конечной цели удаленного выполнения кода (RCE). Четвертая представляет собой более внутренний процесс, и детали ее эксплуатации не раскрывались.
Чтобы понять, как они влияют на сервер, нам сначала потребуется рассмотреть несколько концепций.
Что за PHP? Краткий глоссарий
- PHP-воркер веб-сервера. Процесс, который обрабатывает HTTP-запрос и переиспользуется для последующих запросов, вместо того чтобы перезапускаться каждый раз.
- Парсинг multipart-запросов. Чтение PHP входящего запроса multipart/form-data (загрузка файла) и разбиение его на помеченные части. Этот процесс начинается очень рано.
- Обработка прогресса загрузки сессии. Функция PHP, которая отслеживает прогресс загрузки файла, чтобы страница могла отображать полосу прогресса. Она работает во время синтаксического анализа сервером multipart-запроса.
- Сессия. Способ PHP запоминать пользователя между запросами (cookie PHPSESSID).
- Лимит памяти (memory limit). Максимальный объем памяти, который может использовать один запрос.
- Глобальные указатели движка. Внутренние служебные переменные, которые движок PHP использует для отслеживания глобального состояния выполнения. Здесь важны три из них: PS(id) — идентификатор сессии; BG(unserialize) — состояние десериализатора (состояние восстановления исходного массива или объекта из сериализованной строки); EG(last_fatal_error_backtrace) — хранит информацию о последней ошибке.
- PS(id): идентификатор сессии.
- BG(unserialize): состояние десериализатора (состояние восстановления исходного массива или объекта из сериализованной строки).
- EG(last_fatal_error_backtrace): хранит информацию о последней ошибке.
- Очистка воркера. Нормальный процесс завершения в PHP должен выполняться между запросами на переиспользуемом воркере, сбрасывая глобальные указатели движка, чтобы следующий запрос начинался с чистого листа. Цепочка уязвимостей существует потому, что фатальные ошибки нехватки памяти прерывают запрос до выполнения этой очистки, оставляя указатели устаревшими.
- OPcache. Разделяемая память, содержащая прекомпилированный байт-код скриптов, который могут читать все воркеры, что исключает необходимость повторного чтения и компиляции одного и того же PHP-файла.
Теперь, когда мы знакомы с терминологией, перейдем к части, которая делает всё это возможным.
Предфаза
Основная концепция, используемая здесь, — это использование памяти после ее освобождения (use-after-free или UAF): память освобождается, но указатель на нее сохраняется и используется позже. Если злоумышленник добивается размещения новых данных в этой освобожденной памяти, PHP воспринимает байты злоумышленника как собственную доверенную структуру.
Злоумышленник отправляет специально сформированный multipart-запрос на загрузку, который приводит к исчерпанию памяти PHP во время обработки прогресса загрузки сессии на раннем этапе запроса. Запрос неожиданно завершается, очистка воркера пропускается, и остаются устаревшие указатели. Это может привести к раскрытию памяти или ее повреждению.
Последовательность действий злоумышленника:
- Создание «подготавливающего» запроса. Злоумышленник отправляет запрос multipart/form-data с данными о прогрессе загрузки сессии, размер которых рассчитан на исчерпание памяти во время синтаксического анализа.
- Ранний парсинг до приложения. Обработка прогресса загрузки выполняется до завершения нормального запуска PHP, поэтому глобальные указатели движка настраиваются на раннем этапе.
- Фатальная ошибка из-за нехватки памяти. Запрос превышает memory_limit; PHP прерывает работу и освобождает кучу (heap) запроса.
- Очистка пропускается. Указатели никогда не сбрасываются.
- Рабочий процесс выживает и используется повторно. Тот же рабочий процесс обрабатывает следующий запрос, все еще удерживая устаревшие указатели.
- Использование памяти. Данные злоумышленника занимают одно из освобожденных распределений (каждый указатель имеет собственное отдельное распределение).
Это конфигурация, от которой зависят первые три уязвимости.
Уязвимость 1: Раскрытие памяти удаленного процесса
После предварительной фазы другой многочастный запрос в том же рабочем процессе по-прежнему доверяет освобожденному распределению PS(id). PHP считывает повторно занятые байты как действующий идентификатор сеанса и кодирует их в URL-адрес в куки-файле ответа PHPSESSID. Злоумышленник может просто прочитать куки-файл, чтобы получить утечку памяти рабочего процесса. Это позволяет им преодолеть неопределенность адресов, что делает следующий шаг к RCE практичным.
Уязвимость 2: Использование памяти после освобождения в десериализаторе
Здесь освобожденному распределению BG (unserialize) доверяют вызывать повреждение памяти. PHP продолжает «десериализацию», используя память, возвращенную злоумышленником, как если бы она все еще была действительной, превращаясь в примитив повреждения памяти. В сочетании с утечкой из Уязвимости 1 эта уязвимость использовала неопределенность адресов для достижения неавторизованного RCE и была продемонстрирована на платформах WordPress, Drupal и Joomla.
Уязвимость 3: Использование памяти после освобождения в трассировке фатальных ошибок
Еще одно злоупотребление указателем EG(last_fatal_error_backtrace). Если тот же рабочий процесс отправляет диагностическое событие (любую последующую ошибку или предупреждение) после сбоя очистки, он может получить доступ к освобожденному указателю до повторной инициализации состояния. PHP обновит или уничтожит трассировку указателя и перейдет к памяти, возвращенной злоумышленником. Это использование после освобождения может быть превращено в повреждение памяти, которое может привести к RCE.
Уязвимость 4: Путаница типов в OPcache (отдельный поток, между рабочими процессами)
В отчете об уязвимости Wiz не описываются конкретные запросы или шаги для этой уязвимости, а упоминается лишь сбой внутреннего механизма. Итак, вкратце:
- Общий кэш скомпилированного кода. OPcache хранит предварительно скомпилированный байт-код в разделяемой памяти, чтобы каждый рабочий процесс мог использовать его повторно вместо перекомпиляции (php.net: «устраняет необходимость для PHP загружать и синтаксически анализировать скрипты при каждом запросе»).
- Два трекера. Локальный трекер процесса (CG(map_ptr_last)) и общий трекер (ZCSG(map_ptr_last)) оба отслеживают степень заполнения разделяемой памяти.
- Сбой выделения в процессе обновления. В промежутке между обновлением двух трекеров сбой выделения может привести к рассинхронизации общего трекера с тем, что было записано.
- Повторное использование между рабочими процессами. Wiz утверждает, что это может позволить другому рабочему процессу повторно использовать этот слот памяти, и он разрешится в указатель неверного типа. Это вызывает путаницу типов и повреждает общее состояние OPcache, которое впоследствии было использовано для достижения RCE. То, как и когда это происходит, не уточняется, поэтому воспринимайте это как общую схему уязвимости, а не как точную последовательность.
Влияние на продукты Varonis
Varonis оценила влияние этих уязвимостей на все свои продукты и предприняла необходимые меры по устранению.
Продукт
Статус уязвимости
Varonis SaaS
Не затронуты
Varonis DAC
Не затронуты
Varonis Atlas
Не затронуты
Varonis Interceptor
Ранее затронуты; полностью исправлены
На дату публикации компания Varonis не выявила признаков компрометации, связанных с этими уязвимостями. Все затронутые среды Varonis Interceptor исправлены. Никаких действий от клиентов не требуется. Затронутые компоненты Varonis исправлены, а продукты Varonis SaaS, DAC и Atlas не уязвимы к данным CVE.
Ссылки
Как Varonis может помочь
Varonis помогает клиентам противостоять PHP2Shell и другим угрозам путем обнаружения подозрительного латерального перемещения и аномального доступа к данным, а затем автоматически изолирует скомпрометированные учетные записи для защиты конфиденциальных данных.
Управляемое обнаружение угроз и реагирование на них (MDDR) обеспечивает дополнительный уровень защиты наряду с установкой исправлений: эксперты Varonis круглосуточно и без выходных мониторят активность данных, расследуют такие угрозы, как доступ к конфиденциальным данным с помощью украденных учетных данных, и принимают меры по их изоляции. Клиенты получают круглосуточную экспертную поддержку без необходимости нанимать собственный штат специалистов.
Резюме
PHP2Shell — это цепочка, порожденная одним непримечательным событием: запросом, у которого заканчивается память и который пропускает этап очистки. На основе этого единственного устаревшего указателя исследователи получили раскрытие памяти, два варианта использования после освобождения и отдельную путаницу типов OPcache, и все это ниже уровня приложения и присутствует еще со времен PHP 5.4.
Гавриэль Фрид (Gavriel Fried) — исследователь облачной безопасности в компании Varonis. До работы в Varonis опыт работы Гавриэля в сфере кибербезопасности включал различные исследовательские должности, такие как облачные технологии, системы управления идентификацией (Identity), UEBA, технологии обмана (Deception), сети и DPI, Red Teaming, цифровая криминалистика и анализ вредоносного ПО. Гавриэль исследует потенциальные атаки, злоупотребления, уязвимости и аномалии в облачных сервисах и SaaS




.png)




