Une mise à jour 2.3.1 de Log4j étant disponible pour les utilisateurs de Java 6, nous avons mis notre graphique à jour.
Log4shell (de son petit nom CVE-2021-44228) est un bel exemple de vulnérabilité qui maintient éveillé des équipes IT depuis plusieurs jours et dont on va parler un bon bout de temps. Au moins jusqu’à la prochaine alerte aussi sérieuse, dont personne n’est capable d’en prédire la nature ni la date de survenue.
Cela fait partie des charmes de l’informatique tout en contribuant au maintien d’un taux élevé d’ulcères chez les RSSI. Maintenant, bien qu’elle soit fondamentalement assez simple, il est intéressant de connaître les mécanismes de cette vulnérabilité, afin de comprendre pourquoi elle est aussi dangereuse.
Nous vous proposons donc un débrief complet, explications et schémas à la clé.
Log4J, c’est quoi ?
Il s’agit à la base d’une librairie bibliothèque écrite en Java pour des applications Java. Son rôle est de permettre une gestion unifiée et cohérente des logs applicatives, comme son nom l’indique (log4j signifiant « Log For Java »).
On voit donc que cela traite d’une fonction de base de toute application informatique, et cette librairie bibliothèque existe depuis un bon bout de temps, son implémentation ayant débuté en 1996. Rapidement intégrée par la fondation Apache avec une licence de type Apache Software License, elle est donc disponible en source ouverte et utilisable par n’importe quel projet informatique.
Tant et si bien qu’elle fut intégrée, au fil du temps, dans d’innombrables applications y compris par de très grands acteurs comme Google, Microsoft, Twitter, IBM, CloudFlare et bien d’autres
Version 1 et version 2
Cet utilitaire a ensuite vécu une histoire classique, avec l’apparition d’une version 2 à partir de 2012. L’équipe de développement a maintenu une branche 1.x en parallèle de la nouvelle, pour conserver une compatibilité ascendante, jusqu’en 2015 où il a été jugé que le maintien des deux versions devenait trop complexe.
La branche 1.x s’est arrêtée et n’a plus reçu aucune évolution, même pour corriger une faille de sécurité. D’ailleurs, une vulnérabilité (CVE-2019-17571) a été trouvée postérieurement à cet arrêt ; elle affectait les deux versions, mais n’a fait logiquement l’objet d’aucune correction sur la 1.x, et seule la branche 2.x a reçu un correctif.
Toute application utilisant encore aujourd’hui une version 1.x est potentiellement vulnérable à cette faille. Il s’agit d’un problème assez sérieux, du même genre que log4shell, mais avec des impacts légèrement moindres. Il n’affecte que les versions allant de 1.2 à 1.2.17.
JNDI et lookup
Java est très utilisé dans des architectures distribuées. Il est donc logique pour un composant Java d’en appeler un autre sur une machine distante. La JNDI (Java Naming and Directory Interface) permet d’aller récupérer un objet Java présent sur une machine distante, y compris très loin sur le réseau, comme le permet internet.
Il est donc légitime qu’un composant Java appelle un objet éloigné, qu’il retrouvera grâce à deux informations (constituant le contexte) :
- Son nom
- Le service d’annuaire où il est connu
Ce dernier peut être du type LDAP, RMI Registry ou même CORBA COS pour les plus téméraires. L’objet peut donc vivre sa vie, du moment qu’il signale son emplacement au service d’annuaire ; ainsi, un autre objet arrivera toujours à le retrouver avec son nom et l’annuaire approprié.
L’annuaire peut être situé n’importe où, du moment qu’il est accessible par le réseau. Une machine connectée à internet peut très bien aller chercher un objet Java en interrogeant un serveur LDAP placé en dehors de son réseau interne (si le réseau et le paramétrage le permettent) : gardez bien ce point à l’esprit pour comprendre log4shell. Un lookup est simplement la fonction qui permet de récupérer l’objet Java en utilisant son nom et le contexte adéquat.
Log4shell : LA faille (avant LES failles)
Des chercheurs en sécurité d’Alibaba Cloud ont découvert un comportement problématique de l'application log4j : par défaut, elle autorise JNDI et il était possible de faire un lookup en appelant un annuaire… externe !
On a vu que l’usage était légitime, mais depuis longtemps il est considéré comme prudent de se méfier de ce qui n’est pas sous contrôle et donc tout ce qui est en dehors du système informatique que vous gérez (il est même désormais de bon ton de ne faire confiance à personne, dans le cas d’une démarche Zero Trust).
Or, log4j n’avait pas pris de précaution particulière, ni établi de contrôle suffisant, tout en autorisant par défaut ces appels JNDI. Imaginons un vilain pirate qui se rend compte de la situation : il lui suffit d’envoyer un paquet de données (spécialement formé) que le serveur va loguer via log4j pour déclencher la vulnérabilité.
Voici comment :
- L’attaquant envoie le paquet préparé pour l’attaque (payload), par exemple dans le champ « nom d’utilisateur » d’un formulaire HTML, qu’on imagine aisément tracé sur les logs de l’application, mais toute information loguée ferait l’affaire (un entête HTTP peut suffire) ;
- Le serveur reçoit l’info et écrit, via log4j, dans les logs de l’application ;
- Le payload contient un appel JNDI (la syntaxe est basique) : log4j va alors réaliser ce lookup et aller chercher l’objet désigné qui sera injecté dans le processus du serveur cible.
Sous la forme d'un graphique, cela donne le résultat suivant :

Bien évidemment, le pirate a conçu son payload en demandant d’aller chercher un objet Java malveillant sur un annuaire qu’il contrôle. En clair, on dit presque directement au serveur d’aller chercher le malware sur internet…
Pourquoi c’est si grave
Les failles reçoivent souvent, en plus d’une identification, une indication de dangerosité : un score allant jusqu’à 10 permet de savoir s’il faut trembler devant la vulnérabilité ou pas. Pour log4shell, on trouve :
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Traduction en clair : log4shell reçoit un 10/10, car la faille est à la fois facile à exploiter et ravageuse, les impacts pouvant être dramatiques. En effet, le charabia ci-dessus signifie que :
- Le vecteur d’accès est le réseau (toute machine accessible peut être touchée) ;
- La complexité de l’attaque est très faible (il suffit d’envoyer un paquet de données assez trivial pour déclencher l’attaque) ;
- Aucun privilège n’est nécessaire (inutile d’être identifié, authentifié, habilité) ;
- Aucune interaction utilisateur n’est nécessaire (pas de lien à cliquer, d’application à ouvrir)
- Les impacts sont énormes (on peut altérer la confidentialité des données, leur intégrité, leur disponibilité, donc en résumé on peut tout faire sur le serveur ciblé).
Ajoutez à cela la popularité de log4j et vous vous retrouvez avec la faille la plus dangereuse depuis un moment.
Et après ? Ça continue ?
Les développeurs de log4j ont agi très rapidement après avoir été contactés par les chercheurs d’Alibaba Cloud. Ils ont corrigé la vulnérabilité dans la version 2.15.0 qui a été publiée dans la foulée le 6 décembre. Malheureusement, la correction était incomplète dans certains cas de figure, ce qui a valu une autre CVE, nommée CVE-2021-45046.
Elle fut considérée moins grave mais suffisamment pour qu’une nouvelle version soit relivrée le 13 décembre, la 2.16.0. Le score de gravité n’était plus que de 3,7 sur 10, car l’attaque était complexe et n’aurait comme impact possible qu’un déni de service (c’est-à-dire qu'il se situe au niveau de la disponibilité du système touché).
Pas de chance, comme cette bibliothèque log4j est maintenant scrutée par des milliers d’yeux fébriles, une nouvelle vulnérabilité (CVE-2021-45105) a été découverte dans la version 2.16.0 et corrigée par les développeurs. Cette fois la gravité est de 7,5 sur 10 selon Apache (avec un impact principalement sur la disponibilité). Le résultat reste qu'à l'heure actuelle la version à mettre en place est bien la 2.17.0, même si on a déjà migré en 2.16.0 ou 2.15.0.
Pire encore, la faille précédente qu’on croyait moyennement grave a vu son score de dangerosité passer de 3,7 à 9,0 sur 10 ! Une partie des recommandations faites pour atténuer les attaques s’avère désormais insuffisantes !
Une faille puis des failles vite corrigées mais très vite exploitées
En raison de sa simplicité et de l’étendue des cibles possibles, cette faille a vite été activement exploitée. De nombreux signalements ont été émis dès le 13 décembre par KnowSec 404, AlienVault ou SecureList par exemple. Même de vieux rançongiciels se sont réactivés pour profiter de l’aubaine, autant sur Windows que sur Linux. Le CERT Suisse a produit une infographie illustrant son fonctionnement et les points d’atténuation possibles :

Quelles sont les versions touchées et quelles solutions ?
La meilleure solution reste la mise à jour vers la dernière version de log4j, en vérifiant également que la configuration ne permet pas le JNDI (ce qui est le comportement par défaut depuis la version 2.16.0). Les versions 2.15.0 et 2.16.0 ne corrigent pas tous les problèmes de sécurité, il est donc important de refaire l’update vers la 2.17.0 (au 20 décembre 2021).
Pour la branche 1.x, aucune correction n’est prévue. C’est donc par paramétrage qu’on peut agir, soit en désactivant le JMS Appender
, ce qui est le comportement par défaut de la 1.x, soit en enlevant carrément JMSAppender
du classpath Java (la classe réalisant les appels JNDI n’existera plus). Précaution supplémentaire : s’assurer que l’utilisateur système (niveau OS) faisant tourner l’application utilisant log4j n’a pas les droits de modifier le fichier de configuration. Il ne faudrait pas qu’un attaquant puisse réactiver le JNDI…
Pour la branche 2.x, la seule vraie bonne solution reste la mise-à-jour ou la suppression du JndiLookup
dans le classpath Java (on est alors sûr qu’aucun lookup ne se fera).

Certaines des recommandations antérieures, rappelées ci-dessous, ne permettent qu’une atténuation partielle. Si vous les avez appliquées, sachez que vous êtes toujours vulnérable !
- De 2.7 à 2.10, il faut à chaque directive d’affichage ajouter un paramètre pour empêcher le lookup (ex : %m{nolookups});
- A partir de 2.10, il faut passer le paramètre de configuration formatMsgNoLookups à true;
- Pour pallier les risques d’exécution de code à distance, deux paramètres sont à passer à false :
- sun.jndi.rmi.object.trustURLCodebase
- sun.jndi.cosnaming.object.trustURLCodebase
Ces recommandations sont issues du papier des chercheurs d’Alibaba Cloud, mais ceux qui veulent suivre les évolutions de la situation doivent se conformer à l’avis très complet du CERT-FR, très régulièrement mis-à-jour :
D’autres solutions sont possibles, comme on le voit sur le schéma du CERT Suisse, comme l’utilisation d’un pare-feu applicatif ou d’un filtrage réseau, mais les attaquants modifient rapidement le payload afin de contourner les règles.
Par ailleurs, cette charge utile est tellement triviale qu’elle risque soit de passer au travers des filtres, soit d’obliger à mettre en place des règles qui vont bloquer des requêtes légitimes et créer de nombreux faux positifs. Et n’oubliez pas que les versions ultérieures à la 2.14 corrigent aussi d’autres problèmes de sécurité plus anciens, et que les contournements proposés pour log4shell ne suffiront pas forcément pour ces autres vulnérabilités.
On en a fini ?
Il reste un dernier problème : dans certains cas, il n’est pas possible de réaliser une mise à jour de log4j parce que le système est lié à une vieille version de Java. Cela explique qu’une version 2.12.1 de log4j traîne encore par endroits, car c’est la dernière version supportant encore Java 7.
Vous vous dites qu’il n’y a qu’à mettre Java à jour ? Hélas, ceux qui s'y sont frottés dans des environnements de production savent que toucher à Java peut avoir des effets indésirables catastrophiques, et que sans réaliser de minutieux tests de non-régression, on peut se retrouver avec un système instable ou carrément inopérant.
Un cas très simple pour comprendre : vous avez acheté une fortune un progiciel écrit en Java. Il est tellement cher que vous n’avez pas souscrit aux mises-à-jour et donc vous avez une vieille version qui marche très bien, qui fait ce qu’elle a à faire, mais en Java 7. Ce vieil applicatif ne peut donc loguer qu’avec la version 2.12.x de log4j avec votre vieux Java : si vous faites la mise-à-jour vers la 2.17.0 de log4j, votre applicatif va se planter au démarrage.
Apache a produit une version 2.12.2 le 14 décembre, pour les utilisateurs de Java 7, mais la correction s’avère incomplète et les corrections par paramétrage ne sont pas plus efficaces que sur les versions 2.15.0 et 2.16.0. Apache promet une version 2.12.3 à venir, qui permettra de mettre fin aux vulnérabilités sous Java 7. Le mal de crâne est garanti dans les grandes organisations où pullulent les versions hétérogènes de Java.
À ce jour, il n’y a plus de faille non corrigée, mais on a vu qu’agir vite pouvait avoir des effets indésirables, car l’urgence conduit parfois à proposer des solutions incomplètes ou contenant encore des problèmes. Cette vulnérabilité prend désormais la forme d’une saga (ou d’un cauchemar pour les services IT).
Pour terminer, la liste des produits touchés ne sera probablement jamais complète tellement elle est vaste. Des tentatives existent toutefois pour essayer de mesurer l’impact de cette vulnérabilité dans son système d’information, comme ici ou ici. Même des voitures Tesla ou des serveurs Minecraft sont touchés !