Why the Log4j Vulnerability is so Serious
Apache

Why the Log4j Vulnerability is so Serious

Log4j Issue

Everyone by now is likely familiar with the Log4j issue. If you haven't read about CVE-2021-44228, I recommend you immediately do so. I won't delve into the background of the exploit other than to disassemble it at a high level.

What strikes me most is the limitless number of potential exploit permutations that depends solely on what input a given application logs or doesn't log and where that input is ascertained from within the request. The myriad of possibilities is endless.

Where does the vulnerability reside?

The core issue lies in a fundamental logging engine used by many Java frameworks including Struts. Additionally, the popular logger is found in many enterprise applications. What makes this vulnerability so serious is that any element within the application that logs user input of any kind could potentially be an exploit vector. In fact, the component that is exploited may be deep in your application infrastructure, not just you edge web services. It could theoretically be exploited by a non-web interface as well. All your application needs to do is log user generated input.

This mean the vulnerability is in the logging mechanism itself:

logger.info("Expoit Variable {} Input", input)        

Imagine the hundreds of lines of JAVA code that logs values which come from user input in your applications!

Where could this vector be used?

While the most obvious place to see this exploit is in HTTP headers,?any portion?of a web request could contain the exploit. In fact, it doesn't even need to be a web request. An RPC protocol could just as easily carry this payload. That is because the issue is not in the transport protocol, but the logger infrastructure itself.

Headers, Cookies, Parameters, URI components, Body elements all could contain the malicious content. All that is required is that the parsed and post-processed element of the request is logged.

This means that compressed payloads, encoded payloads and even encrypted payloads could potentially carry the exploit. For example, if a JWT token was decoded to produce the right string outcome and an element of the post-decoded token values carried the malicious payload and was subsequently logged, then the exploit could be realized.

Additionally, what makes this so insidious is that many encoding methods could also mask the actual exploit including various web encoding formats, UTF encodings, base64 encodings, escape-character encodings, RPC protocol formats, inline obfuscations, etc. All that is required is that post decoding/processing output parameter containing the exploit is logged.

While the HTTP Header techniques are well understood, let's explore the following JWT token carrying the same exploit:

On the wire a JWT payload will look something like this:

No alt text provided for this image

After decoding the payload, the internal elements of the purple portion of the JWT token look as follows:

No alt text provided for this image

How many places in a Java application will the value of 'name' be potentially logged?

The 'name' exploit payload shown above could alternatively be found in form data or URI parameters. Failed login? Log the?username?value. This would be common design pattern in many applications.

While searching your web input for '${jndi:ldap:' might yield some script-kiddie-level protections, they will not protect you from the capabilities of this exploit vector and a clever attacker. As shown above, a JWT could just as easily carry the exploit in a manner that would obfuscate it from any inline inspection mechanism. Additionally, these types of tokens can also be encrypted, not just encoded and signed.

What this means is that any payload that is post-processed and then logged, anywhere in the execution path of the workload, could potentially carry this exploit. As a result, the permutations of where the exploit could be hidden are essentially infinite.

Inline Exploitation

One of the things that might not be immediately apparent is that it could be possible to chain an attack together that is done entirely inline and is very difficult to detect. For example, if both your web server and application server contain the Log4j vulnerability, one could potentially craft a multistage attack that hops across the nodes using existing / expected connections and then exfiltrates database entries without the need for shells or calls outside of the normal ones used within the application. This is because once the attacker controls both the Web and App Server components they can return any response they want to the original request.

Using the JWT example show above, you could imagine the 'user' parameter being propagated from the Web Server to the App Server and logged in both workloads. Alternatively, another parameter might be used to attack the second stage once the first stage is compromised and then the database information is exfiltrated using entirely existing connections and methods.

It might look something like this:

No alt text provided for this image


Inline Lateral Movement

Similar to the example above, an attacker can compromise a node, scan for adjacent vulnerable nodes on the network and then move laterally to that next node. All of which could be done from within the workloads themselves, requiring no external shells or additional function calls outside what the workload already performs. Given the proliferation of HTTP and REST as a communication protocol it would not be that hard to image doing this all with just web requests. Additionally, it has become commonplace to support HTTP health checks in Cloud-Native environments, making the likelihood of some HTTP mechanism being present in a workload probable. Of course, nothing prevents trying different protocols along the way given enough time to explore, scan and iterate.

This might look like the following:

No alt text provided for this image



How did this happen?

Log4j 2.0 introduces lookups, including JNDI

Log4j 2.0 added?lookup?capabilities including?JNDI:

No alt text provided for this image
No alt text provided for this image

The?Java Naming and Directory Interface?is a Java API used for a directory service that allows interfacing with LDAP, DNS, RMI, CORBA or any number of custom JNDI plugins to?lookup?resources and data.?As it turns out, one of the types that can be returned is a URI pointing to a Java class. This means that potentially malicious code could be downloaded and invoked inside your Java application at runtime.

A number of JDK versions will prevent the LDAP attack path as a result of the following parameter being set to false by default.

com.sun.jndi.ldap.object.trustURLCodebase = false        


Anatomy of an Exploit

Below is a high-level representation of the exploit being performed using a simple HTTP header payload and LDAP. As noted earlier this payload could be anywhere in the request and not just an HTTP header. Additionally,?LDAP is not the only mechanism?to complete the circuit. The core requirement is that the post-processed element containing the malicious payload is logged by?Log4j?and that a JNDI path is available to complete the circuit.

No alt text provided for this image


How to Remediate the Log4j vulnerability

The easiest way to address this is to update Log4j to version 2.15.0 or greater, as this behavior is now disabled by default in newer versions.

As noted, some JDK versions have the property set to prevent the LDAP exploit vector as noted earlier in the post. However, there could be potentially other JNDI paths that are not disabled and might still allow an exploitation to occur.

In versions between 2.10 and 2.15.0 this exploit vector can be prevented by setting the system property?log4j2.formatMsgNoLookups?to?true?by adding the following Java parameter:?-Dlog4j2.formatMsgNoLookups=true to the command line arguments and restarting the application.

Removing the?JndiLookup?class from the classpath would also mitigate the issue, however this might break a number of other components in the process that require this behavior to function.

Conclusion

  • Block all workloads from making outbound connections to network locations outside your datacenter to prevent the exploit download or completion of LDAP/DNS/RMI/CORBA (or other JNDI) circuit.?Micro-segmentation?systems can be helpful in mitigating this issue.
  • Update all Java software ASAP to remove the vulnerable logging code.
  • Do not solely rely on inline mechanisms to detect the payload within web requests. This will only catch the most obvious and trivial of attack vectors and will not mitigate non-HTTP exploit paths.
  • The exploit does not necessarily need to run shell commands. While a smash-and-grab operation might do this, a persistent attacker with enough time can use other means as shown in the high-level examples above that depict full in-app db-exfiltration and lateral movement approaches.
  • Malicious payloads could be anywhere within the requests including?encrypted?elements.
  • The delivery mechanism does not have to be?HTTP?although that is the most likely remote exploit method from remote attackers.
  • Attacks can be chained together to hop from one vulnerable node to another, including lateral movement, without ever needing to invoke system level code or shells outside the vulnerable application(s) themselves. This means that shell-execution protections from RASP software may prove ineffective.
  • LDAP is?only one possible exploit vector?and any number of other JNDI mechanisms could theoretically be possible including custom JNDI components, so keep a look out for those exploit paths.
  • Patching after exploitation?will not remove the attacker?from your systems. Monitor / block all inbound and outbound communications outside your datacenter once compromise is suspected.

要查看或添加评论,请登录

社区洞察

其他会员也浏览了