FlawOpen

flawopen.com/Teardowns/cve-2024-21626-runc-container-breakout-leaky-vessels

● CVE-2024-21626 · CVSS 8.6[1], [5] · Haute
Recherche · FlawOpen

CVE-2024-21626 : comment runc a corrigé l’évasion Leaky Vessels

CVE-2024-21626 associait une fuite interne de descripteur dans runc à l’absence de vérification après chdir. Selon le chemin de lancement, le conteneur pouvait démarrer avec un répertoire de travail dans l’espace de noms de l’hôte ou atteindre des fichiers de l’hôte par un chemin lié à exec.[1], [2], [3]

💡 Explication en Langage Simple (ELI5)

runc prépare une pièce isolée pour le conteneur. Un handle interne divulgué pouvait faire pointer le répertoire de travail choisi hors de cette pièce ; la vérification finale de la limite et la fermeture des handles internes bloquent ce passage.[1], [2]

Concepts Clés et Termes

runc
Le runtime OCI qui crée et démarre les conteneurs.[1]
Descripteur de fichier interne
Handle du système d’exploitation vers un fichier ou répertoire ouvert. Un descripteur divulgué peut conserver un accès entre processus s’il reste ouvert pendant le lancement d’un enfant.[1], [3]
cwd
Répertoire de travail du processus. Sous Linux, Getwd peut renvoyer ENOENT lorsqu’il se trouve hors de la racine de l’espace de noms de montage.[1], [2]
Évasion de conteneur
Chemin permettant à un processus du conteneur d’accéder aux ressources de l’hôte situées hors de sa frontière d’isolation.[1]

Correspondances de référentiels

  • Référence CWE pour la faiblesse décrite dans ce guide : CWE-403

Analyse de Cause Racine

Avant runc 1.1.12, des descripteurs internes pouvaient fuiter vers runc init. Ils restaient internes à runc init et n’étaient pas simplement hérités par le processus du conteneur. Dans les attaques 1 et 2, le répertoire de travail configuré ou choisi pouvait être résolu via un handle de l’espace de noms de montage de l’hôte ; runc ne vérifiait pas après chdir que le répertoire final restait dans la racine du conteneur. D’autres variantes exploitaient le traitement des chemins d’execve pour écraser un binaire de l’hôte. La version 1.1.12 a ajouté quatre protections : vérifier cwd avec le comportement Getwd/ENOENT de Linux, fermer les descripteurs internes juste avant execve, corriger les fuites identifiées et marquer les descripteurs non-stdio close-on-exec avant de lancer runc init.[1], [2], [3], [4]

CVE-2024-21626 : variantes d’attaque et protections de runc 1.1.12

Variante de l’avisConditions et frontière requisesCorrectif ou mesure temporaire pertinente
Attaque 1 — image malveillante avec runc runUn utilisateur privilégié doit être amené à lancer une image non fiable. Son répertoire de travail configuré peut se résoudre hors de l’espace de noms de montage du conteneur.Le contrôle unix.Getwd() après chdir échoue si cwd se trouve hors de la racine de l’espace de noms. En attendant le correctif, n’autorisez que / comme cwd pour les images non fiables.
Attaque 2 — processus du conteneur et runc execUn processus dans le conteneur doit anticiper le choix par l’administrateur d’un cwd autre que / avec runc exec --cwd, puis préparer le chemin concerné avant l’exécution.Le même contrôle de cwd après chdir bloque l’exécution hors du conteneur. Limitez --cwd à / jusqu’à la mise à jour.
Attaque 3a — écrasement d’un binaire hôte au lancement d’imageCette variante adapte l’attaque 1 et exige toujours qu’un utilisateur privilégié lance l’image malveillante ; elle franchit la frontière execve vers un binaire de l’hôte.Fermez les descripteurs internes de runc juste avant execve, corrigez les fuites identifiées et définissez O_CLOEXEC. Mettez à jour vers runc 1.1.12 ou une version corrigée par le fournisseur.
Attaque 3b — écrasement d’un binaire hôte via runc execCette variante adapte l’attaque 2 et part d’un processus malveillant dans un conteneur actif que l’attaquant peut influencer ; un administrateur privilégié doit néanmoins effectuer une opération normale de runc exec sur ce conteneur. L’avis indique que cette voie demande moins d’interaction utilisateur que celle par image.Les protections de fermeture avant execve et close-on-exec couvrent cette voie distincte. Les mainteneurs ne signalent pas de contournement pratique ; mettez à jour.

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

Étape 1

Fuite d’un handle interne

Pendant la préparation, un descripteur interne de runc référant à l’espace de noms de montage de l’hôte pouvait rester disponible pour runc init.[1], [3]

Étape 2

Chemin de répertoire atteignable

Une image malveillante ou un scénario runc exec répondant à certaines conditions pouvait placer le cwd demandé hors de la racine du conteneur.[1], [2]

Étape 3

Échec de la frontière

Le code antérieur ne vérifiait pas le cwd final après chdir ; des variantes exploitaient le traitement des chemins d’execve pour écraser un binaire de l’hôte.[2], [3]

Étape 4

Impact et conditions

L’avis documente un accès au système de fichiers et le contrôle de l’hôte dans quatre variantes. Les attaques par image exigent qu’un utilisateur privilégié lance une image non fiable. L’attaque 3b exige toujours qu’un administrateur effectue une opération normale de runc exec sur un conteneur que l’attaquant peut influencer.[1]

Code Source : Vulnérable vs Sécurisé

IMPLÉMENTATION VULNÉRABLE
// Comportement pré-correctif simplifié ; extrait non littéral de runc
if err := os.Chdir(config.Cwd); err != nil {
    return err
}
// Il manquait la vérification que le cwd final reste dans la racine du namespace
PATCH SÉCURISÉ ET ROBUSTE
// Vérification de frontière de runc 1.1.12 (extrait upstream)
if wd, err := unix.Getwd(); errors.Is(err, unix.ENOENT) {
    return errors.New("cwd hors de la racine du namespace de montage du conteneur")
} else if err != nil {
    return fmt.Errorf("impossible de vérifier la sécurité du cwd : %w", err)
} else if !filepath.IsAbs(wd) {
    return fmt.Errorf("cwd non absolu : %q", wd)
}

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

Sources