Log4J Vulnerability — Attack & Defence Strategy for Cyber Analysts

Sachin Verlekar
10 min readDec 24, 2021
Photo by Kevin Ku on Unsplash

OVERVIEW

Log4j vulnerability or Log4Shell (Officially Coded: CVE-2021–44228 / CVE-2021–45046 / CVE-2021–4104) is one of the most dangerous security flaws found in the various Java based applications. This security loophole (CVE-2021–44228) is considered to be on the highest severity level i.e. Level 10 of CVSS (Common Vulnerability Scoring System) according to the National Vulnerability Database (NVD). Attackers have already started exploiting this Log4J vulnerability at very high rates and are reportedly attempting to target some of the popular applications such as Minecraft, Steam, NetEase, Apache Struts2, IBM QRadar SIEM, Elasticsearch, Ghidra SRE. There are studies which claim that some of the popular fortune companies such as Apple, Tencent, Twitter, Baidu, Cloudfare, Amazon, Apache, Google, Cisco, VMware etc. can be under the target. The full list of manufacturers / Components can be found here

What is Log4j?

In a nutshell, Log4j is a Java based framework or a library used for logging stuffs from your code that includes file-based errors, syntax error messages, debug messages etc. So these error messages can be looked up on the log file for figuring out the problem that is causing any kind of issue to the program or a standalone application. To be honest, java logging libraries have always been a little bit of a mess. Log4J have been in existence for quiet a long time now, but there was a dark secret which was hidden under the surface, which came into light after long time. Chances are, attackers might already have leveraged this vulnerability long before the vulnerability was actually reported. Any Java application that uses Log4J can be compromised. So anything lower than the recently patched version (i.e. v2.16 as of 16th December 2021) is severely vulnerable. This resulted in enterprises raising the patches for their Log4J functions and developers deploy the new versions of the application. We may think “Hey, we aren’t actually using Log4J, so we are safe”. Maybe you are wrong. Log4J is such a popular library that even if you aren’t using it directly you might be dependent on another library which actually uses Log4J for logging, or that library might depend on another library which uses Log4J. At this point, considering how popular Log4J is, there is a good chance that any decent sized Java application running out there probably has unpatched Log4J version integrated into it. Now, this vulnerability of Log4J is serious because of the possible Denial of Service Attacks (DDoS) which can lead to services availability violations and RCE (Remote code execution) which will allow the attackers to be able to run any code on your machine and further escalate privileges by hacking into your application.

Now there are 3 entities involved in this attack:

  1. Log4J Log Expressions

2. JNDI (Java Naming and Directory Interface) & LDAP (Lightweight Directory Access Protocol)

3. JNDI lookup in log messages

Log4J Log Expressions

Assume this Java code snippet:

Final Logger logger = LogManager.getLogger(…);

logger.error(“Error message: {}”,error.getMessage());

What you are doing here is, you are initializing the logger class and you are logging the simple error using the logger.error() method. What you’re also doing here is plugging in the error message from the error object into the string. So java is going to run this piece of code that’s going to get the error message and then send the value. Then log4j is going to detect error.getMessage() and plug into these curly braces and is going to print it as it is on a log terminal. Now as long as you’re passing in the valid expressions, this is a standard logging. So this itself is not a problem.

JNDI & LDAP

JNDI allows you to store java objects in a remote location and then serialize them. It’s kind of like streaming them to your JVM (Java Virtual Machine). As scary as this might seem, this is a technology that’s been around for a while. It’s safe to say that this was a Pre-Rest-API technology. Although this method has fallen out of popularity now, but it is still there in java.

Let’s assume a Java based Active Directory link:

ldap://192.168.1.22:8000/0=Sachin,C=India

This is an active directory link called LDAP URL. We can invoke this URL and get a serialized java object from somewhere else. In this case it will probably be my profile, object that I’m going to get from an active directory. This is basically a feature in java that’s been on the platform for years. You can disable it, in fact you’re encouraged to disable it, but it hasn’t been removed from java yet because java never deprecates anything and it strives for so much backward compatibility that even my great grandmother’s java code can run with the latest JVM and the latest java compiler. Anyway, it exists, most people leave it on and it’s harmless in and as of itself.

JNDI Lookups in Log Messages

Back in 2013, a contributor introduced a change to log4j that allowed you to do this kind of JNDI lookups from the logging message. A good use case for this would be if you have some kind of a centralized log configuration from a config server and you want to serialize that configuration using JNDI and have that affecting log messages like assume the logging path or prefix messages with a certain value etc.

You’ve seen string extrapolation and logging in the first code. Now imagine something like this with JNDI lookup in the following snippet.

Final Logger logger = LogManager.getLogger(Main.class);

logger.error(“Error message: {}”,”${jndi:ldap://logconfig/prefix}”,error.getMessage());

So what you’re doing here is you’re getting a prefix for the logging message from JNDI by passing the JNDI URL as an argument. You’re not just passing a value here, but you’re actually passing a string value. But this is not something that java resolves, this is something you’re passing to LOG4J. Basically the thing is LOG4J does lookups for certain types of string input. For example if you have any string like say “hello world” as shown in the following code snippet:

logger.error(“Some message for logging: {}”,”hello world”);

What this does is it basically inserts the string in the curlies, so you would see “some message for logging colon space hello world” in the log message. However if the string that you’re passing as an argument has this special syntax as shown in the below given snippet.

logger.error(“Lookup up value and inserts: {}”,${jndi:ldap://…}”);

This would be a clue for log4j to actually look it up. In this particular case, the actual string within the ${} is JNDI call, so it says okay this is a JNDI lookup. So it’s going to look up the value and it will execute that JNDI parameter as a lookup and insert the value in the double curlies instead of printing a normal log string.

Another example à Environment variables

logger.error(“Looks up value and inserts:{}”, “${env:ENV_VALUE}”);

Here ${} is wrapping an env:. So in this case, it realizes that this is an environment variable lookup. It is going to look this up and insert the value in the double curlies. And this is the exact vulnerability. Confused? Assume a search bar in the Java application and you are trying to find a keyword, but instead of a string, you type in the JNDI parameter. Obviously as an application validation you won’t find anything on the search bar. However behind the scenes, Your application will perform a JNDI request to the intended LDAP server containing a loaded exploit. The LDAP server can be a malicious server created by the attacker which can than be used to inject a backdoor on a hybrid application as shown on the below given image.

Log4J General Logging Procedure v/s Hacker’s Strategy to Leverage the Vulnerability

Normal Process of LOG4J Library Logging System
Hacker’s Strategy to perform an Attack on Java Based Application

Log4J Exploiting & Demonstration

For this Demonstration, I will be using Kali Linux 2021.3 on VMWare Workstation 16 Pro. Here we will perform the security testing on the Java based application named Ghidra. It is a software reverse engineering tool developed by the United States National Security Agency. My penetration testing shell script is available to clone/download on this repository. Check out the link given here → Link to git repository

Step 1 > Setup Local Server & NETCAT listener

To run the script type (./automation.sh). Select 2 to setup python local server. Open up the new terminal, run the script again and select 3 to setup reverse shell configured NETCAT listener.

What we are doing here is executing a local HTTP server on port number 8081. Since we want a loopback call for reverse shell while attempting to exploit the vulnerability using a JNDI lookup snippet, we will also be running a netcat listener which will run on port number 9090.

Step 2 > Run the Pentesting Tool

We have now selected the 1st option to perform LOG4J penetration testing. The URL/IP address of the server in this case, will be the loopback address. We can also type “localhost” and press enter. Port number of your server will the port number you have specified during the local server creation. Your local response listener will be the port number of your NETCAT listener.

Once you complete the above procedure, you should get the following output:

Step 3 > Run Ghidra tool

For Kali Linux Debian distribution, you can download the GHIDRA tool from here

NSA has already provided a fix to the GHIDRA SRE (v 10.1). However we will download and use the vulnerable version of the same. (i.e. 10.0.4)

Once you download, extract and configure GHIDRA SRE, we will run the tool as shown in the image given below. (Command to execute→ ./ghidraRun)

We will navigate the taskbar and click on Help tab → Contents which will open the following window. We will now click on the magnifying glass symbol on the left-hand side to find something on the directory search bar.

Step 4 > Perform JNDI lookup on a directory search bar

If you noticed carefully, in step 2 output, there was a JNDI lookup parameter which was generated for you. At the same time the rogue LDAP server was also initialized and is awaiting response from the application. All we need to do is copy the JNDI lookup parameter from the output which was generated and paste it on the directory search bar and hit enter. The image is shown below for reference:

Normally the find search bar is used to find the files and folders present in the directory. But the keywords that we are entering in the text-field is a JNDI Log4J parameter. So henceforth it will perform a JNDI lookup instead of search operation and send a response to my LDAP server. If you get a send LDAP exploit class response on your terminal at the end, this shows that your software has a loophole of CVE-2021–44228 LOG4J vulnerability. The output will be returned as shown in the following image:

Vulnerability Patching & Fixing

To rectify this major issue, we can also perform Vulnerability analysis and Patching using this tool. It is capable of patching all the latest LOG4SHELL vulnerabilities in all the Java based applications. It’s easy as pie to apply the patch. All it does is basically removes the JNDI lookup class file.

Step 1 > Select option 4 → Specify the directory of the vulnerable Java application.

Step 2 > You will now get the following message from the scanner

If you get a message with Found vulnerability with the vulnerability code, You will see the prompt below to apply the patch. Hit “y” and press enter. The patch will be applied. Time of applying patch will depend upon the number of vulnerable files present in the directory.

Try running the penetration testing module again, follow all the steps of exploitation and you will notice that after entering the JNDI lookup parameter, you are no more getting LDAP reference response from the application.

(As of latest update to my repository It can now generate a Vulnerability test report in the form of CSV file. Make sure you open with Libre-Office Calc or MS-Excel. This scan report will be saved automatically into your respective root directly of this repository.)

--

--

Sachin Verlekar

Computer Scientist | Blogger | CyberSecurity Analyst | Critical Thinker | Inquisitive | Universal Learner | Time-Travelling & Space Enthusiast