Массовая кампания взлома WordPress, Joomla и Craft CMS: 15 уязвимостей, один и тот же результат — веб-шелл
Массовая кампания взлома WordPress, Joomla и Craft CMS: 15 уязвимостей, один и тот же результат — веб-шелл
Вы держите десяток клиентских сайтов на одном сервере — общий nginx, общий PHP-FPM пул, отдельные вебруты. Один из сайтов — WordPress с формой обратной связи на Ninja Forms и плагином для загрузки файлов. Вы его не трогали полгода: сайт работает, зачем лезть. 9 июля 2026 года австралийский ACSC (Australian Signals Directorate’s Cyber Security Centre) выпускает критическое предупреждение: по всему миру идёт масштабная кампания, в которой атакующие сканируют именно такие сайты и заливают на них веб-шеллы через известные уязвимости в CMS-платформах и их компонентах. Список — 15 записей, почти все с CVSS 9.8–10.0: плагины WordPress, редактор Joomla Content Editor, сами платформы Craft CMS, MaxSite CMS и MetInfo CMS, и даже один Laravel-пакет (pay-uz) для приёма платежей — попал в общий список, хотя к WordPress отношения не имеет.
Это не эксплуатация одного нашумевшего 0-day. Это одновременный обстрел целого фронта известных, давно запатченных уязвимостей — от файлового аплоада в Ninja Forms File Uploads (CVE-2026-0740, CVSS 9.8) до PHP-инъекции через функцию трансформации изображений в Craft CMS (CVE-2025-32432, CVSS 10.0). ACSC прямо связывает рост скорости атак с использованием ИИ для автоматизации сканирования и подбора эксплойтов — это упоминалось и в недавнем совместном заявлении агентств Five Eyes. Для сайтов малого и среднего бизнеса, где обновления плагинов откладываются месяцами, это тот самый сценарий, когда «работает — не трогай» превращается в открытую дверь.
ЧТО ТАКОЕ КАМПАНИЯ С ВЕБ-ШЕЛЛАМИ
Веб-шелл — это файл (чаще всего .php), который атакующий заливает на сервер через уязвимый обработчик загрузки, а затем обращается к нему напрямую по URL. Файл выполняется веб-сервером как обычный скрипт сайта — но внутри него код, который принимает команды от атакующего: выполнение shell-команд, чтение и запись файлов, создание новых пользователей, разворачивание дальнейших инструментов. В отличие от разового дефейса, веб-шелл — это persistent-доступ: даже если вы найдёте и удалите один файл, ничего не помешает атакующему просто снова просканировать сайт и повторить процесс, если сама уязвимость осталась незакрытой.
Массовая кампания в данном случае значит следующее: боты не выбирают жертву осознанно, они прочёсывают интернет по сигнатурам — характерным путям плагинов, версиям в мета-тегах, откликам сервера на пробный запрос. Найденная связка «CMS + версия плагина» сверяется со списком известных уязвимостей, и если совпадение есть — в ход идёт готовый эксплойт. Ваш сайт эксплуатируют не потому что кто-то специально нацелился на вас, а потому что он статистически попался в невод.
РЕАЛЬНАЯ ЦЕПОЧКА АТАКИ
Возьмём Craft CMS и CVE-2025-32432 — самый показательный пример из списка, потому что его начали эксплуатировать в реальных атаках ещё в феврале 2025 года, за два месяца до того, как вышел патч, и историю разбирала команда Orange Cyberdefense. У Craft CMS есть встроенная функция трансформации изображений: загрузили фото 4.5 МБ — CMS сама генерирует уменьшенную версию для миниатюры. Обрабатывает это неаутентифицированный контроллер-эндпоинт actions/assets/generate-transform — доступный без логина, потому что нужен для отображения картинок на публичной части сайта.
Проблема в том, что в версиях 4.x и 5.x проверка валидности asset ID — идентификатора конкретного файла-изображения — происходит уже после создания объекта трансформации, а не до. Атакующий сначала перебирает численные значения asset ID в POST-запросах к тому же эндпоинту, пока не находит существующий, — в версиях 3.x эта проверка стоит раньше по потоку выполнения, поэтому там нужен рабочий ID заранее, но исход тот же. Как только валидный ID найден, второй запрос несёт в теле параметр handle — в норме это просто имя трансформации вроде «thumbnail», строка. В боевом эксплойте вместо строки прилетает вложенный объект с полем __class, которое говорит серверу: создай экземпляр вот этого PHP-класса — GuzzleHttp\Psr7\FnStream, служебный HTTP-класс, который в норме никогда не должен создаваться напрямую из тела чужого запроса. Сервер слушается, не проверяя, что клиент вообще не должен иметь права указывать, какой код выполнять. Официальный CVSS-вектор от Craft CMS (10.0, приватность и целостность данных страдают полностью) относит проблему к категории Code Injection; независимая классификация GitHub Security Advisory уточняет её как CWE-470, небезопасное использование пользовательского ввода при выборе класса для рефлексии. Суть в обоих случаях одна: тело чужого HTTP-запроса решает, что выполнит ваш PHP-процесс.
В том самом расследованном инциденте атака началась 14 февраля 2025 года, и атакующий не останавливался на демонстрационном вызове phpinfo(). По данным Orange Cyberdefense, у бага было два рабочих способа эксплуатации; в этой атаке использовался следующий: атакующий отправлял запрос с параметром «return URL», значение которого Craft CMS сохраняла в файле PHP-сессии на диске, а затем возвращала обратно посетителю как часть того же самого HTTP-ответа — то есть в файл сессии на сервере попадал код, полностью подконтрольный атакующему. Вторым шагом атакующий эксплуатировал независимую уязвимость в самом фреймворке Yii, на котором построен Craft CMS (CVE-2024-58136 — ошибка валидации ввода), чтобы заставить сервер выполнить именно этот файл сессии как PHP-код. Результат — файловый менеджер на PHP, залитый в веб-рут сервера, который атакующий затем использовал, чтобы догрузить дополнительные PHP-файлы.
С этого момента у атакующего полноценный веб-шелл, через который он читает конфиги с учётными данными БД, устанавливает бэкдоры для сохранения доступа и использует скомпрометированный сервер как плацдарм для сканирования внутренней сети — если веб-сервер стоит в одном сегменте с остальной инфраструктурой компании. Масштаб именно этой кампании подтверждён количественно: Orange Cyberdefense насканировала порядка 35 000 уникальных доменов с Craft CMS, из них около 13 000 инсталляций оказались уязвимы, а порядка 300 — по характерным следам в виде файлов filemanager.php и autoload_classmap.php в веб-руте — были признаны скомпрометированными на момент публикации отчёта в апреле 2025 года. Сама Craft CMS официально подтвердила активную эксплуатацию 17 апреля 2025 года — через неделю после выхода патча — и разослала предупреждение всем держателям лицензий с рекомендацией обновиться немедленно.
Похожая логика — с разными техническими деталями — работает для остальных 14 записей в списке ACSC. В Ninja Forms File Uploads (CVE-2026-0740) корень проблемы не в отсутствии проверки типа файла как такового, а в том, что функция NF_FU_AJAX_Controllers_Uploads::handle_upload валидирует расширение исходного файла, но не проверяет итоговое имя файла на этапе перемещения в целевую директорию — атакующий манипулирует путём назначения и обходит allowlist расширений, заливая PHP-файл напрямую в веб-доступную папку загрузок. Ни аутентификация, ни какая-либо капча тут не требуются — эндпоинт AJAX открыт публично, потому что форма с загрузкой файлов должна работать для анонимных посетителей сайта. Это не теоретический риск: по данным Wordfence, эксплуатация началась в тот же день, когда уязвимость была раскрыта, а массовая волна атак пришлась на 9–13 апреля 2026 года — файрвол Wordfence заблокировал более 118 600 попыток эксплуатации именно этой уязвимости.
А то, что список ACSC — не гипотетическая угроза, а описание уже идущей охоты, подтвердило независимое расследование буквально накануне бюллетеня. 11 июня 2026 года исследователи SOCRadar обнаружили открытый без пароля сервер злоумышленников, который те по невнимательности оставили доступным на три недели. Внутри — почти 800 МБ инструментов, логов и списков целей на 1,4 млн доменов, использующих ровно те же уязвимости, что перечисляет ACSC: Breeze (CVE-2026-3844), ThemeREX Addons, Simple File List, BerqWP, Ninja Forms File Uploads, WavePlayer, WPBookit и Joomla JCE. По оценке независимой команды Ctrl-Alt-Intel, проанализировавшей ту же папку, подтверждённых или вероятных компрометаций набралось 25 195 — большая часть пришлась именно на баг в Breeze при включённой не по умолчанию настройке «Host Files Locally — Gravatars»: свыше 45 000 целей просканировано, свыше 17 000 успешно скомпрометировано. Обе исследовательские группы с умеренной-высокой уверенностью связывают операцию с китайскоязычной группировкой — из-за китайского языка в командной истории и использования FOFA, китайского аналога Shodan, требующего китайский номер телефона для регистрации.
Механизм в Breeze показателен именно потому, что уязвимая функция вообще не про загрузку файлов пользователем — про кэширование аватаров. Функция fetch_gravatar_from_remote в файле class-breeze-cache-cronjobs.php скачивает Gravatar-картинку по URL и сохраняет её на диск через file_put_contents() — без единой проверки, что скачанное содержимое действительно является изображением. Если настройка «Host Files Locally — Gravatars» включена (по умолчанию выключена, что и объясняет, почему пострадала лишь часть из 45 000 просканированных целей), атакующий подсовывает вместо аватара PHP-файл, замаскированный под URL Gravatar-сервиса, — и Breeze сам, от имени сайта, скачивает и сохраняет веб-шелл в директорию /uploads/breeze/gravatars/. Дальше не нужен ни аплоад через форму, ни аутентификация — только знание того, что у сайта включена эта опция.
ХРОНОЛОГИЯ
Список уязвимостей в кампании охватывает почти два года разработки эксплойтов, объединённых в одну текущую волну атак: CVE-2020-36847 в плагине Simple File List — старейшая запись, обнаруженная ещё в 2020 году (отдельно заведённый CVE-2025-34085 ACSC отклонил как дубликат этой же уязвимости). CVE-2024-9234 в GutenKit и Hunk Companion датируется 2024 годом — ACSC считает её связь с кампанией «вероятной», но не подтверждённой на сто процентов. CVE-2025-32432 в Craft CMS начали эксплуатировать вручную 10 февраля 2025 года, а уже 14 февраля Orange Cyberdefense привлекли к расследованию конкретного взломанного сервера — с этой даты и началось документирование бага. Официальный патч (версии 3.9.15, 4.14.15 и 5.6.17) вышел только 10 апреля — ровно два месяца спустя первой атаки. Большинство остальных записей — CVE-2025-7443 (BerqWP), CVE-2025-7852 (WPBookit), CVE-2025-12057 (WavePlayer), CVE-2025-13486 (ACF Extended), CVE-2025-6389 (Sneeit Framework), CVE-2025-12352 (Gravity Forms) — раскрыты в течение 2025 года. CVE-2026-0740 в Ninja Forms File Uploads исследователь Sélim Lanouar передал в Wordfence Bug Bounty Program 8 января 2026 года, получив за находку 2145 долларов; публичное раскрытие состоялось 6 апреля 2026-го, и в тот же день начались первые попытки эксплуатации. Патч прошёл три итерации: частичное исправление 3.3.25 вышло 10 февраля, ещё более широкий блэклист расширений в 3.3.26, и только версия 3.3.27 от 19 марта 2026 года закрыла обход целиком — то есть окончательный патч появился почти за три недели до публичного раскрытия самой уязвимости.
Отдельного внимания заслуживает самая свежая и самая агрессивно эксплуатируемая запись в списке — CVE-2026-48907 в Joomla Content Editor (JCE), редакторе, установленном на огромном количестве Joomla-сайтов. Патч вышел 3 июня 2026 года в версии 2.9.99.5, но уже 9 июня на GitHub появился публичный PoC — и с этого момента начались автоматизированные атаки на сотни сайтов. 16 июня 2026 года CISA включила эту уязвимость в каталог Known Exploited Vulnerabilities (KEV) — подтверждение факта активной эксплуатации — и установила федеральным агентствам США трёхдневный срок на устранение, до 19 июня. Три дня — один из самых коротких сроков, которые когда-либо назначала CISA, что само по себе говорит о серьёзности ситуации: от публикации патча до попадания в KEV прошло меньше двух недель.
9 июля 2026 года ACSC объединяет весь этот разнородный набор — от пятилетней давности бага до полугодовой свежести — в единый бюллетень о текущей активной кампании. Это ключевой момент: возраст CVE тут не имеет значения для атакующего. Если патч не установлен, дырка одинаково открыта что в 2020, что в 2026 году.
ПОЧЕМУ ЭТО ВАЖНО
Для сисадмина, который держит один или несколько сайтов на shared-хостинге или на своём VPS, ключевая мысль такая: ни один из 15 багов в списке не новый и не сложный в эксплуатации технически. Все они имеют публичные патчи. Проблема не в том, что защититься невозможно, а в том, что обновление плагинов — это рутинная задача, которую откладывают, пока сайт «работает». Атакующие в этой кампании как раз и делают ставку на разрыв между датой публикации патча и датой его реального применения на конкретном сервере.
Отдельная проблема — премиум-плагины вроде Ninja Forms File Uploads: они распространяются не через штатный репозиторий WordPress.org, а через собственный канал вендора, и автообновление WordPress core на них попросту не действует. Если вы настроили auto-update для core и бесплатных плагинов из каталога, но забыли, что у вас есть платное расширение с отдельным механизмом обновления — оно тихо остаётся на уязвимой версии, пока вы вручную не зайдёте и не проверите.
Для тех, кто администрирует не один сайт, а десятки клиентских инсталляций на общей инфраструктуре — хостинг-провайдеры, агентства, фрилансеры с портфелем клиентов — риск множится линейно на число сайтов. Формы обратной связи и загрузки файлов (Ninja Forms, Gravity Forms, Simple File List, WPBookit) — это именно те компоненты, которые чаще всего есть на любом коммерческом сайте, а не экзотика, которую можно проигнорировать. Веб-шелл на одном из клиентских сайтов на общем сервере — это потенциальный плацдарм для атаки на соседние вебруты через тот же PHP-FPM или общие точки монтирования, если изоляция между сайтами настроена небрежно.
КАК ПРЕДОТВРАТИТЬ ПОВТОРЕНИЕ
Патчинг — это обязательный минимум, но кампания именно потому и массовая, что одного патчинга исторически недостаточно. Что реально снижает поверхность атаки на уровне архитектуры сервера:
Сделайте директории веб-рута read-only там, где в них не должно происходить записи в обычном режиме работы. Большинство CMS пишут только в конкретные подкаталоги — wp-content/uploads, storage, кэш-директории. Остальное дерево файлов CMS (движок, ядро плагинов, темы) может быть смонтировано с правами на чтение для пользователя, от которого работает PHP-FPM; изменение файла ядра WordPress веб-сервером само по себе уже сигнал компрометации.
Запретите выполнение PHP-файлов в директориях загрузки на уровне веб-сервера, а не полагайтесь только на проверку типа файла внутри плагина. В nginx это делается блоком location для /wp-content/uploads/, который отдаёт статику, но не передаёт запросы в PHP-FPM. Даже если атакующий обойдёт allowlist расширений в самом плагине и зальёт .php-файл в папку аплоадов, сервер не станет его исполнять — отдаст как обычный текстовый файл или откажет в доступе.
Контролируйте, какие дочерние процессы порождает воркер веб-сервера. Веб-шелл почти всегда в какой-то момент вызывает system(), exec() или аналог, чтобы запустить shell-команду. Если у вас есть возможность ограничить это через seccomp-профиль в контейнере или через AppArmor/SELinux-политику для процесса PHP-FPM, любой неожиданный дочерний процесс типа /bin/sh или curl, порождённый от php-fpm, — это сигнал для алерта, даже если сам эксплойт сработал.
Разделите публичные сайты и внутреннюю корпоративную сеть на уровне сетевой сегментации. Даже если веб-шелл заведётся, он не должен иметь маршрутизируемого доступа к внутренним ресурсам компании — базам данных, не связанным с этим сайтом, файловым шарам, административным панелям других систем. nftables-правила, ограничивающие исходящий трафик с веб-серверов только на необходимые адреса, — базовая, но часто пропускаемая мера.
ЧТО ДЕЛАТЬ
Начните не с обновления, а с проверки следов компрометации — если уязвимый плагин стоял у вас месяцами, шанс, что его уже просканировали и, возможно, эксплуатировали, не нулевой. Проверьте каталог загрузок и директорию конкретного плагина на файлы, которые вы туда не клали: подозрительны любые .php-файлы со случайными именами, файлы с недавней датой изменения, не совпадающей с вашими собственными действиями — в норме исполняемого кода в uploads быть не должно вообще.
Просмотрите access-логи веб-сервера на GET и POST-запросы к нехарактерным путям — для случая Craft CMS официальный advisory прямо указывает искать POST-запросы на actions/assets/generate-transform со строкой __class в теле запроса; сама Craft CMS оговаривает, что наличие такого запроса в логах означает как минимум факт сканирования, не обязательно успешный взлом. Пустой результат такого поиска не отменяет проверку остальных 14 CVE из списка, если у вас установлены соответствующие плагины. Для Joomla с JCE ищите похожие следы отдельно: неожиданные новые профили редактора в базе данных (таблица профилей JCE) и POST-запросы к index.php?option=com_jce с параметрами, указывающими на импорт или создание профиля, пришедшие от внешних IP без предварительной авторизации в админке. Если у вас установлен Breeze Cache — первым делом проверьте, включена ли настройка «Host Files Locally — Gravatars» (по умолчанию выключена); если да, независимо от версии плагина проверьте директорию /wp-content/uploads/breeze/gravatars/ на файлы с расширениями .php, .phtml или .phar — по умолчанию там должны быть только изображения.
Если веб-шелл найден — не удаляйте файл и не считайте инцидент закрытым. ACSC прямо рекомендует: сервер с обнаруженным веб-шеллом нужно рассматривать как полностью скомпрометированный. Изолируйте его от сети, проверьте журналы аутентификации на предмет новых учётных записей администратора, которые вы не создавали, проверьте, не появились ли новые SSH-ключи или cron-задачи, и просмотрите сетевые логи (в том числе на периметровом файрволе) на предмет исходящих соединений от этого сервера к незнакомым внешним адресам — это может указывать на эксфильтрацию данных или связь с C2.
Только после того как компрометация подтверждена или исключена, обновляйте сами уязвимые компоненты. Если конкретно у вас стоит Craft CMS — обновляйтесь до версии 3.9.15, 4.14.15 или 5.6.17 в зависимости от вашей мажорной ветки. Из корня проекта запустите обновление именно пакета Craft, а не всех зависимостей разом:
composer update craftcms/cms
После этого обязательно примените миграции — Craft хранит часть настроек в базе данных, и без этого шага сайт может повести себя странно после обновления кода. Официальная документация рекомендует запускать это в неинтерактивном режиме, чтобы команда не зависла в ожидании ответа на подтверждение:
php craft up --interactive=0
Проверить, что версия действительно обновилась, можно так — команда покажет установленный номер версии пакета:
composer show craftcms/cms
Для Ninja Forms File Uploads нужна версия 3.3.27 или новее. Это платный аддон, распространяется не через каталог WordPress.org, а через отдельный канал вендора — автообновление core на него не действует. Проверьте установленную версию в панели WordPress (Плагины → Ninja Forms — File Uploads) и обновите вручную через тот же канал, откуда покупали лицензию. Если обновить прямо сейчас невозможно — временно деактивируйте плагин через админку или переименуйте директорию плагина в wp-content/plugins/, чтобы WordPress перестал его загружать, пока вы не готовы применить патч.
Если у вас Joomla с установленным Joomla Content Editor — обновление здесь самое срочное из всех пятнадцати пунктов: версия должна быть 2.9.99.5 или новее, вышла 3 июня 2026 года (разработчик рекомендует сразу 2.9.99.6 от 8 июня, где добавлено дополнительное усиление). Проверить установленную версию можно в панели администратора Joomla, в разделе Components → JCE Editor → Control Panel. Учитывая, что эта уязвимость уже официально в CISA KEV с подтверждённой эксплуатацией, любая задержка здесь — не гипотетический риск, а известный факт активных атак прямо сейчас. Сам разработчик JCE прямо предупреждает: обновление закрывает точку входа, но не удаляет то, что атакующий уже мог оставить на сервере, если сайт был уязвим после 9 июня 2026 года, когда в открытом доступе появился рабочий эксплойт — после обновления обязательно проверьте директории загрузки JCE (обычно /images/, /images/stories/ или заданный в профиле редактора путь) на незнакомые PHP-файлы.
ВЫВОДЫ
Если вы администрируете один сайт на своём VPS — потратьте час на аудит установленных плагинов против списка ACSC и на проверку логов, описанную выше, прежде чем откладывать это на следующую неделю. Особое внимание — Breeze Cache: даже если вы уверены, что настройка «Host Files Locally — Gravatars» никогда не включалась, проверьте это явно в настройках плагина, а не полагайтесь на память — именно этот баг дал больше всего реальных компрометаций в задокументированной кампании WP-SHELLSTORM. Если вы хостинг-провайдер или ведёте несколько клиентских сайтов на общей инфраструктуре — начните с изоляции PHP-FPM пулов между клиентами и с блокировки исполнения PHP в директориях загрузки на уровне nginx, это единственная мера из списка, которая защищает сразу от всех 15 уязвимостей одновременно, а не от одной конкретной. И для владельцев сайтов, которые платят агентству за поддержку, — это тот случай, когда стоит прямо спросить у подрядчика, применены ли патчи из бюллетеня ACSC от 9 июля, а не полагаться на то, что «у нас всё автоматически обновляется».
