Empoisonnement du cache GitHub

Tous Les Articles

Savez-vous ce qui se passe sous le capot de votre CI ? Sans une compréhension approfondie, vous pourriez être vulnérable aux attaques innovantes de la chaîne d’approvisionnement. Cet article décrit une telle attaque.

La mise en cache est utilisée pour accélérer les processus. Au lieu de créer ou de télécharger encore et encore un package, il conserve simplement et automatiquement les artefacts pour les réutiliser. Cependant, les caches pourraient être empoisonnées. Par exemple, un outil malveillant utilisé dans un workflow de test peut empoisonner son cache. Ultérieurement, un autre workflow utilisant le même cache pourrait être affecté. Si ce workflow dispose de privilèges plus élevés, il s’agit en fait d’une méthode permettant de faire pivoter une attaque. Dans cet article, nous rendons compte d'une attaque expérimentale sur un pipeline CI GitHub, mais une vulnérabilité logique similaire existe dans d'autres produits CI.

L'attaque se déroule comme suit : 

  1. Un attaquant publie un outil malveillant ou une action Github qui est récupéré par un flux de travail sans méfiance dans Github.
  2. Le workflow est conçu avec un cache
  3. La charge utile malveillante modifie le cache pour inclure des données malveillantes.
  4. D'autres workflows qui font appel à ce cache à partir de ce stade pourraient être affectés.

En réponse à notre divulgation, GitHub a déclaré qu'il n'avait pas l'intention de renforcer la fonctionnalité de cache contre ce type d'attaque. 

Nous proposons une atténuation en signant cryptographiquement la valeur de hachage du contenu du cache et en vérifiant la signature avant utilisation. Pour en savoir plus sur l’attaque et les mesures d’atténuation, continuez à lire.

Attaque d'empoisonnement du cache

Cache GitHub

réutiliser souvent les mêmes sorties ou dépendances téléchargées d'une exécution à l'autre (par exemple, les packages téléchargés par des outils de gestion de packages et de dépendances tels que Maven, Gradle, npm et Yarn. Ces packages sont généralement conservés dans un cache local des dépendances téléchargées).

Pour optimiser les exécutions de CI, GitHub accorde l'accès à une ressource de cache qui peut être utilisée dans le pipeline via une API. Les entrées dans le cache sont une combinaison clé-valeur, où les clés sont basées sur des chaînes et les valeurs sont des fichiers ou des répertoires que l'on souhaite mettre en cache.

Le action/cache L'action Git n'importe où dans le CI se déroulera en deux étapes : une étape aura lieu pendant le courir processus lorsqu'il est appelé et l'autre aura lieu après workflow (si l'action d'exécution a renvoyé un échec de cache).

  • Exécuter une action – est utilisé pour rechercher et récupérer le cache. La recherche est effectuée à l'aide de la clé de cache, le résultat étant soit un accès au cache (succès, données trouvées dans le cache), soit un échec du cache. S'ils sont trouvés, les fichiers et répertoires sont récupérés du cache pour une utilisation active. Si le résultat est un échec de cache, les fichiers et répertoires souhaités sont téléchargés comme si c'était la première fois qu'ils étaient appelés.
  • Action post-workflow – utilisé pour sauvegarder le cache. Si le résultat de l'appel au cache dans l'action d'exécution renvoie un échec de cache, cette action enregistrera l'état actuel des répertoires que nous souhaitons mettre en cache avec la clé fournie. Cette action se produit automatiquement et n'a pas besoin d'être explicitement appelée.

Autorisations du cache GitHub

Les restrictions d'accès fournissent isolation du cache et la sécurité en créant une frontière logique entre les différentes branches (par exemple : un cache créé pour la branche Caractéristique-A [avec la base main] ne serait pas accessible à une pull request pour la branche Caractéristique-B [avec la base principale]).

L'action de cache recherche d'abord une clé dans les accès au cache et restaure les clés dans la branche contenant la clé. exécution du flux de travail. S'il n'y a aucun résultat dans la branche actuelle, l'action de cache recherche la clé et restaure les clés dans la branche parent et les branches en amont.

L'accès à un cache est limité à la branche (actuelle et parent), ce qui signifie que l'accès est fourni à tous workflows à travers fonctionne de ladite succursale.

Une autre remarque importante est que GitHub n'autorise pas les modifications une fois les entrées poussées : les entrées du cache sont des enregistrements en lecture seule.

Portée de GitHub CI

GitHub portée permettent de spécifier exactement quel type d'accès est nécessaire pour diverses tâches. Le CI de GitHub est étendu de différentes manières, chacune avec son propre ensemble de valeurs et de fonctionnalités :

  • Machine virtuelle (VM) pour chaque tâche
  • Autorisations de travail
  • Portées du flux de travail
  • Exécutions de flux de travail
  • Branches Git
  • Jetons d'identité de workflow
  • et d'autres

La portée du cache GitHub a été définie d'une manière qui peut briser certaines des autres restrictions de portée (ex : le cache GitHub peut affecter plusieurs workflows).

L'attaque

Nous avons utilisé un exemple de CI qui comprenait deux workflows. Cet exemple montre comment une attaque peut passer d’un workflow à faible autorisation à un workflow à haute autorisation.

  • Test de l'unité workflow exécutant des outils de tests unitaires et de couverture de code. Nous supposons que l'un des outils est malveillant ou vulnérable à l'exécution de code à distance. Le flux de travail doit utiliser le action/cache Action Git. N’importe quel workflow peut accéder au cache.
  • Libération Le workflow crée et libère l'artefact d'application. Ce workflow utilise un cache pour optimiser l'utilisation des dépendances Golang.

Les Test de l'unité le workflow utilise une action malveillante qui ajoute une entrée de cache avec un contenu malveillant en modifiant une bibliothèque de journalisation Golang (go.uber.org/zap@v1) pour ajouter la chaîne « BAD library » à la description de l'artefact d'application.

Ensuite, le libérer Le workflow utilise cette entrée de cache empoisonnée. En conséquence, le code malveillant est injecté dans le binaire et l’image Golang construits. Le cache reste empoisonné jusqu'à ce que la clé d'entrée soit supprimée (généralement déclenchée par des mises à jour de dépendances). Le même cache empoisonné affectera tout autre workflow, couriret la branche enfant en utilisant la même clé de cache.

Dans le test que nous avons effectué, nous avons réussi à injecter la chaîne 'BAD library' dans la description de l'image :

MAUVAISE bibliothèque

C'était dans la version 0.4.1. Ensuite, nous avons mis à jour la balise et reconstruit l'image plusieurs fois, et avons observé que « Mauvaise bibliothèque » restait dans la description.

Divulgation GitHub

La réponse de Github à notre divulgation a été que l'action Git,  action/cache se comporte comme prévu et ils n'ont pas l'intention de resserrer la portée du cache.
Bien que l'équipe GitHub ne considère pas ce comportement comme problématique, nous conseillons aux praticiens DevSecOps de se méfier de ce vecteur d'attaque.

Atténuation

  1. N'utilisez pas de caches dans la version ou dans les flux de travail importants.
  2. Exécutez vos workflows de manière séquentielle, en commençant par le workflow approuvé pour vous assurer que votre cache est créé dans un workflow approuvé.
  3. Vendez vos dépendances – La vente dans GoLang est une méthode permettant de garantir que tous les packages tiers utilisés dans le projet Go sont cohérents pour tous ceux qui développent pour cette application. De cette façon, les dépendances mises en cache resteront valables pour toutes les branches du projet. D'autres langues peuvent ne pas prendre en charge cette méthode.
  4. Signez la valeur du cache de manière cryptographique et vérifiez la signature avant utilisation.
    Scribe atténue ces attaques en signant de manière granulaire tout objet ou répertoire dans un flux de travail tel qu'un cache. Avant la version, vous pouvez utiliser Scribe pour vérifier que seul un cache généré par un workflow approuvé a été utilisé pour créer la version.

Résumé 

Dans cet article, nous avons décrit une attaque par empoisonnement du cache dans les flux de travail CI, qui est cachée aux yeux de l'équipe DevSecOps, et discuté des mesures d'atténuation.

Ce contenu vous est proposé par Scribe Security, l'un des principaux fournisseurs de solutions de sécurité de bout en bout pour la chaîne d'approvisionnement logicielle, offrant une sécurité de pointe aux artefacts de code ainsi qu'aux processus de développement et de livraison de code tout au long des chaînes d'approvisionnement logicielles. En savoir plus.