Log4J zero-day exploit explained and proposed fixes – a Critical Security Vulnerability (CVE-2021-44228)

Overview

There is a new zero-day exploit of the famous log4j library reported and fixed in the latest version, 2.15.0.  In brief, this vulnerability is critical and can give the offender complete server control. For more, please see the Apache Log4j security page.   Everyone in the Java-sphere should be aware of it. Actually, no! Every engineer and information security personnel should take action (looking over to my .net and Javascript buddies who are giggling at another Java security issue and then realising by the end of this post that their Elasticsearch and Atlassian apps are affected). This post will attempt to explain the log4j security exploit, help you determine if you are compromised, how to fix the exploit, and crucially, how to ascertain that you have resolved the log4j security exploit.

The best evidence I have seen so far is that of a little bobby table LinkedIn exploit.

Quick specifics about the log4j-core

  • Log4J: The CVE-2021-44228 vulnerability affects only the log4j-core library.
  • Springboot: The bundle libraries log4j-to-slf4j and log4j-api in spring-boot-starter-logging are not affected according to Spring. Unless of cause you have swapped them out to directly use log4j-core or another logging library that transitively brings it in scope.
  • So far reports seems to suggest applications are only affected when user inputs are logged.
  • PS: Springboot says, v2.5.8 & v2.6.2 releases (due Dec 23, 2021) will contain the fixed Log4J version v2.15.0.

Although the affected versions are anything between 2.0-beta9 and 2.14.1, any beta versions of 2.15.* would be affected.  The most secure/”permanent” fix is to update your log4j library to 2.15.0 immediately.  Please see Maven Central and log4j security announcements or carry on reading. 

Am I affected?

Anyone running Java is affected.  With the assumption that you would have something at least in your application’s transitive dependencies that bring in log4j if you are not using it directly.  Best to assume you have it and act accordingly.  In practice, any java application that takes in a user input that may end up in a log is affected given that log4j is ubiquitous in the java community! 

How to tell which version of Log4J library I have

You can use your dependencies managers like Maven or Gradle to print out all your dependencies and their versions to verify what version of Log4J you have.

For example, for Gradle:

# execute, logging out only the log4j dependency lines
./gradlew dependencies | grep “log4j”

Also, note you can right-click on your pom.xml or build.gradle file in popular IDEs like IntelliJ then chose to “generate visual dependency graph” / “effective dependency”

How to fix the log4J zero-day secuirty exploit

Example fix of the Log4j zero day exploit for Maven

# Override the log4j dependency of a Springboot project
<properties>
    <log4j2.version>2.15.0</log4j2.version>
</properties>

# And then verify the override works
./mvnw dependency:list | grep log4j

Example fix of the log4j zero day exploit for Gradle

# Via gradle's platform support add
implementation(platform("org.apache.logging.log4j:log4j-bom:2.15.0"))

# or for those with Springboot simply set the log4j's version
ext['log4j2.version'] = '2.15.0'

# And then verify the override works
./gradlew dependencyInsight --dependency log4j-core

Where upgrading the dependency is not possible

A workaround exists for some versions, such as releases >=2.10, by setting either the system property log4j2.formatMsgNoLookups or any of the following:

# In the JVM.Options file, add this:
‐Dlog4j2.formatMsgNoLookups=True
# or set the environment variable:  LOG4J_FORMAT_MSG_NO_LOOKUPS=true
# or simply run the application with (you may need to add quotes, depending on your shell . i.e "true")
java -Dlog4j2.formatMsgNoLookups=true -jar myapplication.jar

Popular applications affected by the log4J critical vulnerability

If you think you are not affected, have a look at this flavour of applications that would be affected:

  • Libraries:
    • Spring Boot
    • Struts
  • Apps
    • Solr
    • ElasticSearch
    • Kafka
    • Logstash
    • Jira
    • Confluence
    • Stash
    • Bamboo
    • Crowd
    • Fisheye
    • Crucible 
  • Server:
    • Steam
    • Apple iCloud
    • Minecraft

Yes, that’s almost any good Java application out there…

As a final reminder, this vulnerability is classed as critical by Apache.  Apache describes a Critical vulnerability as one “which a remote attacker could potentially exploit to get Log4j to execute arbitrary code (either as the user the server is running as or root). These are the sorts of vulnerabilities that could be exploited automatically by worms”.  Here are additional resources for you on the recent Log4J security vulnerability:

Upgrading from a Spring boot application with JUnit 4 to JUnit 5, Jupiter

I realised this is only doable with spring 5

To migrate from JUnit 4 to JUnit 5 you can replace @RunWith(SpringRunner.class) with @ExtendWith(SpringExtension.class).

Unfortunately, spring-boot version 1.5.9-RELEASE is based on Spring 4 and the SpringExtension is only available since Spring 5.

Source: https://stackoverflow.com/questions/48019430/junit5-with-spring-boot-1-5

and  http://www.baeldung.com/junit-5-runwith

 

Current dependency:

Exclude the transitive Junit 4 dependency from the Spring boot test dependency

Current:

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-test</artifactId>
 <scope>test</scope>
</dependency>

After:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
  <exclusions>
    <exclusion>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
    </exclusion>
  </exclusions>
</dependency>

 

This will break all your imports with of junit in your test classes. And your vigilant IDE should be compalining already about these.

import org.junit.Test;
import org.junit.runner.RunWith;

Down also goes your tags:

@RunWith(SpringRunner.class)
@Test

You should now be able to use your IDE assist features to generate add teh depency to your pom like show in the following image for intellij.  Or simple copy the depency from the pom snippet below.

add_junit5_to_classpath

 

Snippet here of dependecny

 

Make things easy and do a global find/replace:

import org.junit.Test; ->  import org.junit.jupiter.api.Test;

import org.junit.runner.RunWith; –> import org.junit.jupiter.api.extension.ExtendWith;

import org.springframework.test.context.junit4.SpringRunner; –>

@RunWith(SpringRunner.class) –> @ExtendWith(SpringExtension.class)

 

 

 

 

 

TypeScript is great but I just want to write my Angular2 app in Java8

angular2boot intellij Idea

angular2boot intellij Idea
angular2boot intellij Idea

 

It is really hard to look at any other alternative to TypeScript for Angular2 development. Not only is it easy to learn it is also far less error prone compared to developing in JS as you get static type checking for classes, interfaces and so on.

Sometimes you just want to write Angular2 app in java8 and hopefull java9 soon.  This is particularly a non-brainer if it’s only a small application where in splitting the app into multiple component/tiers (WebClient, Service & Backend REST-API) is not really worth the overhead.

I just want to write my Angular2 app in Java8

Enters Angular2Boot

  • Write angular2 app in java8
  • Framework built on top of Angular 2, GWT and Spring Boot
    • Gwt used to compile to JS
    • You are free to mix GWT and Angular, but why if not to deal with legacy only.

Benefits

  1. TypeScript is good but here you get an even stronger typed OO language in Java
  2. Numerous tried and tested tooling and IDEs aroung for java.
  3. And for when you need one single jar, nothing better than one uber springboot jar! Not to mention the simplicity and ease of Springboot, especially when building POCs
  4. And lets face it, java is the language of choice for building robust applications

 

Give it a try (5minute)

 

Create Project

Generate Angular and Gwt App from archetype template

mvn archetype:generate \

 -DarchetypeGroupId=fr.lteconsulting \

 -DarchetypeArtifactId=angular2-gwt.archetype \

 -DarchetypeVersion=1.6
  • This will then do the scanning and downloading of dependences etc. You’ll then be prompted to feed in a few more details:
# Define value for property 'groupId': com.mosesmansaray.play
# Define value for property 'artifactId': angular-gwt-in-java8-example
# Define value for property 'version' 1.0-SNAPSHOT: :
# Define value for property 'package' com.mosesmansaray.play: :
  • Then confirm properties configuration to complete

Install

To install/produces and executable fat jar

mvn clean install

  • The above will complete the download of further dependences needed to compile the application.
  • It should then be ready in your application target folder e.g.

/angular-gwt-in-java8-example/target/angular-gwt-in-java8-example-1.0-SNAPSHOT.jar

Run

To run the fat jar

java -jar target/angular-gwt-in-java8-example-1.0-SNAPSHOT.jar

Development

Developing/Live reload

  • Backend mvn spring-boot:run
  • Frontend mvn gwt:run-codeserver

Resources

  1. Documentation and More From Here at lteconsulting.fr
  2. Libary SourceCode
  3. Or checkout Arnaud Tournier’s talk at GWT con 2016 bellow:
    1. Youtube quick run through
    2. Speaker Decks
  4. Angular2boot Tour of Heroes Tutorial
  5. Demos on github
  6. The angular2-gwt.archetype

Lean Maven Release

The Lean Maven Release (AKA Maven Release on Steroids)
Simply put to get rid of Maven Release Plugin’s repetitive and time wasting inefficient builds and multiple checkins to SCM script this process to:
mvn clean
mvn versions:set
mvn deploy
mvn scm:tag
This can be setup in both Jenkins and Team-city.  I have been able configured this within a few minutes replacing my teams Maven Release Plugin.  This is a huge time safer and more people really need to do this especially within true Continuous Delivery team or any type of setting with frequent need for builds.

Benefits

 So how big exactly was the improvement of Releases On Steroids over the Release Plugin?

See for yourself

Releases on Steroids Maven Release Plug-in
Clean/Compile/Test cycle 1 3
POM transformations 0 2
Commits 0 2
SCM revisons
1 (binary source tag)
3

See more at Axel Fontaine’s blog where I first came across this piece of treasure after manager tipped me about it.

 

A Typical Fix

Typically The following is all I ever need to add on any project to getting maven on steriods pattern working

Add the Properties

...
<maven.compiler.plugin.version>3.1</maven.compiler.plugin.version>
<maven.release.plugin.version>2.5</maven.release.plugin.version>
<maven.source.plugin.version>2.2.1</maven.source.plugin.version>
<maven.javadoc.plugin.version>2.9.1</maven.javadoc.plugin.version>
<maven.gpg.plugin.version>1.5</maven.gpg.plugin.version>
...

Deployment path settings

... Local deployment
<distributionManagement>
    <repository>
        <id>internal.repo</id>
        <name>Internal repo</name>
        <url>file:///${user.home}/.m2/repository/internal.local</url>
    </repository>
</distributionManagement>
...
... or Remote deployment
<distributionManagement>
    <repository>
      <uniqueVersion>false</uniqueVersion>
      <id>corp1</id>
      <name>Corporate Repository</name>
      <url>scp://repo/maven2</url>
      <layout>default</layout>
    </repository>
</distributionManagement>

Apache maven plugins

<pluinManagement>
<plugins>
...
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>${maven.compiler.plugin.version}</version>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-release-plugin</artifactId>
    <version>${maven.release.plugin.version}</version>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-source-plugin</artifactId>
    <version>${maven.source.plugin.version}</version>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-javadoc-plugin</artifactId>
    <version>${maven.javadoc.plugin.version}</version>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-gpg-plugin</artifactId>
    <version>${maven.gpg.plugin.version}</version>
</plugin>
...
<plugins>
...
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-release-plugin</artifactId>

    <configuration>
        <useReleaseProfile>false</useReleaseProfile>
        <releaseProfiles>release</releaseProfiles>
        <goals>deploy</goals>
    </configuration>
</plugin>
<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <outputDirectory>${project.build.directory}/releases/</outputDirectory>
        <descriptors>
            <descriptor>${basedir}/src/main/assemblies/plugin.xml</descriptor>
        </descriptors>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.3</version>
    <configuration>
        <source>${java.version}</source>
        <target>${java.version}</target>
    </configuration>
</plugin>
<plugin>
    <artifactId>maven-clean-plugin</artifactId>
    <version>2.6.1</version>
    <configuration>
        <filesets>
            <fileset>
                <directory>overlays</directory>
                <includes>
                    <include>**/*</include>
                </includes>
                <followSymlinks>false</followSymlinks>
            </fileset>
        </filesets>
    </configuration>

</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-deploy-plugin</artifactId>
    <version>2.8.2</version>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-source-plugin</artifactId>
    <version>2.4</version>
</plugin>
...

The Release Profile

The Maven Release profile will be infered to for the maven deploy option

<profiles>
...
    <profile>
        <id>release</id>
        <properties>
            <activatedProperties>release</activatedProperties>
        </properties>
        <build>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>${maven.compiler.plugin.version}</version>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-release-plugin</artifactId>
                        <version>${maven.release.plugin.version}</version>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-source-plugin</artifactId>
                        <version>${maven.source.plugin.version}</version>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-javadoc-plugin</artifactId>
                        <version>${maven.javadoc.plugin.version}</version>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-gpg-plugin</artifactId>
                        <version>${maven.gpg.plugin.version}</version>
                    </plugin>
                </plugins>
            </pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-source-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>attach-sources</id>
                            <goals>
                                <goal>jar</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-javadoc-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>attach-javadocs</id>
                            <goals>
                                <goal>jar</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-gpg-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>sign-artifacts</id>
                            <phase>verify</phase>
                            <goals>
                                <goal>sign</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>
...


Assemly description

And the plugin assemly description xml.  Location: src/main/assemblies/plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<assembly>
    <id>plugin</id>
    <formats>
        <format>zip</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <useTransitiveFiltering>true</useTransitiveFiltering>
            <excludes>
            </excludes>
        </dependencySet>
    </dependencySets>
</assembly>

Note if you intend to sign the package with the GPG plugin you’ll need to further configure this for your environment. I will write a seperate blog for this later. You may skip it with the bellow:

mvn deploy -Prelease -Dgpg.skip=true

Thats It!