BlackArrow’s Threat Hunting team uses a Minecraft server to illustrate the impact of Log4Shell from both an attacker’s and defender’s point of view
The JNDI injection attack affecting the Java component Log4j is having a significant impact on organizations, especially as it is such a common Java component that it may take longer to mitigate than is advisable. Beyond remediation or mitigation, the need for defensive layers capable of detecting this threat at the endpoint level is more necesary than ever. What options do security managers have when Log4Shell is being actively exploited on their assets?
To illustrate this attack and its perspective on both the attacker’s or Red Team‘s side and the defender’s side, we have used a server of the popular video game Minecraft Java Edition, as it uses a version of log4j that is vulnerable to this attack.
This is a simple and representative example of any Java application that makes use of the functions provided by Log4j. The attacker basically only needs to locate which user input parameters are logged by the Java engine via Log4j to execute code in the context of the vulnerable application.
Log4Shell threat telemetry and analysis
Under this scenario, the game chat is sent to Log4j, making it the ideal space to perform the injection. Our victim machine is an Ubuntu server that includes an EDR solution that will allow us to monitor the activity and generate enough telemetry to analyze threats.
On the attacker’s side, we have to prepare an LDAP server that includes the payload we want to execute on the target server. In this case, we will use a tool published by @pimps (https://github.com/pimps/JNDI-Exploit-Kit), a fork of the project created by @welk1n.
This tool receives the command that we want to execute on our target server as an argument and will package it in a malicious Java class that will be served on port 1389 (if we opt for the LDAP method) or 1099 (if we opt for RMI).
We can see that the tool itself divides the answer into different options, separated by unique links.
This substantially simplifies the attacker’s job, as he will have all the available options of the exploit depending on the version of JDK he has installed, as well as different alternatives for Tomcat 8.
In our scenario we already know that we have JDK 1.8 and we have trustURLCodebase enabled as true, so we will use the LDAP option to send it through the game chat.
Once the text message is sent, we see on the server-side that the message is indeed processed by the server as a JNDI resource, which will perform an LDAP query to the attacking server.
At this point, the malicious Java class is generated on the fly to execute the attacker’s desired command. For our scenario we want the vulnerable application to download and execute a reverse shell written in python.
The following image is a representative example of what the malicious class builts on the fly and how system commands are embedded:
As a summary, the previous code only decides whether the operating system is Windows or not and, depending on the result, it will execute system commands as an argument of cmd.exe or to /bin/bash.
Finally, the system command is executed and the reverse shell reaches the attacker listener:
Continuing with this scenario, we now take the role of a Threat Hunter and focus efforts on identifying the origin of this reverse shell from the telemetry generated during the attack.
We see that the telemetry is enough to identify the following facts:
• The origin of this reverse shell is the JAVA process, although the tool does not show which technique has been used to reach this execution.
• The process responsible for this reverse shell has made LDAP connections to the attacking machine just before the execution of the reverse shell.
• It is possible to identify all the system commands performed by the attacker from the Java child processes.
In addition, from defensive point of view, there are different topics to highlight:
• The proof of concept makes exclusive use of cmd.exe and bash to perform the execution. This does not mean that attackers do not incorporate additional binaries in their payloads and use other resources for execution (such as powershell or zsh, among others).
• TCP ports used in the proof of concept can be modified, so they should not be considered unique identifiers for this attack vector. However, the same ports can be used to identify whether the same proof-of-concept has been involved in the attack.
• The payload is executed as a different process running on top of Java, but the Java engine itself will always be responsible for all executions and connections.
The following searches, together with an analysis of their results, would be very helpfull to focus attention on a compromise hypothesis from the use of the Log4Shell proof of concept.
At a high level, the query to detect such an exploit would be as follows:
• Parent process=*java*
• Child process= any binary allowing code execution in the operating system (cmd, powershell, sh, bash, wscript,…)
• Connections from the *java* process to target ports related to the proof of concept (636, 389, 1099,1389,…)
A particular implementation of such a query for a known EDR is provided below, which could be trivial to be converted to other EDR/XDR technologies:
Connections made by the Java process
• Exclusions of internal addressing (in case only external attacks are of interest).
• Only common TCP ports are included to this attack are included (but the attack is not limited only to these ports)
event_simpleName=ProcessRollup2 FileName = *java*
| join max=0 aid TargetProcessId_decimal [search event_simpleName=NetworkConnectIP4 NOT RemoteIP IN (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8) RPort IN (636, 389, 1099,1389)
| rename ContextProcessId_decimal as TargetProcessId_decimal
| table TargetProcessId_decimal RemoteIP RemotePort_decimal aid]
Processes invoked from Java:
• Limit the search for Java child processes to binaries that allow code execution, including beyond those listed in the original proof of concept (more binaries may be included).
event_simpleName=ProcessRollup2 ParentBaseFileName = java FileName IN (cmd.exe, bash, sh, zsh, powershell.exe, wscript.exe, cscript.exe, mshta.exe, tcsh)
| table _time UID_decimal ComputerName UserName UserName GrandParentBaseFileName ParentBaseFileName FilePath FileName CommandLine
It’s foreseeable that this vulnerability will evolve as time goes by and more information becomes known. This is evidenced by the fact that Log4j 2.15, which is intended to fix the vulnerability, does not prevent Denial of Service attacks, as recently announced. Those products and developments that have upgraded to version 2.15 will also need to upgrade to version 2.16 which disables JNDI functionality by default.
This article is part of a series of articles about Log4Shell
- Log4Shell vulnerability CVE-2021-44228, the new cyber-apocalypse
- Tracking JNDI attacks: Hunting Log4Shell in your network
- Log4shell full picture: All the vulnerabilities affecting Log4j