Blogs

Blogs

Log4j2 vulnerability - Fixing the jar

Using marketplace override

The Apache Log4j project is now saying that setting -Dlog4j2.formatMsgNoLookups=true is not a 100% guarantee that you are protected from exploits. I think that currently no one has found a way to exploit the vulnerability on Liferay with -Dlog4j2.formatMsgNoLookups=true set but many prefer to be extra safe.

As it has been stated before, you're likely to find log4j2 in DXP 7.4 or in some marketplace apps in previous versions, elasticsearch connector being often quoted.

Among the mitigations, the log4j project quotes another option:

remove the JndiLookup class from the classpath: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class

https://logging.apache.org/log4j/2.x/security.html

Liferay has a feature that allows you to override any LPKG you may find under osgi/marketplace:

https://help.liferay.com/hc/en-us/articles/360018159991-Overriding-lpkg-files

I've tested this procedure with Liferay DXP 7.0 and the Elasticsearch 6 connector ans already shared it with customers.

I'll provide you with the detailed steps of the procedure and how I demonstrated that it is getting the job done.

First, I've run the lb command in the gogo shell to identify the bundle ID of the elasticsearch connector:

 642|Active     |   10|Liferay Portal Search Elasticsearch 6 Implementation (1.0.62)

And I've written this groovy script to test the classloading of the JndiLookup class:

import com.liferay.portal.scripting.groovy.internal.GroovyExecutor;
def bundle = org.osgi.framework.FrameworkUtil.getBundle(GroovyExecutor.class);
def esbundle = bundle.getBundleContext().getBundle(642);
def clazz = esbundle.loadClass("org.apache.logging.log4j.core.lookup.JndiLookup");
out.println(clazz);

The output of this script is the following:

class org.apache.logging.log4j.core.lookup.JndiLookup

We know that the class can be currently loaded in the bundle.

Using 7zip, I've opened the Liferay Connector to Elasticsearch 6.lpkg file in my osgi/marketplace folder and extracted the com.liferay.portal.search.elasticsearch6.impl-1.0.62.jar which I have copied to osgi/marketplace/override. I then renamed it as com.liferay.portal.search.elasticsearch6.impl.jar

Using 7zip again, I've browsed that jar until I've found log4j-core.jar and browsed down to the place where the JndiLookup class is located:

I've removed it and saved the archive with 7zip.

Note: Theoretically, you should use the jar command line (https://docs.oracle.com/en/java/javase/14/docs/specs/man/jar.html#:~:text=The%20jar%20command%20is%20a,command%20to%20create%20modular%20JARs.) to fix your jar but in my case 7zip did not corrupt the jar. If you run into issues, consider using the jar tool instead.

Then, I've restarted Liferay and discovered that it was useless unless you clean osgi/state. So please do it! :)

During Liferay's restart, you'll see this kind of log entries which is explaining that the original jar contained in the LPKG is ignored and replaced by the override:

2021-12-16 21:25:20.683 INFO  [main][ModuleFrameworkImpl:1604] Starting initial bundles
2021-12-16 21:25:21.529 INFO  [ModuleFramework-Static-Bundles-1][LPKGBundleTrackerCustomizer:626] Disabled Liferay Foundation - Liferay Connector to Elasticsearch 6 - Impl:com.liferay.portal.search.elasticsearch6.impl.jar
2021-12-16 21:25:22.737 INFO  [ModuleFramework-Static-Bundles-1][DefaultLPKGDeployer:426] Installed override JAR bundle LPKG-Override::D:\wk\cardif\bundles\osgi\marketplace\override\com.liferay.portal.search.elasticsearch6.impl.jar
2021-12-16 21:25:23.536 INFO  [main][ModuleFrameworkImpl:1888] Started initial bundles

I've run the lb command in the gogo shell gain and discovered that the bundle ID had changed:

 624|Active     |   10|Liferay Portal Search Elasticsearch 6 Implementation (1.0.62)

And I've run the same script but with this new bundle ID:

import com.liferay.portal.scripting.groovy.internal.GroovyExecutor;
def bundle = org.osgi.framework.FrameworkUtil.getBundle(GroovyExecutor.class);
def esbundle = bundle.getBundleContext().getBundle(624);
def clazz = esbundle.loadClass("org.apache.logging.log4j.core.lookup.JndiLookup");
out.println(clazz);

It failed and I could see this log on my Liferay server:

org.apache.logging.log4j.core.lookup.JndiLookup cannot be found by com.liferay.portal.search.elasticsearch6.impl_1.0.62

This is exactly what I wanted to achieve. If you browse the osgi/state directory looking for the log4j-core jar, you'll find it but it will not have the JndiLookup.class file.

Now, in order to make sure that I just don't have broken everything, I've tried to load a sister class:

import com.liferay.portal.scripting.groovy.internal.GroovyExecutor;
def bundle = org.osgi.framework.FrameworkUtil.getBundle(GroovyExecutor.class);
def esbundle = bundle.getBundleContext().getBundle(624);
def clazz = esbundle.loadClass("org.apache.logging.log4j.core.lookup.JavaLookup");
out.println(clazz);

And I got that output:

class org.apache.logging.log4j.core.lookup.JavaLookup

Works as expected!

If you want to be 100% sure to remove any attacking surface before being able to apply a Liferay fix, you may use this procedure.

The nice thing about it is that it is easy to reverse: just remove the jar in the osgi/marketplace/override directory, restart Liferay with a clean osgi/state folder and you've reversed that manual fix of yours.

Of course, I encourage you to test this procedure in QA environment to practice the procedure before going live.

hi 

why you don't just replace the jar to 2.17.0?

i try download log4j 2.17.0 and replace 3 jras in

<liferay home>/tomcat-9.0.53/webapps/ROOT/WEB-INF/shieded-container-lib

and

<liferay home>/elasticsearch-sidecar/7.10.2/lib

but i find there still have log4j-api-2.11.1.jar and log4j-core-2.11.1.jar in 

<liferay home>\osgi\state\org.eclipse.osgi\607\0\.cp\lib

still do not know how to fix it

Hello Scarletake,

I've opted for class removal because I did not check whether there were potential breaking changes with newer versions of the library.

Regarding your case, have you emptied the osgi/state directory before restarting Liferay?

Please also use the "b 607" command so as to check what the 607 bundle is.

Kind regards,

hi 

thank you for reply 

yes, i delete osgi/state directory before restarting Liferay, but after start up, it still there.

it looks like download by maven, but i do not know where can i change the config to make it download newest log4j jar.