GitHub-Cache-Vergiftung

Alle Beiträge

Wissen Sie, was unter der Haube Ihres CI passiert? Ohne umfassendes Verständnis sind Sie möglicherweise anfällig für innovative Angriffe auf die Lieferkette. Dieser Artikel beschreibt einen solchen Angriff.

Caching dient der Beschleunigung von Prozessen. Anstatt immer wieder ein Paket zu erstellen oder herunterzuladen, werden Artefakte einfach und automatisch zur Wiederverwendung aufbewahrt. Caches könnten jedoch vergiftet sein. Beispielsweise kann ein bösartiges Tool, das in einem Test-Workflow verwendet wird, seinen Cache vergiften. Später könnte ein anderer Workflow betroffen sein, der denselben Cache verwendet. Wenn dieser Workflow über höhere Berechtigungen verfügt, handelt es sich tatsächlich um eine Methode zur Pivotierung eines Angriffs. In diesem Beitrag berichten wir über einen experimentellen Angriff auf eine GitHub-CI-Pipeline, eine ähnliche logische Schwachstelle besteht jedoch auch in anderen CI-Produkten.

Der Angriff läuft wie folgt ab: 

  1. Ein Angreifer veröffentlicht ein schädliches Tool oder eine Github-Aktion, die von einem ahnungslosen Workflow in Github erfasst wird.
  2. Der Workflow ist mit einem Cache ausgelegt
  3. Die schädliche Nutzlast ändert den Cache, sodass er schädliche Daten enthält.
  4. Andere Workflows, die ab diesem Zeitpunkt diesen Cache aufrufen, könnten davon betroffen sein.

Als Reaktion auf unsere Offenlegung sagte GitHub, dass es keinen Plan gibt, die Cache-Funktion gegen diese Art von Angriff zu härten. 

Wir schlagen eine Abhilfe vor, indem wir den Inhalts-Hashwert des Caches kryptografisch signieren und die Signatur vor der Verwendung überprüfen. Um mehr über den Angriff und die Gegenmaßnahmen zu erfahren, lesen Sie weiter.

Cache-Poisoning-Angriff

GitHub-Cache

Verwenden Sie häufig dieselben Ausgaben oder heruntergeladenen Abhängigkeiten von einem Lauf zum anderen wieder (z. B. die Pakete, die von Paket- und Abhängigkeitsverwaltungstools wie Maven, Gradle, npm und Yarn heruntergeladen wurden. Diese Pakete werden normalerweise in einem lokalen Cache heruntergeladener Abhängigkeiten gespeichert.).

Um CI-Läufe zu optimieren, gewährt GitHub Zugriff auf eine Cache-Ressource, die über eine API in der gesamten Pipeline verwendet werden kann. Die Einträge im Cache sind eine Schlüssel-Wert-Kombination, wobei die Schlüssel auf Zeichenfolgen basieren und die Werte Dateien oder Verzeichnisse sind, die zwischengespeichert werden sollen.

Verwendung der Aktion/Cache Eine Git-Aktion an einer beliebigen Stelle im CI führt zwei Schritte aus: Ein Schritt findet während des statt Lauf Prozess, wenn er aufgerufen wird, und der andere wird nachträglich stattfinden Arbeitsablauf. (wenn die Ausführungsaktion einen Cache-Fehler zurückgegeben hat).

  • Aktion ausführen – wird zum Suchen und Abrufen des Caches verwendet. Die Suche erfolgt mithilfe des Cache-Schlüssels. Das Ergebnis ist entweder ein Cache-Hit (Erfolg, Daten im Cache gefunden) oder ein Cache-Miss. Wenn die Dateien und Verzeichnisse gefunden werden, werden sie zur aktiven Verwendung aus dem Cache abgerufen. Wenn das Ergebnis ein Cache-Miss ist, werden die gewünschten Dateien und Verzeichnisse so heruntergeladen, als ob sie zum ersten Mal aufgerufen würden.
  • Workflow-Aktion veröffentlichen – Wird zum Speichern des Caches verwendet. Wenn das Ergebnis des Cache-Aufrufs in der Ausführungsaktion einen Cache-Fehler zurückgibt, speichert diese Aktion den aktuellen Status der Verzeichnisse, die wir mit dem bereitgestellten Schlüssel zwischenspeichern möchten. Diese Aktion erfolgt automatisch und muss nicht explizit aufgerufen werden.

GitHub-Cache-Berechtigungen

Zugangsbeschränkungen vorsehen Cache-Isolation und Sicherheit durch die Schaffung einer logischen Grenze zwischen verschiedenen Zweigen (Beispiel: ein für den Zweig erstellter Cache Feature-A [mit der Basis main] wäre für eine Pull-Anfrage für den Zweig nicht zugänglich Feature-B [mit der Basis main]).

Die Cache-Aktion durchsucht zunächst Cache-Treffer nach einem Schlüssel und stellt Schlüssel in dem Zweig wieder her, der den enthält Workflow-Lauf. Wenn es im aktuellen Zweig keine Treffer gibt, sucht die Cache-Aktion nach dem Schlüssel und stellt die Schlüssel im übergeordneten Zweig und den Upstream-Zweigen wieder her.

Der Zugriff auf einen Cache ist nach Zweig (aktueller und übergeordneter Zweig) begrenzt, d. h. der Zugriff ist für alle möglich Workflows über läuft der besagten Filiale.

Ein weiterer wichtiger Hinweis ist, dass GitHub keine Änderungen zulässt, sobald Einträge gepusht wurden – Cache-Einträge sind schreibgeschützte Datensätze.

GitHub CI-Scoping

GitHub Zielfernrohre ermöglichen es, genau anzugeben, welche Art von Zugriff für verschiedene Aufgaben benötigt wird. Das CI von GitHub hat verschiedene Geltungsbereiche, jede mit ihren eigenen Werten und Funktionen:

  • Virtuelle Maschine (VM) für jeden Job
  • Arbeitsberechtigungen
  • Workflow-Bereiche
  • Workflow wird ausgeführt
  • Git-Zweige
  • Workflow-Identitätstoken
  • und anderen beteiligt

Der GitHub-Cache-Bereich wurde so definiert, dass einige der anderen Bereichseinschränkungen aufgehoben werden können (Beispiel: GitHub-Cache kann sich auf mehrere Arbeitsabläufe auswirken).

Der Angriff

Wir haben ein Beispiel-CI verwendet, das zwei Workflows beinhaltete. Dieses Beispiel zeigt, wie ein Angriff von einem Workflow mit niedriger Berechtigung zu einem Workflow mit hoher Berechtigung übergehen kann.

  • Gerätetest Workflow zum Ausführen von Unit-Test- und Code-Coverage-Tools. Wir gehen davon aus, dass eines der Tools bösartig oder anfällig für die Remotecodeausführung ist. Der Workflow muss die verwenden Aktion/Cache Git-Aktion. Jeder Workflow kann auf den Cache zugreifen.
  • Loslassen Der Workflow erstellt und gibt das Anwendungsartefakt frei. Dieser Workflow verwendet einen Cache zur Optimierung mithilfe der Golang-Abhängigkeiten.

Das Gerätetest Der Workflow verwendet eine schädliche Aktion, die durch Ändern einer Golang-Protokollierungsbibliothek einen Cache-Eintrag mit schädlichem Inhalt hinzufügt (go.uber.org/zap@v1), um die Zeichenfolge „BAD-Bibliothek“ zur Beschreibung des Anwendungsartefakts hinzuzufügen.

Als nächstes Release Der Workflow verwendet diesen vergifteten Cache-Eintrag. Dadurch wird der Schadcode in die erstellte Golang-Binärdatei und das Golang-Image eingeschleust. Der Cache bleibt vergiftet, bis der Eintragsschlüssel verworfen wird (normalerweise ausgelöst durch Abhängigkeitsaktualisierungen). Der gleiche vergiftete Cache wirkt sich auf jeden anderen aus Arbeitsablauf., Lauf und Unterzweig mit demselben Cache-Schlüssel.

In dem von uns durchgeführten Test ist es uns gelungen, die Zeichenfolge „BAD-Bibliothek“ in die Bildbeschreibung einzufügen:

SCHLECHTE Bibliothek

Dies war in Version 0.4.1. Als Nächstes haben wir das Tag mehrmals aktualisiert und das Bild neu erstellt. Dabei haben wir festgestellt, dass in der Beschreibung immer noch „Bad Library“ enthalten war.

GitHub-Offenlegung

Githubs Antwort auf unsere Offenlegung war, dass die Git-Aktion,  Aktion/Cache verhält sich wie erwartet und es besteht keine Absicht, den Umfang des Caches zu verschärfen.
Obwohl das GitHub-Team dieses Verhalten nicht als problematisch ansieht, raten wir DevSecOps-Praktikern, sich vor diesem Angriffsvektor in Acht zu nehmen.

Milderungen

  1. Verwenden Sie keine Caches in Releases oder in wichtigen Workflows.
  2. Führen Sie Ihre Workflows nacheinander aus, wobei der vertrauenswürdige Workflow zuerst ausgeführt wird, um sicherzustellen, dass Ihr Cache in einem vertrauenswürdigen Workflow erstellt wird.
  3. Bieten Sie Ihre Abhängigkeiten an – Vendoring in GoLang ist eine Methode, um sicherzustellen, dass alle im Go-Projekt verwendeten Pakete von Drittanbietern für alle konsistent sind, die für diese Anwendung entwickeln. Auf diese Weise bleiben zwischengespeicherte Abhängigkeiten für alle Zweige des Projekts gültig. Andere Sprachen unterstützen diese Methode möglicherweise nicht.
  4. Signieren Sie den Cache-Wert kryptografisch und überprüfen Sie die Signatur vor der Verwendung.
    Scribe schwächt solche Angriffe ab, indem es jedes Objekt oder Verzeichnis in einem Workflow, beispielsweise einem Cache, granular signiert. Vor der Veröffentlichung können Sie mit Scribe überprüfen, ob zum Erstellen der Veröffentlichung nur ein von einem vertrauenswürdigen Workflow generierter Cache verwendet wurde.

Zusammenfassung 

In diesem Beitrag haben wir einen Cache-Poisoning-Angriff in CI-Workflows beschrieben, der vor den Augen des DevSecOps-Teams verborgen bleibt, und Abhilfemaßnahmen besprochen.

Diese Inhalte werden Ihnen von Scribe Security zur Verfügung gestellt, einem führenden Anbieter von End-to-End-Sicherheitslösungen für die Software-Lieferkette, der modernste Sicherheit für Code-Artefakte sowie Code-Entwicklungs- und Bereitstellungsprozesse in der gesamten Software-Lieferkette bietet. Weitere Informationen.