• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Про уязвимость Text4Shell

pablo

(L2) cache
Пользователь
Регистрация
01.02.2019
Сообщения
433
Реакции
1 524
За последнюю неделю в информационном поле инфобеза стали появляться новости о втором пришествии уязвимости Log4Shell, окрестившим себя Text4Shell. Первым об уязвимости сообщил Alvaro Muñoz, который рассказал о возможности удаленного выполнения произвольных скриптов в продуктах, использующих библиотеку Apache Commons Text.

Apache Commons Text — это open source компонент, используемый разработчиками для управления символьными строками. Уязвимость была выявлена в версиях 1.5-1.9 и связана с небезопасной реализацией функций интерполяции переменных. По данным сайта maven repository, библиотека Apache Commons Text используется в 2591 проекте, однако данная оценка не учитывает транзитивные зависимости библиотек.

Сама уязвимость была обнаружена еще в марте 2022 года, но команде Apache Commons потребовалось время на ее исправление и выпуск обновлений библиотеки.

Уязвимости был присвоен идентификатор CVE-2022-42889 (CWE-94 – i Injection), и определен достаточно высокий уровень риска CVSS 9.8.

В течение последующих дней после раскрытия информации об уязвимости стали появляться сомнения в критичности уязвимости, ссылаясь на невозможность эксплуатации в версиях JDK 15+ или по причине маловероятности попадания пользовательских данных в функцию интерполяции переменной. Однако при дальнейшем изучении уязвимости оказались открыты и другие векторы ее эксплуатации.

Перечень исследований, подвергавших сомнению серьезный уровень опасности уязвимости:
Наша команда PT Application Inspector решила определить уязвимые места в исходном тексте, оценить выпущенный патч от команды разработки и посоветовать шаги, которые помогут защититься от возможных атак.

Сначала про причины уязвимости​

В состав функциональных возможностей заложен механизм интерполяции переменных, то есть вставка в строку значений на основе обработки данных по шаблону. В качестве шаблона по умолчанию для данной библиотеки используется строка ${prefix:[options]:data}, где prefix определяет алгоритм обработки данных из options и data. Если у атакующего есть возможность задавать шаблон, он способен на следующее:

Атака​
Prefix​
Вектор атаки​
Удаленное выполнение кода​
script​
${script:javascript:java.lang.Runtime.getRuntime().exec('calc')}​
Сбор информации через запрос к DNS-серверу атакующего​
dns​
${dns:address|ptsecurity.com}​
Раскрытие внутренней сети, через http (https)-запросы​
url​
Чтение произвольного файла​
file​
${file:UTF-8:/etc/passwd}​
Доступ к переменным окружения, содержащим критичную информацию​
env​
${env: AWS_ACCESS_KEY_ID}​

А что же творится внутри библиотеки​

Чтобы разобраться с алгоритмом работы библиотеки, создадим простейшее веб-приложение, использующее уязвимый код приложения. Причем вектор попадает в уязвимую функцию из состава http-запроса параметра taint.

kecq5qrdz8fermrfvaqtorl85ccsrezl.png


В качестве вектора атаки будем использовать самый критичный вариант (i injection):
Код:
${script:javascript:java.lang.Runtime.getRuntime().exec('calc')}
В результате атаки должна выполнится команда ОС и запустится программа «Калькулятор».

При анализе кода можно выделить два момента, которые выполняются при использовании библиотеки:
  1. Создание экземпляра объекта StringSubstitutor путем вызова StringSubstitutor.createInterpolator.
  2. Манипулирования строкой, которая задается из параметра http-запроса. Это осуществляется путем вызова interpolator.replace(taint).
В первом случае при вызове функции StringSubstitutor.createInterpolator выполняется автоматическое заполнение таблицы связей между prefix и классом обработки вызова lookup().

Стек вызовов:

qxvqz0u0ok7jb2hl6avr3otopclnhgqg.png

В функции addDefaultStringLookups класса StringLookupFactory в конечном виде формируется HashMap (stringLookupMap) следующего вида:
Код:
…
"dns" -> {DnsStringLookup@785}
"env" -> {FunctionStringLookup@787}
…
"script" -> {ScriptStringLookup@793}
"url" -> {UrlStringLookup@795}
"file" -> {FileStringLookup@799}
…
Уязвимые префиксы (script, dns, url, file иenv) определены по умолчанию и доступны для использования.

Во втором случае для функции replace (replaceIn) класса StringSubstitutor выполняется вызов функций из стека:

qbccf7ozl89dxrbatr8eim97rz2ihpy4.png

Для данного стека можно выделить вызов функции lookup из класса ScriptStringLookup — это стало возможным из-за того, что для prefix=script установлена связь с классом ScriptStringLookup.

В зависимости от установленного класса в stringLookupMap для соответствующего значения prefix выполняется соответствующий метод lookup. Перечень критичных методов в зависимости от установленного префикса приведены ниже:

prefix​
Класс​
Критичный метод​
Ссылка на код​
script​
ScriptStringLookup​
scriptEngine.eval(script)​
dns​
DnsStringLookup​
InetAddress.getByName(subValue)​
url​
UrlStringLookup​
new URL(urlStr)​
file​
FileStringLookup​
Files.readAllBytes(Paths.get(fileName))​
env​
StringLookupFactory​
System::getenv​


Для нашего примера вызывается scriptEngine.eval(script). В JDK до версии 15 scriptEngine ассоциируется со встроенным скриптовым движком Nashorn, который выполняет скрипт, заданный пользователем. В версия JDK 15+ движок Nashorn был удален. Однако, если в проекте используется JDK 15+ и установлены зависимости на другой скриптовый движок, например JEXL, то вектор изменится на: ${script:JEXL:''.getClass().forName('java.lang.Runtime').getRuntime().exec('calc')}.

Таким образом, можно выделить три обязательных условия для эксплуатации уязвимости:
  1. Должна быть определена связь (в stringLookupMap) между prefix и соответствующим классом. С использованием функции StringSubstitutor.createInterpolator будут по умолчанию установлены небезопасные префиксы: script, dns, url, file, env и соответствующие им классы.
  2. Должна быть вызвана функция replace (replaceIn) класса StringSubstitutor, в которой произойдет вызов функции lookup.
  3. При вызове функции replace (replaceIn) пользовательские данные должны записываться в ее аргумент source.

Как разработчик исправил уязвимость​

В патче к уязвимости было сделано следующее:

1. Изменен алгоритм заполнения связей prefix и классов (stringLookupMap) в функции addDefaultStringLookups класса StringLookupFactory. Теперь HashMap stringLookupMap заполняется коллекцией defaultStringLookups из экземпляра класса DefaultStringLookupsHolder.

099kjzy86lz8iiov2a8reg387h2zmyvy.png

2.Добавлен класс DefaultStringLookupsHolder,и в его конструкторе выполняется контроль ключа системного свойства org.apache.commons.text.lookup.StringLookupFactory.defaultStringLookups.

a. Если ключ отсутствует, формируются связи по умолчанию с помощью вызова функции createDefaultStringLookups;

b. Если ключ присутствует, формируются связи на основе значений ключа с помощью вызова функции parserStringLoookups.

dbjozx1hd2b482qo5ojhukbgfzdskd3x.png

3.Для случая формирования связей по умолчанию (функция createDefaultStringLookups) не создаются связи для prefix: script, dns, url.

az6j0bcomoao172el7duvzxhd32romsk.png

4.Для случая формирования связи на основе значений ключа org.apache.commons.text.lookup.StringLookupFactory.defaultStringLookups в функции parserStringLoookups по значению ключа сформируется список связей между prefix и классом. Значения должны соответствовать из перечня, заданного в enum DefaultStringLookup (например, BASE64_DEiR, SCRIPT).

5x7m77y5y76zoxgrpg3ewe8yymf2b1lr.png

Таким образом, внесенные изменения содержат следующее:
  • из списка связей между prefix и классом, который определяется по умолчанию, исключены: script, dns, url;
  • появился механизм определения списка связей между prefix и классом через указания соответствующего перечня prefix в ключе org.apache.commons.text.lookup.StringLookupFactory.defaultStringLookups (например, SCRIPT, URL, DNS).
Следовательно, можно утверждать, что патч для версии 1.10.0 библиотеки Apache Commons Text оставляет по умолчанию небезопасные prefix: file, env. Для включения уязвимых режимов обработки интерполяции (script, dns, url) достаточно записать соответствующие значения в поле org.apache.commons.text.lookup.StringLookupFactory.defaultStringLookups.

Это можно сделать несколькими способами:
  • в параметрах запуска приложения
Код:
java -Dorg.apache.commons.text.lookup.StringLookupFactory.defaultStringLookups=SCRIPT,DNS,URL text4j.jar
  • установкой свойства внутри кода с помощью функции System.setProperty:
rqaahjancrhdj37495km0gql69iemkft.png

Что делать дальше​

Из результатов рассмотрения уязвимости и варианта исправления от разработчиков можно сделать следующий вывод:
  • библиотека Apache Commons Text остается уязвимой и после обновления до версии 1.10.0. Все зависит от системного свойства, указанного в окружения приложения;
  • эксплуатация уязвимости этой библиотеки главным образом зависит от попадания пользовательских входных данных на вход уязвимых функций replace (replaceIn) класса StringSubstitutor. На текущий момент для пакетов, в которые включена библиотека Apache Commons Text, отсутствует публичная информация о том, что существует прямой канал передачи пользовательских данных в уязвимые функции, но расслабляться рано.
Следовательно, библиотека Apache Commons Text остается уязвимой, эксплуатация зависит от способов ее применения и отсутствуют гарантии в небезопасном использовании библиотеки внутри собственного продукта или внутри заимствованного пакета.
Поэтому предлагаем подготовиться к реагированию на такую уязвимость:
  • настроить правила фильтрации межсетевых экранов на наличие шаблона ${prefix:[options]:data} ;
  • выполнить контроль на наличие в составе проекта продукта уязвимой библиотеки Apache Commons Text и проводить такой контроль динамически (например, с использованием утилиты);
  • если библиотека присутствует в составе проекта:
    o обновиться до версии 1.10.0, в которой были изменены настройки по запуску небезопасного функционала по умолчанию;
    o проконтролировать в настройках окружения наличие включенных уязвимых режимов (scritp, dns, url, file, env);
    o провести статический анализ на возможность передачи входных пользовательских данных в аргумент source функций replace(replaceIn) класса StringSubstitutor. Это можно выполнить автоматически с помощью обновленной версии PT Application Inspector или же с использованием правил SemGrep.
    o выполнить санитизацию/экранирование входных пользовательских данных перед попаданием их в аргумент source функции replace (replaceIn) класса StringSubstitutor.
Правило SemGrep — создание StringSubstitutor через createInterpolator:
Код:
rules:
  - id: text4shell_via_createInterpolator
patterns:
- pattern-either:
- pattern: $INTERPOLATOR.replace(...);
- pattern: $INTERPOLATOR.replaceIn(...);
- pattern-inside: |
import org.apache.commons.text.$PKG;
...
$INTERPOLATOR = $PKG.createInterpolator(...);
...
message: text4shell $INTERPOLATOR.replace call found
languages:
- java
severity: WARNING
Правило SemGrep — создание StringSubstitutor через конструктор:
Код:
rules:
  - id: text4shell_via_createInterpolator
patterns:
- pattern-either:
- pattern: $INTERPOLATOR.replace(...);
- pattern: $INTERPOLATOR.replaceIn(...);
- pattern-inside: |
import org.apache.commons.text.$PKG;
...
$INTERPOLATOR = $PKG.createInterpolator(...);
...
message: text4shell $INTERPOLATOR.replace call found
languages:
- java
severity: WARNING

Автор : Positive Technologies
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх