CVE-2021-43798 – Path Traversal – Grafana

Grafana est une plateforme open-source largement utilisée pour l’analyse et la surveillance. La vulnérabilité CVE-2021-43798 permet à des acteurs malveillants non authentifiés de lire des fichiers arbitraires depuis le système de fichiers du serveur, en exploitant une faiblesse dans la gestion des chemins d’accès aux plugins. Cette vulnérabilité a été activement exploitée et figure désormais dans le catalogue CISA des vulnérabilités connues exploitées. Il est crucial d’appliquer immédiatement les correctifs disponibles.

ProduitGrafana, Grafana
Date2025-10-10 13:14:42

Résumé technique

La vulnérabilité était présente dans la fonction getPluginAssets au sein du fichier pkg/api/plugins.go. Le code original n’effectuait aucune validation sur le chemin du fichier demandé, mais prenait simplement le paramètre URL et l’utilisait pour construire un chemin de fichier :

func (hs *HTTPServer) getPluginAssets(c *models.ReqContext) {

  pluginID := web.Params(c.Req)[":pluginId"]

        ...........................

  requestedFile := filepath.Clean(web.Params(c.Req)["*"])

  pluginFilePath := filepath.Join(plugin.PluginDir, requestedFile)

        ...........................

  f, err := os.Open(pluginFilePath)

        ...........................

}

Le code récupérait le chemin générique (wild-card) fourni par l’utilisateur (web.Params(c.Req)["*"]) et exécutait un filepath.Clean directement sur celui-ci, puis un filepath.Join(plugin.PluginDir, requestedFile). Cela permettait à des segments de type ..%2f..%2f..%2f..%2fetc/passwd de “sortir” du répertoire du plugin après la jointure des chemins.

Le correctif est désormais le suivant :

func (hs *HTTPServer) getPluginAssets(c *models.ReqContext) {

  pluginID := web.Params(c.Req)[":pluginId"]

  plugin, exists := hs.pluginStore.Plugin(c.Req.Context(), pluginID)

  if (!exists) {

    c.JsonApiErr(404, "Plugin not found", nil)

    return

  }

  // ajout d'un slash pour nettoyer les chemins relatifs

  requestedFile := filepath.Clean(filepath.Join("/", web.Params(c.Req)["*"]))

  rel, err := filepath.Rel("/", requestedFile)

  if (err != nil) {

    // le slash est ajouté ci-dessus, donc cela ne devrait pas échouer

    c.JsonApiErr(500, "Failed to get the relative path", err)

    return

  }

  if !plugin.IncludedInSignature(rel) {

    hs.log.Warn("Access to requested plugin file will be forbidden in upcoming Grafana versions as the file "+

      "is not included in the plugin signature", "file", requestedFile)

  }

  absPluginDir, err := filepath.Abs(plugin.PluginDir)

  if (err != nil) {

    c.JsonApiErr(500, "Failed to get plugin absolute path", nil)

    return

  }

  pluginFilePath := filepath.Join(absPluginDir, rel)

  f, err := os.Open(pluginFilePath)

        ...........................

}

Recommandations

  1. Appliquer immédiatement le correctif : Mettre à jour toutes les instances de Grafana comprises entre les versions v8.0.0-beta1 et v8.3.0 vers la version la plus récente.

  2. Reverse proxy : Si la mise à jour n’est pas possible, utilisez un reverse proxy devant Grafana qui normalise le PATH de la requête pour atténuer la vulnérabilité.

  3. Surveillance et analyse : Effectuer un audit des accès et examiner les requêtes vers le point de terminaison /public/plugins/ à la recherche d’anomalies.

  4. Défense en profondeur : Utiliser des Web Application Firewalls (WAF) configurés pour bloquer les tentatives de traversée de répertoire (path traversal) comme couche de protection supplémentaire.

[Callforaction-THREAT-Footer]

Leave a Reply

Your email address will not be published. Required fields are marked *