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:

How to configure JEST to test a Typescript React or NodeJS

Jest integration with Intellij Idea

This is an opinionated guide that would illustrate how to configure Jest for testing NodeJS/React projects written in Typescript. It assumes Typescript is already installed. For new projects or projects without Typescript, needless, to say this guide can still be used upon completing the initial project setup to add React and or Typescript. There is a lot of guides out there already for adding Typescript to your project already.

1. Install Jest and friends

yarn add --dev jest ts-jest @types/jest
# or
npm i -D jest ts-jest @types/jest

  1. ts-jest is a TypeScript preprocessor for jest – it lets you use jest to test projects written in TypeScript.
  2. @types/jest types, because jest is written in JavaScript

2. Configure the preprocessor for Jest

Configure JEST to use ts-jest as the preprocessor. By using ts-jest to auto create a configuration file named jest.config.js with then jest preprocessor configs:

npx ts-jest config:init

Initial default generated output:

//jest.config.js
module.exports = {
    preset: 'ts-jest',
    testEnvironment: 'node',
};    

3. A complete opinionated configuration for Jest

My full customisations, settings self descriptive:

//jest.config.js
module.exports = {
  roots: ["<rootDir>/src"],
  preset: "ts-jest",
  testEnvironment: "node",
  coverageDirectory: "coverage",
  testPathIgnorePatterns: ["/node_modules"],
  verbose: true,
  // collectCoverage: true, <--Not needed because this would be applied/not by scripts in the package.json below
  coverageThreshold: {
    global: {
      branches: 90,
      functions: 95,
      lines: 95,
      statements: 90,
    },
  },
  collectCoverageFrom: ["**/*.{ts,tsx,js,jsx}", "!**/node_modules/**", "!**/vendor/**"],

  coveragePathIgnorePatterns: ["/node_modules"],
  coverageReporters: ["json", "lcov", "text", "clover"],
};

Note collectCoverage: true must be true or passed as a flag e.g. jest --coverage for coverage to be collected regardless of the content of the other coverage related settings.

For more on configuring jest see the official configuring Jest here

4. Configure the test scripts your package.json:

{
    "scripts": {
        "test": "jest"
    }
}

Or with advance/opinionated customisations. Self-explanatory naming:

{
    "scripts": {
        "test": "jest --coverage",
        "test:watch": "jest --coverage --watchAll",
        "test:nocoverage": "jest",
        "test:watch:nocoverage": "jest --watchAll"
    }
}

Congratulations if you got this far. This is a one off set-up, you would rip the benefits in days to come. Follow-on below to rest your Jest configuration for testing your Typescript React or NodeJs project.

5. Test it

To verify all is well

  1. Write a simple class, and a test for it see the JEST examples.
// sum.ts
const sum = (a: number, b: number) => {
  return a * b; // currently red, fixme: to go green (TDD).
};
export default sum;


// sum.test.ts
import sum from "./sum";

describe("test add function", () => {
  test("adds 1 + 2 to equal 3", () => {
    expect(sum(1, 2)).toBe(3); // should fail, fix function under test above.
  });
});

Then run the tests with the following, note the commands are from the script configured above

  1. yarn test to run the tests with coverage
  2. yarn test:watch to continuously run the tests. Highly recommended particular when doing TDD (Test Driven Development)
  3. yarn test:watch:nocoverage to continuously run the tests with no coverage, faster feedback.
  4. yarn view:coverage hosts the reports as a static website, note serve needs to be globally installed: yarn global add serve

Example out put when I run yarn test:

yarn test Example console output with failing test.
yarn test example console output with failing test.

Go on fix the test, you know you want to if you have not already done so. Here is what the output should look like once all your test(s) are passing:

yarn test Example console output with passing test.
yarn test example console output with passing test.

Thank you! Enjoy!

-MM