InfraFenceInfraFence

Live Security Operations

Get Started

CVE-2021-44228 (Log4Shell): check and fix

Last updated:

Log4Shell is a remote code execution flaw in Apache Log4j 2, the logging library inside a large share of Java applications. When an application logs text that an attacker controls (a URL, a header, a form field) and the text contains a lookup such as ${jndi:ldap://…}, Log4j fetches and runs code from the attacker's server.

It was exploited within hours of its disclosure in December 2021 and is still scanned for every day. The library hides inside other software, so the work is to find every copy on the server, then update.

At a glance

CVE
CVE-2021-44228
Software
Apache Log4j 2 (log4j-core)
Affected versions
2.0-beta9 to 2.14.1, except the security releases 2.3.1 and 2.12.2 or later
Fixed in
2.15.0 (Java 8), 2.12.2 (Java 7), 2.3.1 (Java 6); upgrade to 2.17.1, 2.12.4 or 2.3.2 or later
CVSS score
10.0 Critical (NVD, CVSS 3.1) · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
CISA Known Exploited Vulnerabilities
Yes, added on December 10, 2021
Published by NVD
December 10, 2021
InfraFence virtual patch
vp-cve-2021-44228 (ModSecurity id 9920004)

What is affected

Only log4j-core from Log4j 2 is affected, and only from 2.0-beta9 up to the fix. Log4j 1.x is not affected by this CVE, but it reached end of life in 2015 and has flaws of its own. Java applications built on Log4j 2 (application servers, search engines, custom apps) carry the library in their own folders, often inside a .war or a fat .jar, not as a system package.

The first fix, 2.15.0, was incomplete in some configurations (CVE-2021-45046), and two further issues followed (CVE-2021-45105 and CVE-2021-44832). That is why the target today is 2.17.1 or later on Java 8, 2.12.4 on Java 7 and 2.3.2 on Java 6.

Check whether a server has it

Look for log4j-core files, then for archives that bundle it. The version is in the file name:

Any Linux distribution
sudo nice -n 19 ionice -c3 find / -xdev -type f -name 'log4j-core-*.jar' 2>/dev/null
Any Linux distribution (needs unzip)
sudo nice -n 19 ionice -c3 find / -xdev -type f \( -name '*.jar' -o -name '*.war' -o -name '*.ear' \) 2>/dev/null \
  | while read -r f; do
      unzip -l "$f" 2>/dev/null \
        | grep -qE 'log4j/core/lookup/JndiLookup\.class|log4j-core-[0-9][^/]*\.jar' && echo "$f"
    done

Note: -xdev keeps the search on the root file system. Run it again for each other mount where applications live (/opt, /srv), and check container images separately: a file inside an image is not on the host's disk.

For an application you build yourself, ask the build tool which version it really packages:

Maven project
mvn dependency:tree -Dincludes=org.apache.logging.log4j:log4j-core

To see whether someone has tried, search the web server's access logs for lookups (attackers also put them in headers, which these logs do not record):

Apache access logs
sudo grep -rhiE '\$\{jndi|%24%7Bjndi|\$\{\$\{' --include='*access*' --exclude='*.gz' /var/log/apache2 /var/log/httpd 2>/dev/null | tail -20

Fix it

  1. Software from a vendor: install the vendor's release that ships Log4j 2.17.1 or later.
  2. Your own application: raise log4j-core (and log4j-api) to 2.17.1 or later, or 2.12.4 on Java 7, 2.3.2 on Java 6, rebuild and redeploy. Check with the build tool that no other dependency pulls an older copy back in.
  3. Restart the application: a running JVM keeps the old classes until then.
  4. Run the search above again: no old log4j-core should be left, also in backups of deployed applications that might be redeployed.
Maven: pin the fixed version
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-core</artifactId>
  <version>2.17.1</version>
</dependency>

Warning: Setting log4j2.formatMsgNoLookups or removing classes by hand were stopgaps of December 2021, and the first of them does not cover every case. Treat them as temporary and update.

How InfraFence blocks it while you update

The virtual patch for CVE-2021-44228 is a ModSecurity rule that looks at the URL, the request headers, the cookies and their names, and the parameters and their names, after URL decoding. It blocks a request with a ${ followed within a few characters by jndi, or by the nested lookups used to hide it (${lower:, ${upper:, ${env:, ${sys:, ${date:, ${::-).

Note: The patch only sees HTTP requests that pass through Apache with ModSecurity on that server. A Java application reached on its own port, or a payload that arrives by another route (an email, a message queue), is not covered: the update is the fix.

How the patch is applied

  1. The agent notes which SSH ports and sites answer.
  2. It writes the rule (ModSecurity id 9920004) between its own markers in its ModSecurity file, runs apachectl configtest and reloads Apache gracefully. A failed test puts the previous file back.
  3. It checks that SSH and the sites still answer, and removes the patch if they do not.
  4. It checks that ModSecurity really blocks with the rule, with a harmless local probe request. A ModSecurity in DetectionOnly only logs: the patch is then removed and reported as ineffective, never as applied.

Every request the patch blocks is reported with CVE-2021-44228 (agent 1.0.37 or later): you see the attempts on the server's activity and on the Exploitation page of the dashboard, so you know the vulnerability is being tried against you.

Warning: A virtual patch blocks the known form of the attack on the requests that go through Apache on that server. It is not a substitute for the update: install the fixed version, then remove the patch from Activity with Undo if you no longer need it.

Virtual patches need Apache with ModSecurity, the setting Allow web server configuration changes, and no hosting panel or configuration manager in charge of the web server; they are part of the Pro plan and AutoMode. A person applies them from the AI analysis, or AutoMode does. See Virtual patches.

Sources

The facts on this page come from these sources; check them for changes.

Try it free on 1 server

Starter is free for one server, with full protection and automatic blocking. No credit card.

Install the agent as root, with your token in place of <TOKEN>:

curl -fsSL https://github.com/infrafence/infrafence-agent/releases/latest/download/install.sh | sudo bash -s -- --token <TOKEN>

The token is created in the dashboard, in Servers › Add server.