FlawOpen

flawopen.com/Teardowns/cve-2024-32002-git-submodule-rce

● CVE-2024-32002 · CVSS 9.0 · Critique
Recherche · FlawOpen

CVE-2024-32002 : RCE via les Liens Symboliques des Sous-modules Git

CVE-2024-32002 permettait à un dépôt Git conçu à cet effet d’écrire dans .git via un lien symbolique dont le chemin entrait en collision par la casse lors d’un clone récursif, ce qui pouvait déclencher un hook avant toute inspection. Le correctif amont de Git vérifie la destination du sous-module avant et après le clone et interrompt l’opération si son contenu est inattendu ; mettez Git à niveau vers une version corrigée.

💡 Explication en Langage Simple (ELI5)

Imaginez un entrepôt où les panneaux considèrent A et a comme la même porte. Si le chemin d’un sous-module passe par un panneau qui redirige vers la salle des registres (.git), des fichiers destinés à une zone peuvent se retrouver dans les données de contrôle de Git. Le correctif vérifie la destination avant et après le clone et s’arrête si son contenu est inattendu.

Concepts Clés et Termes

Sous-module Git
Un dépôt Git distinct intégré comme sous-dossier dans un dépôt parent.
Lien Symbolique
Un objet de système de fichiers redirigeant les chemins vers une autre cible.
Collision de Casse
Comportement sur NTFS et APFS où deux chemins ne différant que par la casse désignent le même fichier.
Crochets Git (Git Hooks)
Scripts exécutables dans .git/hooks/ déclenchés automatiquement par post-checkout.

Correspondances de référentiels

Analyse de Cause Racine

Sur un système de fichiers insensible à la casse qui prend en charge les liens symboliques, un dépôt conçu à cet effet pouvait donner à un sous-module un chemin entrant en collision, après normalisation de la casse, avec un lien symbolique. Pendant un clone récursif, Git pouvait remplacer par ce lien un répertoire créé pour le clone et écrire des fichiers hors du worktree du sous-module, dans .git. Un hook placé à cet endroit pouvait s’exécuter avant que l’utilisateur n’inspecte le checkout. Le correctif amont refuse de cloner vers une destination de sous-module préexistante et non vide puis, après le clone, rejette toute destination dont le contenu dépasse les métadonnées .git.

Déroulement de l'Attaque Étape par Étape

Étape 1

Le clone récursif atteint des métadonnées contrôlées par le dépôt

Une personne clone récursivement un dépôt non fiable sur un système de fichiers insensible à la casse où Git prend en charge les liens symboliques. Le dépôt fournit des chemins de sous-modules et des entrées suivies qui entrent en collision après normalisation de la casse.

Étape 2

La collision de chemins franchit une frontière de confiance

Git peut résoudre le chemin du sous-module en collision à travers un lien symbolique, au lieu de le placer dans le worktree prévu. La frontière concernée est la résolution des chemins du système de fichiers pendant le clone récursif des sous-modules.

Étape 3

Des fichiers atteignent les métadonnées Git

L’écriture redirigée peut placer un hook dans la zone .git du dépôt. L’avis du projet Git confirme qu’un hook peut y être écrit puis exécuté pendant que le clone est encore en cours.

Étape 4

Le clone peut exécuter du code avant inspection

Git exécute le hook pendant l’opération de clone, avant que l’utilisateur puisse examiner les fichiers. Les versions corrigées vérifient l’état de la destination et interrompent le clone si des fichiers inattendus sont présents.

Code Source : Vulnérable vs Sécurisé

Cet extrait montre une partie du changement amont en C dans clone_submodule() ; il ne constitue pas une fonction autonome. Avant le correctif, le chemin de clone affiché ne comportait pas de contrôle équivalent du contenu de destination. Le correctif refuse un répertoire de checkout préexistant non vide puis vérifie après le clone que seuls les métadonnées .git sont présents ; la fonction auxiliaire inspecte les entrées du répertoire. Le commit amont fournit l’implémentation complète.

IMPLÉMENTATION VULNÉRABLE
if (!file_exists(sm_gitdir)) {
    if (safe_create_leading_directories_const(sm_gitdir) < 0)
        die(_("could not create directory '%s'"), sm_gitdir);

    if (run_command(&cp))
        die(_("clone of '%s' into submodule path '%s' failed"),
            clone_data->url, clone_data_path);
}
PATCH SÉCURISÉ ET ROBUSTE
struct stat st;

if (!file_exists(sm_gitdir)) {
    if (clone_data->require_init && !stat(clone_data_path, &st) &&
        !is_empty_dir(clone_data_path))
        die(_("directory not empty: '%s'"), clone_data_path);

    if (safe_create_leading_directories_const(sm_gitdir) < 0)
        die(_("could not create directory '%s'"), sm_gitdir);

    if (run_command(&cp))
        die(_("clone of '%s' into submodule path '%s' failed"),
            clone_data->url, clone_data_path);

    if (clone_data->require_init && !stat(clone_data_path, &st) &&
        !dir_contains_only_dotgit(clone_data_path)) {
        char *dot_git = xstrfmt("%s/.git", clone_data_path);
        unlink(dot_git);
        free(dot_git);
        die(_("directory not empty: '%s'"), clone_data_path);
    }
}

Liste de Contrôle de Sécurité pour l'Ingénierie

Sources