FlawOpen

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

● CVE-2024-32002 · CVSS 9.0 · Kritisch
Sicherheitsforschung · FlawOpen

CVE-2024-32002: Git-Submodul-Symlink Remotecodeausführung (RCE)

CVE-2024-32002 ermöglichte einem präparierten Git-Repository, während eines rekursiven Klons über einen bei Groß-/Kleinschreibung kollidierenden Symlink in .git zu schreiben. Dadurch konnte ein Hook vor der Prüfung ausgeführt werden. Git prüft im Upstream-Fix das Submodulziel vor und nach dem Klonen und bricht bei unerwarteten Inhalten ab; aktualisieren Sie auf eine korrigierte Git-Version.

💡 Einfache Erklärung (ELI5)

Stellen Sie sich ein Lager vor, dessen Schilder A und a als dieselbe Tür behandeln. Führt der Pfad eines Submoduls über ein Schild in den Aktenraum (.git), können Dateien für ein Lagerfach in Git-interne Steuerdaten gelangen. Der Git-Fix prüft das Ziel vor und nach dem Klonen und bricht bei unerwarteten Inhalten ab.

Kernkonzepte & Begriffe

Git-Submodul
Ein eigenständiges Git-Repository, das als Unterordner in ein Haupt-Repository eingebettet ist.
Symbolischer Link (Symlink)
Ein Dateisystemobjekt, das Pfade auf ein anderes Ziel verweist.
Case-Kollision
Verhalten von NTFS und APFS, bei dem Pfade unabhängig von Groß-/Kleinschreibung dasselbe Ziel referenzieren.
Git Hooks
Ausführbare Skripte in .git/hooks/, die bei Vorgängen wie post-checkout automatisch starten.

Framework-Zuordnungen

Ursachenanalyse

Auf einem groß-/kleinschreibungsunabhängigen Dateisystem mit Symlink-Unterstützung konnte ein präpariertes Repository einen Submodulpfad definieren, der nach der Groß-/Kleinschreibungsnormalisierung mit einem Symlink kollidierte. Beim rekursiven Klonen konnte Git ein für den Klon angelegtes Verzeichnis durch diesen Symlink ersetzen und Dateien außerhalb des Submodul-Worktrees in .git schreiben. Ein dort abgelegter Hook konnte laufen, bevor der Benutzer den Checkout prüfen konnte. Der Upstream-Patch verweigert das Klonen in ein bereits vorhandenes, nicht leeres Submodulziel und weist nach dem Klonen ein Ziel zurück, das mehr als .git-Metadaten enthält.

Schritt-für-Schritt Angriffsablauf

Schritt 1

Der rekursive Klon erreicht repositorykontrollierte Metadaten

Eine Person klont ein nicht vertrauenswürdiges Repository rekursiv auf einem groß-/kleinschreibungsunabhängigen Dateisystem, auf dem Git Symlinks unterstützt. Das Repository enthält Submodulpfade und getrackte Einträge, die nach der Normalisierung kollidieren.

Schritt 2

Die Pfadkollision überschreitet eine Vertrauensgrenze

Git kann den kollidierenden Submodulpfad über einen Symlink auflösen, statt ihn im vorgesehenen Submodul-Worktree anzulegen. Betroffen ist Git-Pfadauflösung während eines rekursiven Submodul-Klons.

Schritt 3

Dateien gelangen in Git-Metadaten

Der umgeleitete Schreibvorgang kann einen Hook im .git-Bereich des Repositorys ablegen. Der Git-Projektbeitrag bestätigt, dass ein Hook dort geschrieben und noch während des Klonvorgangs ausgeführt werden kann.

Schritt 4

Der Klon führt Code vor der Prüfung aus

Git führt den Hook während des Klons aus, bevor der Benutzer die ausgecheckten Dateien untersuchen kann. Korrigierte Git-Versionen prüfen den Zielzustand und brechen bei unerwarteten Dateien ab.

Quellcode: Verwundbar vs. Sicher

Dies ist ein Auszug aus der Upstream-C-Änderung in clone_submodule() und keine eigenständige Funktion. Vor dem Fix enthielt der gezeigte Klonpfad keine entsprechende Prüfung des Zielinhalts. Der Fix weist ein bereits vorhandenes, nicht leeres Checkout-Verzeichnis zurück und prüft nach dem Klonen, dass nur .git-Metadaten vorhanden sind; die Hilfsfunktion untersucht die Verzeichniseinträge. Der Upstream-Commit enthält die vollständige Implementierung.

VERWUNDBARE IMPLEMENTIERUNG
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);
}
GEHÄRTETER SICHERHEITS-PATCH
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);
    }
}

Checkliste für Engineering & Systemsicherheit

Quellen