Уязвимость LOG4J
Java-проект, демонстрирующий эксплуатацию уязвимости CVE-2021-44228.
https://user-images.githubusercontent.com/13152452/147803050-458593e9-4b54-4e1f-ba07-802866b9b43e.mp4
Требования
- Операционная система на основе Linux: я использовал Ubuntu Desktop 20.10 64 bits
- OpenJDK 17.0.1: Для сборки программы эксплуатации. Более новые версии также могут подойти.
- Oracle Java Development Kit (JDK) 1.8.0_181: Это необходимо для работы эксплуатации. Устанавливать его не обязательно, но проект требует его распаковки в корневой директории. JDK можно найти на странице Oracle Java SE 8 Archive Downloads (JDK 8u202 и более ранние версии).
- Apache Maven 3.6.3: Для управления зависимостями и создания jar-файлов. Более новые версии также могут подойти.
- Docker 20.10.12: Для управления контейнером, содержащим сервис для эксплуатации. Более новые версии также могут подойти.
- Docker-compose 1.29.2: Для помощи в оркестрации генерации образа, а также создания, выполнения и удаления контейнера. Более новые версии также могут подойти.
- GNU Make 4.3: В этом проекте используется Makefile для проверки и генерации обязательных файлов. Более новые версии также могут подойти.
- OpenBSD Netcat (также известный как nc): Для создания связи с захваченным сервером. Этот пакет можно установить через менеджер пакетов вашего дистрибутива Linux (например, apt).
- (Рекомендуется) IntelliJ IDEA Community Edition 2021.3.1: Если вы хотите посмотреть, что находится под капотом этих проектов, рекомендую установить эту IDE. И снова, более новые версии также могут подойти.
Выполнение
- Клонируйте этот репозиторий на локальную машину.
- Загрузите Oracle Java SE 8 Archive Downloads (JDK 8u202 и более ранние версии) и распакуйте его в корневой директории проекта. Оставьте его в каталоге
jdk1.8.0_181, созданном при распаковке.
- Запустите
make all, чтобы собрать все проекты и создать Docker-образ с уязвимым сервисом.
- Откройте три терминала и выполните следующие команды:
- Первый терминал:
make start-vulnerable-service, чтобы запустить Docker-контейнер с сервисом для эксплуатации. Сервис будет доступен через порт 8080 локальной машины.
- Второй терминал:
make start-nc, чтобы запустить TCP-слушатель, который будет ожидать установления соединения с захваченным сервером.
- Третий терминал:
make start-exploiter, чтобы запустить программу, которая поможет нам эксплуатировать уязвимость.
- После запуска третьего терминала программа эксплуатации предоставит URL для доступа. Вставьте его в браузер, чтобы начать эксплуатацию.
- Если всё прошло как ожидалось, браузер не получит ответа и останется в состоянии загрузки.
- Теперь проверьте второй терминал (тот, где был выполнен
make start-nc). Возможно, вы получили сообщение вида Connection received on 172.24.0.2 46638 (IP-адрес и TCP-порт могут отличаться от указанных здесь). Это означает, что эксплуатация сработала, и теперь у нас есть shell, подключенный к серверу/контейнеру Docker.
- Чтобы убедиться, что всё прошло как ожидалось, попробуйте выполнить команду
whoami. В ответ вы должны получить root.
- Теперь попробуйте выполнить
cat ../private-directory/my-secret-file.txt, чтобы увидеть, что произойдёт. 🙂
- Закончив возиться с сервером, нажмите
CTRL+C, чтобы закрыть соединение.
- Вы также можете нажать
CTRL+C в других терминалах, чтобы прервать процессы.
Как это работает?
Прежде чем ответить на этот вопрос, давайте рассмотрим процессы, создаваемые в ходе выполнения.

Docker-контейнер
Этот Docker-контейнер будет обслуживать простой HTTP-сервис, который принимает GET-запросы по пути /log с параметром input. Получив запрос, он выводит входные данные на консоль.
https://user-images.githubusercontent.com/13152452/147826880-8ee10391-bcb7-46d3-8d69-2f7ddb4a7b37.mp4
Для эксплуатации уязвимости требуются несколько специфических конфигураций:
- Версия Java Runtime Environment (JRE), используемая для запуска сервиса, —
1.8.0_181. Это необходимо, чтобы разрешить загрузку Java-класса из внешнего сервиса.
- Зависимости Java-проекта должны быть сильно изменены для замены стандартного
spring-boot-starter-logging:2.6.1 на spring-boot-starter-log4j2:2.6.1. Последний добавляет log4j-core:2.14.1 в проект, что является версией, уязвимой для CVE-2021-44228.

- Jar-файл сервиса был создан с помощью компилятора Java версии
1.8.0_181.
Программа Netcat (nc)
Здесь нет особых объяснений или настроек. Это простая программа для чтения и записи данных через протоколы TCP и UDP. Мы будем использовать её для прослушивания входящих TCP-соединений на порту 9001 (кто-то другой откроет это соединение для нас на стороне сервера. 😉).
После установления соединения все входящие данные будут выводиться на консоль. Также весь ввод с клавиатуры будет отправляться через это соединение.
Эксплуататор (Exploiter)
Вот где начинается самое интересное!
Эта программа включает в себя несколько шагов, необходимых для эксплуатации уязвимости. Давайте разберём их:
Аргументы выполнения
Для запуска этой программы нам нужно указать три параметра:
- IP-адрес/хост HTTP-сервера и Netcat: Для эксплуатации уязвимости нам понадобится IP-адрес HTTP-сервера относительно уязвимого сервиса, чтобы наш LDAP-ответ мог перенаправить его на загрузку скомпилированного Java-класса. Он также будет использоваться самим Java-классом для открытия TCP-соединения с Netcat (объяснено выше).
- Порт HTTP-сервера: Порт, на котором HTTP-сервер, отвечающий за отправку скомпилированного Java-класса, будет принимать соединения. Он также будет отправлен вместе с LDAP-ответом, чтобы указать порт, с которого будет загружен скомпилированный Java-класс.
- Порт Netcat: Порт, на котором Netcat прослушивает соединения. Он будет использоваться скомпилированным Java-классом для открытия TCP-соединения с Netcat.
Эксплойт Java-класс
Как только программа запускается, она записывает Java-код на основе шаблона. Этот шаблон требует два аргумента: IP-адрес и порт Netcat.
После записи кода программа компилирует его в бинарный файл класса с помощью компилятора Java (javac) версии 1.8.0_181. Это важно для сохранения той же версии кода, что и у эксплуатируемого сервиса.
Java-класс Exploit имеет довольно простую структуру. В его конструкторе есть инструкция, запрашивающая у операционной системы создание программы shell. После её создания класс открывает TCP-соединение с Netcat, связывает ввод/вывод shell и TCP-соединения и зацикливает выполнение виртуальной машины Java до тех пор, пока соединение не будет закрыто Netcat. После выхода из цикла конструктор продолжает работу, как будто ничего не произошло.
Программа Marshalsec
Эксплуататор открывает подпроцесс, запрашивающий выполнение Java-программы Marshalsec. Программа Marshalsec доступна в GitHub-проекте mbechler/marshalsec.