Категория > Новости > Log4HELL! Разбираем Log4Shell во всех подробностях - «Новости»
Log4HELL! Разбираем Log4Shell во всех подробностях - «Новости»16-01-2022, 00:02. Автор: Walter |
обсуждали ее импакт и рассказывали о том, как разные компании сражаются с напастью. В этой статье мы с тобой подробно разберемся, откуда взялась эта ошибка и как она работает, а также какие успели появиться эксплоиты. Заголовки новостей пестрят ужасными сообщениями о том, что проблема охватывает половину компьютерного мира. А взломать через нее якобы можно всё — от сервера Minecraft твоего соседа до крупных корпораций вроде Apple. На GitHub есть несколько репозиториев, например, Log4jAttackSurface или log4shell со списками уязвимого ПО (с блэкджеком и пруфами, разумеется!). Даже в «Википедии» уже есть статья о Log4Shell! Давай разбираться так ли страшен черт, как его малюют, с чего все началось и почему баг получил такую огласку. Как нашли уязвимостьНачнем с небольшой преамбулы. Баг был обнаружен экспертом Чен Чжаоцзюнь (Zhaojun Chen) из команды Alibaba Cloud Security. Детали уязвимости были отправлены в Apache Foundation 24 ноября 2021 года. В публичный доступ они попали чуть позже — 9 декабря. В твиттере завирусился пост, в котором была пара картинок, изображающих результат успешной эксплуатации — запущенный калькулятор. На первом скрине был затерт пейлоад, но вторая картинка и кусок кода из первой намекали, где и что нужно искать. Помимо этого в посте была ссылка на pull-реквест с фиксом, прямо скажем не слишком удачным! Сейчас пост в твиттере уже удален и посмотреть можно только через Internet Archive. Пост в твиттере об уязвимости в Log4j В этот же день на GitHub появился PoC с деталями эксплуатации. Когда уязвимость обзавелась собственным идентификатором CVE-2021-44228, репозиторий переименовали, а затем и вовсе удалили. Как видишь, увидеть начало истории сейчас можно только благодаря архивам. К слову, баг получил максимальный балл (10) по стандарту CVSS из‑за его простой эксплуатации, не требующей никаких прав, и серьезности последствий для атакуемой системы. Итак, эксплоит получил распространение и начал уходить в массы, люди стали тестировать пейлоады повсеместно и обнаруживать уязвимые продукты. Давай в деталях посмотрим, в чем причина уязвимости, какие были обходы и патчи и в каких продуктах. Найденные уязвимостиCVE-2021-44228 — злоумышленник, который может контролировать сообщения журнала или параметры сообщений журнала, может выполнить произвольный код, загруженный с серверов LDAP через JNDI. Проблема затрагивает версии Apache Log4j2 2.0-beta9 до 2.15.0 (за исключением исправлений безопасности 2.12.2, 2.12.3 и 2.3.1) уязвимы к удаленному выполнению произвольного кода через JNDI. CVE-2021-45046 — злоумышленник, контролирующий через Thread Context Map (MDC) динамические данные в сообщениях журналов событий, может создать пейлоад с использованием JNDILookup, который приведет к утечке информации и удаленному выполнению кода в некоторых конфигурациях Log4j и локальному выполнению кода во всех конфигурациях. Проблема присутствует из‑за не полностью исправленной уязвимости CVE-2021-44228 в Log4j 2.15.0. CVE-2021-45105 — из‑за проблемы неконтролируемой рекурсии, злоумышленник специально сформированным сообщением журнала событий может вызвать отказ в обслуживании. Проблема затрагивает версии Log4j2 начиная с 2.0-alpha1 и до 2.16.0 (за исключением 2.12.3 and 2.3.1). CVE-2021-44832 — Злоумышленник, имеющий доступ к изменению настроек логирования, может создать такую конфигурацию, через которую возможно удаленное выполнение кода. Для этого используется JDBC Appender с источником данных, ссылающимся на JNDI URI. Проблема затрагивает все версии Log4j2 начиная с 2.0-beta7 и до 2.17.0. СтендТеатр, как известно, начинается с вешалки, а тестирование уязвимости — со стенда В качестве основной системы я буду использовать Windows и IntelliJ IDEA для компиляции и отладки. Cоздаем пустой проект на Java с использованием gradle. Добавляем в зависимости уязвимую версию Log4j, например, 2.14.1. build.gradle
dependencies {
implementation 'org.apache.logging.log4j:log4j-api:2.14.1'
implementation 'org.apache.logging.log4j:log4j-core:2.14.1'
}
Потом создаем класс где аргумент, который мы передадим программе, будет логироваться. src/main/java/logger/Test.java
package logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static final Logger logger = LogManager.getLogger(Test.class);
public static void main(String[] args) {
String msg = (args.length > 0 ? String.join(" ", args) : "");
logger.error(msg);
}
}
Теперь укажем главный класс, который должен вызываться при запуске. build.gradle
plugins {
id 'java'
id 'application'
}
...
mainClassName = 'logger.Test'
Все готово, можно запускать. Параметры в логгер передаем в качестве аргументов с помощью флага
gradlew run --args='hello world'
Запуск программы для тестирования уязвимости log4shellТеперь настало время протестировать работу уязвимости, для этого возьмем простой пейлоад Тестирование уязвимости log4shellКоннект приходит, а это значит, что уязвимость успешно проэксплуатирована. Этого пока достаточно для дальнейшего препарирования. Детали уязвимостиПопробуем разобраться, почему эта загадочная конструкция вообще выполняется. По сути, конструкции вида Теперь скачаем исходники нашей версии библиотеки Log4j. Интересующая нас обработка логируемого события начинается в методе org/apache/logging/log4j/core/pattern/MessagePatternConverter.java ... public void format(final LogEvent event, final StringBuilder toAppendTo) { Этот цикл проверяет наличие конструкции { в тексте логируемого сообщения библиотеки log4j' title='Проверка наличия конструкции { в тексте логируемого сообщения библиотеки log4j">Проверка наличия конструкции ${ в тексте логируемого сообщения библиотеки log4j org/apache/logging/log4j/core/lookup/StrSubstitutor.java ... public static final char DEFAULT_ESCAPE = '$'; ... public static final StrMatcher DEFAULT_PREFIX = StrMatcher.stringMatcher(DEFAULT_ESCAPE + "{"); ... public static final StrMatcher DEFAULT_SUFFIX = StrMatcher.stringMatcher("}"); Здесь можно видеть инициализацию дефолтного префикса ( org/apache/logging/log4j/core/lookup/StrSubstitutor.java
public StrMatcher getVariablePrefixMatcher() {
return prefixMatcher;
}
...
public StrMatcher getVariableSuffixMatcher() {
return suffixMatcher;
}
org/apache/logging/log4j/core/lookup/StrSubstitutor.java
private int substitute(final LogEvent event, final StringBuilder buf,
final int offset, final int length,
List<String> priorVariables) {
final StrMatcher prefixMatcher = getVariablePrefixMatcher();
final StrMatcher suffixMatcher = getVariableSuffixMatcher();
Он снова выполняет поиск таких конструкций ( org/apache/logging/log4j/core/lookup/StrSubstitutor.java
while (pos < bufEnd) {
final int startMatchLen = prefixMatcher.isMatch(chars, pos, offset, bufEnd);
if (startMatchLen == 0) {
pos++;
} else // found variable start marker
Метод Перейти обратно к новости |