Updated: Understanding log4j2 vulnerability (CVE-2021-44228 + CVE-2021-45046 + CVE-2021-45105)
On December 10, 2021, cyberspace got flooded with a critical vulnerability in the popular java-based logging package log4j. The vulnerability is now called Log4Shell and published as CVE-2021-44228 with a CVSS v3 score of 10 - which is already the highest risk score. The vulnerability, if exploited, could allow attackers to obtain remote code execution (RCE), thus providing them an opportunity to execute arbitrary commands on the remote server.
This blog post aims to share details and the required workaround to understand the log4j2 vulnerability (CVE-2021-44228). Currently, the critical vulnerability is exploited in the wild, and bad actors are actively scanning cyberspace for vulnerable assets. Apache log4j is also used in many frameworks such as Apache Struts 2, Apache Druid, Apache Flink. Spring and Spring Boot applications are only vulnerable to the flaw in case they have switched the default logging system to Log4j2.
The patch to fix the vulnerability was released earlier in v2.15.0 but later on, it was disclosed that the fix had some vulnerability traced to (CVE-2021-45046) with CVSS score 3.7 which existed due to incertain non-default configurations. As soon as the flaw was discovered in v2.15.0, a new patch update of log4j v2.16.0 was promptly released by Apache. But later on, v2.16.0 was found vulnerable to CVE-2021-45105, DoS attack. Consequently, Apache has released another patch update v2.17.0 to mitigate the new vulnerability in v2.16.0.
If you use Java-based products that use log4j, you should do the remediation as soon as possible to mitigate the risk.
What log4j is, and how is it vulnerable?
Log4j is a Java-based logging framework (APIs) distributed under the Apache Software License. Today, it is being used in a wide range of cloud services, enterprise applications, tools, and frameworks such as Apache Struts 2, Apache Druid, Apache Flink, etc.
Log4j uses multiple lookup plugins to access various information. Back in 2013, the log4j version 2.0-beta9 added the JNDILookup plugin to its framework. The JNDI (Java Naming and Directory Interface) is a directory service that allows Java programs to find Java objects through a directory such as LDAP (Lightweight Directory Access Protocol), and it has been present in Java since the late 1990s. At the same time, Lookups provide a way to add values to the Log4j configuration at arbitrary places.
Most of the time, the plugins do not create any insufficient scenarios as the obtained values are stored in the application log and usually not displayed. However, in the case of this vulnerable version of log4j, the attacker can call the information and log it while using the JNDI to connect to an instance using an LDAP URL and log it.
Once the attacker knows the input is logged with log4j, he can set up an LDAP server and return a compiled class file to execute malicious code on the remote system; this attack can be further stealthy by hiding the input in the HTTP call header since they are often logged by the app servers using log4j. Here’s to remember that the attacker only needs to trigger a log event that contains a malicious string to exploit the vulnerability and once it is done, it would allow an attacker to remotely execute codes on the server.
The flaw was triggered because the message lookup substitution was enabled, allowing the attacker to control the log message or log parameters. The simplest way to remediate the vulnerability was to upgrade to the log4j v2.15.0, which then by default, disable the lookup behavior. CVE-2021-4428 affected the log4j version 2.0-beta9 and <= 2.14.1 and was patched by the maintainers in the log4j 2.15.0 update.
However, on December 14, 2021, it was found that the fix to address CVE-2021-44228 in Apache Log4j 2.15.0 was incomplete in certain non-default configurations. The previous mitigations involve configuration such as setting the system property log4j2.formatMsgNoLookups to true, but in the case of v2.15.0 update, it does not mitigate this specific vulnerability i.e., CVE-2021-45046 entirely.
The flaw in the v2.15.0 could allow attackers with control over Thread Context Map (MDC) input data when the logging configuration uses a non-default Pattern Layout with either a Content Lookup (for example, {ctx:loginId}) or a Thread Context Map pattern (%X, %mdc, or%MDC) to craft malicious input data using a JNDI Lookup pattern resulting in a denial of service (DOS) attack.
As soon as v2.16.0 was released and become available to remediate the missing security countermeasure in v2.15.0, independent security researchers discovered that Apache log4j2 versions 2.0-alpha1 through 2.16.0 did not protect from uncontrolled recursion from self-referential lookups. The vulnerability was immediately traced to CVE-2021-45105 with CVSS 7.5 and high severity, which could allow attackers to trigger a Denial of Service (DoS) attack. Though the JNDI lookups were previously disabled in the v2.16.0, however, under certain circumstances the previous version can be fed patterns that are infinitely recursive.
As published by Apache, “when the logging configuration uses a non-default Pattern Layout with a Context Lookup (for example, {ctx:loginId}), attackers with control over Thread Context Map (MDC) input data can craft malicious input data that contains a recursive lookup, resulting in a StackOverflowError that will terminate the process. This is also known as a DOS (Denial of Service) attack.”
How to mitigate the Log4Shell vulnerability?
-
The flaw was triggered because the message lookup substitution was enabled, allowing the attacker to control the log message or log parameters. The simplest way to remediate the vulnerability is to upgrade to the log4j v2.17.0, which now, by default, disable the lookup behavior. CVE-2021-4428 affects the log4j version 2.0-beta9 and <= 2.14.1 and is patched in the latest update.
Note: The flaw doesn’t impact the 1.x versions, but since they have been end-of-life for six years, it is not recommended to use them either. Moreover, the same flaw does not impact spring boot apps as they use log4j-to-slf4j and log4j-api. -
In case the upgrade is not possible, then set the system property of Java parameter log4j.formatMsgNoLookups to true instead of false Also, the mitigation can be done by removing the JndiLookup class from the classpath. This can be achieved by running a commandlike
zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
-
If you are unsure how many of your custom-developed applications are vulnerable, use the software composition analysis tool (SCA) to identify whether log4j2-core libraries are used or not.
-
Configure your WAF rules to block the JNDI calls. Consult your WAF documentation or contact your vendor for more details. This it establish defense in depth, don’t just rely on WAF.
-
Not sure which servers and other 3P apps are using Log4j, login to your server and use a search query like
find / -name "*log4j*2*"
to identify if vulnerable version of log4j is in use. -
If you use GrayLog or Splunk, setup alerts on JNDI calls and immediately block the offending IP addresses.
-
In version 2.16.0 Log4j disables access to JNDI by default. JNDI lookups in configuration now need to be enabled explicitly. Also, Log4j now limits the protocols by default to only java, ldap, and ldaps and limits the ldap protocols to only accessing Java primitive objects. Hosts other than the local host need to be explicitly allowed. The message lookups feature has been completely removed. -
Users requiring Java 7 should upgrade to release 2.12.2 when it becomes available (work in progress, expected to be available soon). In version 2.12.2 Log4j disables access to JNDI by default. Usage of JNDI in configuration now needs to be enabled explicitly. Calls to the JndiLookup will now return a constant string. Also, Log4j now limits the protocols by default to only java -
The message lookups feature has been completely removed. Therefore, the issue can be mitigated in prior releases by removing the JndiLookup class from the classpath -
Java 8 (or later) users should upgrade to release 2.17.0. https://logging.apache.org/log4j/2.x/
-
Mitigate and harden the known vulnerable services (where the vendor has stated possible Remote Code Execution attack)
-
In PatternLayout in the logging configuration, replace Context Lookups like ${ctx:loginId} or $${ctx:loginId} with Thread Context Map patterns (%X, %mdc, or %MDC).
-
Otherwise, in the configuration, remove references to Context Lookups like ${ctx:loginId} or $${ctx:loginId} where they originate from sources external to the application such as HTTP headers or user input.
-
Remove the Log4j lookup capability
-
Disable lookups via properties
-
Upgrading your JDK isn’t enough, it is important to monitor projects using auto-PR support
-
Add WAF rules to block malicious inbound requests
-
Filter/Restrict egress RMI and LDAP protocols and ports
Things to remember
-
Log4j 2.15.0 restricts JNDI LDAP lookups to localhost by default. Previous mitigations involving configuration such as to set the system property log4j2.noFormatMsgLookup to true do NOT mitigate this specific vulnerability
-
The flaw doesn’t impact the 1.x versions, but since they have been end-of-life for six years, it is not recommended to use them either. The same flaw does not impact spring boot apps as they use log4j-to-slf4jand log4j-API
-
Log4j on the .NET framework is not impacted at all. Only the log4j-core JAR file is impacted by this vulnerability
-
Applications using only the log4j-API JAR file without the log4j-core JAR file are not impacted by this vulnerability