Rétrospective de Log4j, partie 1 : le contexte de la vulnérabilité
Événements
Le 24 novembre 2021, la Fondation Apache a été informée en privé par l'équipe de sécurité du cloud d'Alibaba que Log4j, une bibliothèque de journalisation Java largement utilisée, contenait une vulnérabilité majeure qui pourrait entraîner la fuite d'informations privées ainsi que l'exécution de code à distance (RCE). Cette vulnérabilité était présente depuis 2013.
Le lendemain, la Fondation Apache a réservé le nom CVE-2021-44228 et a commencé à chercher une solution. Au cours des 12 jours qui suivirent, plusieurs modifications ont été introduites dans le code source pour résoudre le problème, et le 9 décembre 2021, la vulnérabilité a été révélée au public.
Il en a résulté une avalanche de tentatives d'exploitation qui n'ont cessé de croître à un rythme alarmant depuis lors.
Qu'est-ce que Log4j ?
Pour vraiment comprendre la vulnérabilité, nous devons comprendre ce qu'est Log4j. Log4j est une bibliothèque qui bénéficie d'une utilisation répandue parmi les développeurs de la communauté Java. Elle fournit un cadre simple mais robuste pour la journalisation des messages d'erreur, des informations de diagnostic, etc.
Parmi ses caractéristiques impressionnantes, on peut citer la possibilité d'établir des journaux vers plusieurs cibles, y compris, mais sans s'y limiter, la console, un fichier, un serveur distant utilisant TCP, Syslog, les journaux d'événements NT et la messagerie électronique. En outre, elle permet le filtrage hiérarchique des messages de journal, les niveaux de journal, les mises en page personnalisées, et bien plus encore.
En bref, elle dispose d'un ensemble complet de fonctionnalités qui en font une bibliothèque très intéressante à exploiter pour les développeurs, ce qui a conduit à son omniprésence dans tous les domaines, des applications Web aux terminaux intégrés.
Recherches et imbrication
L'une des fonctions vraiment puissantes que Log4j prend en charge est connue sous le nom de « lookups » ou recherches. Les recherches permettent à un développeur d'incorporer des variables ou des expressions dans le texte qui sont automatiquement évaluées par Log4j avant leur sortie. Par exemple, un développeur pourrait écrire un code qui indique le texte suivant :
« ${date:MM-dd-yyyy} Tous les systèmes OK »
Log4j reconnaît le modèle ${date:MM-dd-yyyy} comme une recherche de date, et remplace scrupuleusement cette expression par la date du jour. Par exemple, si la date était le 20 décembre 2021, elle modifierait le texte comme suit avant de l'envoyer à une cible :
« 20-12-2021 Tous les systèmes OK »
Ceci est extrêmement utile pour les développeurs. Sans cette fonctionnalité, ils doivent écrire manuellement un code qui recherche la date, la formate en une chaîne de caractères, la fait précéder de la ligne de journal, puis la sort. Et bien que le code ci-dessus ne soit pas particulièrement difficile ou pénible à écrire, il ne se rapporte pas à la logique métier de base du logiciel et finit par être répété d'un projet à l'autre.
En exploitant les fonctionnalités déjà codées de la bibliothèque Log4j, les développeurs peuvent se concentrer sur la différenciation qui compte vraiment pour leur projet et laisser Log4j gérer toutes les tâches liées à la journalisation.
De nombreuses expressions de recherche de ce type sont prises en charge par Log4j. Examinons-en deux autres qui seront très présentes dans cet article : env et lower. env permettent d'inclure les variables d'environnement du système hôte dans les lignes de journal. Par exemple, un développeur entrant le texte :
« L'utilisateur actuel est ${env:USER} »
produirait le résultat suivant, en supposant que le logiciel est exécuté en tant qu'utilisateur Administrateur.
« L'utilisateur actuel est Administrateur »
Contrairement à env et à date qui injectent de nouvelles données dans le texte, lower peut être utilisé pour manipuler ce qui est déjà présent. Log4j met simplement en minuscules ce qui apparaît dans l'expression. Par exemple :
« Le texte en minuscule est ${lower:ABCDEFG} »
produit :
« Le texte en minuscule est abcdefg »
Cet exemple à lui seul n'est pas très intéressant. Pourquoi ne pas simplement mettre la chaîne en minuscules vous-même ? La puissance de cette fonction devient plus évidente si nous prenons en compte le fait que Log4j permet l'imbrication d'expressions de recherche.
Nous pouvons combiner les deux expressions précédentes comme suit :
« L'utilisateur actuel en minuscule est ${lower:${env:USER}} »
Log4j commence par évaluer l'expression ${env:USER} comme Administrateur, puis l'envoie à lower qui produira administrateur, ce qui donnera la ligne suivante :
« L'utilisateur actuel en minuscule est administrateur »
JNDI
Alors que date, envet lower sont intéressants et très utiles, cette vulnérabilité ne serait pas possible sans la recherche JNDI. JNDI, ou Java Naming and Directory Interface, est un mécanisme intégré nativement aux environnements de développement et d'exécution Java qui permet d'interroger de manière simplifiée divers services d'annuaire à l'aide d'une interface commune.
Il s'avère qu'il existe de nombreux types de services d'annuaire pris en charge. Par exemple, JNDI prend en charge l'interrogation des serveurs DNS pour découvrir l'adresse IP d'un hôte, ainsi que l'interrogation des entrées d'annuaire AD et LDAP. Il peut même interroger l'environnement Java en cours d'exécution pour connaître les entrées environnementales, qui peuvent être considérées comme des options de configuration spécialisées pour le logiciel en cours d'exécution.
L'expression de recherche JNDI dans Log4j permet aux développeurs d'accéder à ce sous-système extrêmement puissant directement par le biais d'expressions intégrées dans le texte enregistré. Par exemple, si un développeur tente d'entrer la chaîne suivante :
« L'hôte de messagerie actuel est ${jndi:Java:comp/env/mailhost} »
Log4j reconnaîtra l'expression ${jndi:java:comp/env/mailhost} comme étant une recherche JNDI et transmettra la pseudo URL de java:comp/env/mailhost au sous-système JNDI. JNDI reconnaîtra ce type d'URL comme étant une requête pour rechercher une option de configuration appelée mailhost pour le composant en cours d'exécution.
Imaginons qu'elle soit configurée en tant que mymailserver.example.com. JNDI renverra ces informations à Log4j, qui remplacera alors l'expression de recherche par mymailserver.example.com, ce qui donnera le résultat suivant :
« L'hôte de messagerie actuel est mymailserver.example.com »
Comprendre l'existence de cette vulnérabilité
En bref, la vulnérabilité de Log4j d'Apache représentait une opportunité majeure pour les attaquants en raison de la grande popularité de la bibliothèque et de ses capacités de recherche, d'imbrication et son fonctionnement avec JNDI en particulier. Cette fonctionnalité, bien que puissante pour les développeurs, crée également des opportunités pour présenter des requêtes qui peuvent extraire des données ou provoquer des RCE. Grâce à ces connaissances, nous pouvons maintenant mieux comprendre la vulnérabilité et la façon dont les attaquants peuvent exploiter le système.
Et après ?
Dans la partie 2 de cette série, nous verrons comment les attaquants ont commencé à exploiter cette vulnérabilité pour l'extraction des données et les RCE.