ADG Оставить заявку
Блог Информационная безопасность 5 мин чтения

Spring4Shell (CVE-2022-22965): снова Java, снова критическая RCE

RCE-уязвимость в Spring Framework, активная эксплуатация с 30 марта. За сутки прошлись по всем клиентским Spring Boot приложениям - реестр версий и WAF-правила до патча.

Контекст момента

Spring4Shell CVE-2022-22965: RCE-уязвимость в Spring Framework, активная эксплуатация с 30 марта 2022

Дежавю не заставило себя ждать. 30 марта в публичный доступ утёк PoC эксплоита для CVE-2022-22965 - уязвимости в Spring Framework, которую уже прозвали Spring4Shell. Снова Java. Снова RCE без аутентификации. Снова паника в телеграм-каналах по ИБ и срочные письма от вендоров. С декабрьского Log4Shell-марафона прошло три месяца.

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

Суть в механизме data binding Spring MVC. При определённых условиях атакующий может записать произвольные данные через class.classLoader, получив в итоге выполнение кода на сервере. Вектор - HTTP-запрос, жертва ничего не нажимает.

Условия срабатывания не тривиальные, но и не фантастические:

  • Spring Framework 5.3.0-5.3.17 или 5.2.0-5.2.19 (и более старые неподдерживаемые ветки).
  • JDK 9+. На Java 8 уязвимость не работает из-за различий в ClassLoader. Это важно - часть старых приложений на Java 8 автоматически выпадает из зоны риска.
  • Развёртывание как WAR на Tomcat. Executable JAR (стандартный Spring Boot) менее очевидно уязвим - там другой ClassLoader, механика другая.
  • Нет ограничений на поля в @ModelAttribute. Если разработчики явно задали allowedFields или использовали allowlist - риск снижается.

На момент появления PoC официального патча ещё не было. VMware (владелец Spring) выпустила патч 31 марта - Spring Framework 5.3.18 и 5.2.20.

Дежавю по-крупному

Декабрьский Log4Shell научил одному: Java-приложения в инфраструктуре клиентов живут в самых неожиданных местах. Тогда мы потратили дни на выяснение «а что вообще запущено». Повторять этот опыт не хотелось.

Примерно за последние месяцы после Log4Shell-аудита мы настояли на том, чтобы у клиентов появились хотя бы базовые реестры Java-компонентов. Не SBOM в полном смысле, но список: что запущено, на чём, какая версия фреймворка. Именно это сейчас и пригодилось.

Как прошли за сутки

30 марта вечером информация о PoC разошлась достаточно широко, чтобы стало понятно: завтра будет жарко. Запустили проверку по реестру, который собирали с января.

По каждому Spring-приложению проверяли три вещи:

  • Версия Spring Framework. Если 5.3.x до 5.3.17 или 5.2.x до 5.2.19 - в приоритет.
  • Версия JDK. Приложения на Java 8 отмечали отдельно - формально меньший риск, но расслабляться не стали.
  • Способ деплоя. WAR на Tomcat против executable JAR - разная механика уязвимости.

Картина оказалась пёстрой. Часть приложений - Spring Boot на относительно свежих версиях, часть - легаси WAR на Tomcat с Spring 4.x или 5.2.x. Именно старые WAR-развёртывания вызвали максимальный интерес.

Патча ещё не было - работали с тем, что есть. Для периметровых приложений развернули WAF-правила, блокирующие запросы, в параметрах которых встречается class., Class., %43lass и вариации. Это грубый фильтр и он даёт ложные срабатывания, но лучше разобраться с ложными срабатываниями, чем получить shell на продакшен.

Для части приложений применили mitigation от Spring на уровне кода - добавление глобального DataBinder с setDisallowedFields для class-иерархии. Где был прямой доступ к коду и возможность быстро задеплоить - сделали это.

Что помогло, что нет

Реестр Java-компонентов, собранный после Log4Shell, сократил время первичного скана раза в три по сравнению с декабрём. Вместо «что вообще есть» мы сразу шли к конкретным приложениям. Это не откровение, это просто работает.

Что не помогло: несколько приложений в реестре оказались с устаревшими данными. Версия Spring обновилась в январе без обновления реестра. Небольшая расплата за то, что реестр живёт в документе, а не генерируется автоматически из артефактов.

WAF-правила - временная мера с понятными ограничениями. Обход через urlencoding или другие вариации параметров возможен, фильтр не гарантирует ничего. Это пластырь до патча, не более.

В managed-инфраструктуре к концу 31 марта, когда VMware выпустила 5.3.18, у большинства клиентов обновление было либо уже задеплоено, либо в процессе. Несколько старых WAR-приложений на Tomcat - отдельная история: там обновление Spring зависит от процесса сборки и CI/CD, который в некоторых случаях живёт в 2015 году.

Параллели с Log4Shell

Сравнение напрашивается, но оно не полное. Log4Shell был проще в эксплуатации - jndi lookup можно было засунуть практически куда угодно, в любое поле любого HTTP-запроса. Spring4Shell требует более конкретных условий: нужен Spring MVC с определённым паттерном контроллера, нужен Tomcat в WAR-режиме, нужен JDK 9+.

Это не значит, что можно расслабиться. Это значит, что поверхность атаки несколько уже, и приоритизировать легче. Приложения на embedded Tomcat с JAR-деплоем и Spring Boot - под вопросом, но не в первой очереди. Легаси WAR на внешнем Tomcat с JDK 11 - первая очередь.

Тем не менее ощущение знакомое: снова Java, снова публичный PoC до патча, снова день-два в режиме «разобраться что есть и прикрыть». После декабря хотя бы знаем, как это делать быстрее.

Патч вышел, сейчас основная работа - прокатить обновления там, где это требует согласований или нестандартного процесса деплоя. История продолжается.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.