The world seems to go weird since the CVE-2021-44228 — a.k.a. Log4Shell or LogJam — RCE Vulnerability popped up in the news. It's surely nice to hear something not C19-related, but what are we actually dealing with? Well, this vulnerability might fall in the same severity as Shellshock does.
Warning (not again?!): CVE-2021-44832: Upgrade to Log4j 2.3.2 (for Java 6), 2.12.4 (for Java 7), or 2.17.1 (for Java 8 and later)
Indeed, again, third iteration, the severity score keeps decreasing, so that's nice… This CVE-2021-44832 exploits the JBDC appender to call a malicious JNDI URL.
Upgrade to Log4j 2.3.2 (for Java 6), 2.12.4 (for Java 7), or 2.17.1 (for Java 8 and later).
Warning (again): CVE-2021-45105: Upgrade to Log4j 2.17.0, do not use 2.16.0 or 2.15.0!
A new attack vector has been found in Log4j: CVE-2021-45105. Just two days have past since the 2nd leak found: CVE-2021-45046.
Upgrade to the latest 2.17.0 release, instead of 2.16.0 or 2.15.0.
Warning: CVE-2021-45046: Update log4j to version 2.16.0, do not use 2.15.0!
It took four days: CVE-2021-45046, the second Log4j2 vulnerability. This vulnerability allows for DOS attacks (certain configurations only).
Upgrade to the latest 2.16.0 release, instead of 2.15.0.
The vulnerability can be seen a bit as a log-poisoning attack (technically speaking not really, but yeah): Requesting a URL / Endpoint with a properly formatted payload, will add an entry into the logs for given application. The special payload needs to be "resolved" and this results in Remote Code Execution. It allows an attacker to execute any code on your system just by visiting a single page or posting a single comment. If you want to see this in action, I highly recommend having a look at John Hammond's video on Youtube. Also, watch LiveOverflow's video on YT to learn why Log4j is defective by design.
So, you've watched the videos? If not, do your homework!
The versions Log4j >=2.0-beta9 and <= 2.14.1 are affected. if you're using Log4j1, well, you're very out of date and affected by a different RCE bug. The Log4j2 package is used by many Java applications and is responsible for logging application events. When you call an endpoint running Java, it'll create a log entry of your request. A special feature called JNDI-lookup was added in 2013 — I'll light a candle for the developer that added this feature — and resolves parts of an entry into data that's retrieved from a remote system (LDAP, databases, and more). Since the remote system isn't validated, it'll happily call to your malicious server running a Java class that runs a remote shell for example.
The Vulnerability in Action
In our example, we'll be using some software chained together in the following format:
Let's set up our local exploit environment!
First, we need a Java payload that can be called when we connect to the LDAP server. Save the snippet below, for example as /tmp/poc/Exploit.java
.
In this snippet we'll execute touch /tmp/pwned
, but this command can be changed off course.
This needs to be compiled with the same version as the application you're exploiting. I'm using JDK 1.8.0_181. Use Google to search for a working download URL.
The Exploit we've just created needs to be hosted on a simple HTTP server, we chose port 8000
.
Next, using Marshalsec, we run our bad LDAP Server that in turn returns the Exploit.class
from our HTTP server.
This special LDAP server is the result of huge amounts of research and will form the link between our Exploit and the LDAP server that Log4j wil call.
Now we need a vulnerable target, for testing purposes only off course! If you have one in your network to test against, you can that.
In our case, we'll run a prepared docker container that exposes a sample vulnerable application on port 8080
:
Finally, we run our actual exploit against our target 127.0.0.1:8080
:
As you can see, this exploit uses the X-API-Version
header, for other systems you're probably better off using the User-Agent
header, since chances are that header is probably logged.
In our case, we're attacking a docker container, so let's see if /tmp/pwned
has been created:
If all went well, the file has been created and you've got a proof of concept for code execution.
Detection: Am I vulnerable?
Finding vulnerable packages
Both YfryTchsGD and NCSC-NL have very complete lists of software that's currently vulnerable, so that's a good place to start. And no, if you run Apache HTTP Server (httpd) you're NOT vulnerable, it's not Java, it's simply one of the many project's provided by The Apache Software Foundation.
You can simply list any remotely matching packages using your package manager, like dpkg -l apache* log*
and see if there's a match with these lists.
Finding vulnerable code
You can either search for log4j*jar
files in your code repository, or look in jar-archives META-INF/MANIFEST.MF
for Log4jReleaseVersion
:
Keep in mind this method probably returns false-positives.
Mitigation: Make me invulnerable!
Low hanging fruit
If possible, Update, Update, Update! Switch over to Log4j 2.17.0 (Java 8) or 2.12.3 (Java 7). Check with your software vendor in case software packages might use Log4j and see if they have updates. Anything Java-related is suspicious!
For Windows machines, ensure Windows Defender and Real-Time protection are enabled. You might add extra rules to your WAF to block certain requests, but keep in mind there's a lot of obfuscation going on that might be bypassed. You might also want to block malicious IP's on your Firewall, though this list is — obviously — always incomplete.
Check your log entries
You can simply check your logs for malicious entries, though this method probably will return some false-positives:
Above method should search for most WAF obfuscations as well, but might not include all latest variations. Alternatively you can use the log4shell-detector to a more thorough search, though it might be a bit slower.
Disable log4j2 or JndiLookup
You can disable the JNDI processing trough one the following methods:
-
Disable lookups in the
log4j2.xml
configuration (Log4j >= 2.10.0), for example:%m{nolookups}
-
Setting an argument when launching a program (Log4j >= 2.7 <= 2.14.1):
java -Dlog4j2.formatMsgNoLookups=true -jar archive.jar
orexport LOG4J_FORMAT_MSG_NO_LOOKUPS=true java -jar archive.jar
-
Remove the
JndiLookup.class
from jar files (Log4j >= 2.0-beta9 <= 2.10.0):zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
On Windows, you'll manually need to open alllog4j-core*.jar
files in a ZIP-program (e.g. 7zip), remove theorg/apache/logging/log4j/core/lookup/JndiLookup.class
file and save asjar
file again. -
Changing / setting Java system properties (I'm no Java developer, so please contact me if this is wrong):
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase");
System.setProperty("com.sun.jndi.cosnaming.object.trustURLCodebase", false);
Extra Sources
- Inside the Log4j2 vulnerability
- Log4Shell: JNDI Injection via Attackable Log4J
- Nortwave Log4j checker
- Leon Jacobs log4jpwn
- Find vulnerable log4j hosts: log4j-scan
- Pentesterland: Log4shell resources & technical details
Changes
- 2021-12-14
- First publication, initial research.
- 2021-12-15
- Added instructions to remove
JndiLookup.class
from jar-files on Windows systems. - Added alert for CVE-2021-45046 to upgrade to 2.16.0.
- 2021-12-20
- Added alert for CVE-2021-45105 to upgrade to 2.17.0, this hopefully is the last time now.
- 2021-12-30
- The sequel continues, added alert for CVE-2021-44832 to upgrade to 2.3.2 (Java 6) / 2.12.4 (Java 7) / 2.17.1 (Java 8+).
- Slightly changed explanation for disabling JNDI lookup techniques, to (hopefully) make them easier to understand.