Der NPM-Wurm ist zurück – und er ist weitaus gefährlicher (TanStack gehackt)
BBetter Stack
Computing/SoftwareManagementInternet Technology
Transcript
00:00:00Shai Hulud ist zurück für ein viertes Sequel.
00:00:02Diesmal zielt es auf Pakete wie TanStack,
00:00:04buchstäblich Stunden nachdem ich dieses Video über Next.js veröffentlicht hatte,
00:00:07was ein brillantes Timing von mir war.
00:00:08Dies ist ein massiver NPM-Supply-Chain-Angriff,
00:00:11der mehr als nur TanStack betrifft.
00:00:13Er traf auch Pakete wie UiPath, Mistral
00:00:15und 160 weitere Pakete,
00:00:17sogar PyPy-Pakete wie Guardrails.ai.
00:00:20Was das Ganze noch amüsanter macht,
00:00:22ist, dass es einen Deadman-Switch enthielt,
00:00:24also wenn es erkannte, dass du deine gestohlenen Schlüssel geändert hast,
00:00:26würde es deinen gesamten PC löschen,
00:00:28und es hatte sogar globale Politik integriert.
00:00:30Also lasst uns eintauchen.
00:00:36Für dieses Sequel hat der Wurm dasselbe Ziel:
00:00:39Anmeldedaten von Entwickler-Rechnern und CI/CD-Runnern stehlen,
00:00:42dann diese Daten nutzen, um weitere Pakete zu erreichen.
00:00:44Für TanStack bedeutete das, 84 bösartige Versionen
00:00:47über 42 TanStack-Pakete in wenigen Minuten zu veröffentlichen.
00:00:51Ich gehe nun durch, wie sie es geschafft haben,
00:00:52TanStack überhaupt zu infizieren,
00:00:54aber zuerst sehen wir uns an, was die Malware tut,
00:00:56wenn du eines dieser betroffenen Pakete installierst.
00:00:58In den bösartigen Paketen
00:00:59würdest du eine neue Datei namens routerinit.js finden,
00:01:02sowie eine injizierte optionale Abhängigkeit,
00:01:04die zu etwas führt, das aussieht wie
00:01:05ein legitimer TanStack-Router-GitHub-Link,
00:01:08aber eigentlich ein verwaister Commit im Fork des Angreifers ist.
00:01:10Das ist einfach die Art, wie GitHub mit Fork-Links umgeht,
00:01:13sodass die URL tatsächlich so aussehen kann,
00:01:14als gehöre sie zum Originalprojekt,
00:01:16obwohl der Commit tatsächlich von einem Fork stammt.
00:01:18In diesem Fork gibt es ein Lifecycle-Skript,
00:01:20prepare, das bun run task runner JS ausführt,
00:01:22und am Ende exit 1 hat.
00:01:24Das ist nur ein cleverer Weg, die optionale Abhängigkeit fehlschlagen zu lassen,
00:01:27nachdem die Nutzlast bereits ausgeführt wurde,
00:01:28sodass die Installation wie gewohnt weitergeht,
00:01:30und es hinterlässt weniger offensichtliche Spuren in deinen Installationsprotokollen.
00:01:33Vielleicht ist dir auch aufgefallen, dass das nicht
00:01:35die routerinit.js Datei ausführt, von der ich sagte, sie sei
00:01:37zu Beginn in die Pakete injiziert worden,
00:01:38aber für jetzt, stell dir einfach vor, diese beiden Dateien
00:01:40spielen exakt dieselbe Rolle mit unterschiedlichen Namen.
00:01:42Die Kurzfassung ist: Wenn du das installierst,
00:01:44wird dieses Skript ausgeführt.
00:01:46Das Erste, was das Skript zu tun versucht,
00:01:47ist, sich vom offensichtlichen Installationsablauf abzukoppeln,
00:01:50also prüft es, ob es bereits
00:01:51im Hintergrund läuft, und wenn nicht,
00:01:53forkt es eine losgelöste Kopie von sich selbst
00:01:54und beendet das übergeordnete Skript sauber.
00:01:57Auf diese Weise zeigen deine npm-Installationsprotokolle
00:01:58keine Ausgabe des Skripts,
00:02:00da die Malware sich nun von diesem Prozess gelöst hat
00:02:01und im Hintergrund läuft.
00:02:04Danach macht es etwas wirklich Cleveres.
00:02:06Es schreibt Kopien von sich selbst
00:02:07in dein Claude-Code-Hooks-Verzeichnis,
00:02:08konfiguriert dann deine Claude-Einstellungen,
00:02:10um diesen Hook jedes Mal auszuführen, wenn du Claude Code
00:02:12in diesem Projekt verwendest.
00:02:13Auf diese Weise kann es die ursprüngliche Installation überdauern
00:02:16und immer wieder neu ausgelöst werden, jedes Mal,
00:02:17wenn du Claude Code in diesem Projekt öffnest.
00:02:20Es macht das Gleiche sogar mit dem Task-Runner von VS Code,
00:02:22dupliziert sich dort hinein,
00:02:23sodass du bei den automatischen Arbeitsbereichsfunktionen von VS Code
00:02:26exakt dasselbe Problem hast.
00:02:28Es richtet sogar einen Betriebssystem-Dienst ein,
00:02:29genannt GitHub Token Monitor,
00:02:31aber darauf kommen wir zurück,
00:02:32denn der ist absolut diabolisch.
00:02:34Es ist auch ziemlich diabolisch,
00:02:35dass du noch nicht abonniert hast.
00:02:37Als Nächstes tut die Nutzlast das Folgende:
00:02:38Sie macht sich daran, deine Anmeldedaten zu stehlen,
00:02:40und sie versucht es mit allem.
00:02:41In GitHub Actions sucht sie nach Anmeldedaten
00:02:43und Geheimnissen in der Runner-Umgebung.
00:02:45Genauer gesagt, sie durchsucht den GitHub Actions
00:02:47Runner-Worker-Prozessspeicher
00:02:48nach deinen Workflow-Geheimnissen,
00:02:50einschließlich maskierter Geheimnisse,
00:02:52und sie fügt sogar einen gefälschten CodeQL-ähnlichen GitHub-Workflow ein,
00:02:55der deine Repository-Geheimnisse serialisiert
00:02:57und später exfiltriert.
00:02:58Sie sucht auch nach AWS-Geheimnissen,
00:03:00zuerst geht sie auf deine Umgebungsvariablen
00:03:02und lokalen Konfigurationsdateien,
00:03:03aber dann geht sie auch auf AWS-Metadatendienste
00:03:06wie IMDS v2 und ECS-Task-Metadaten los.
00:03:09Für Kubernetes stiehlt sie Service-Account-Token
00:03:11und Zertifikate, was ihr In-Cluster-API-Zugriff ermöglicht,
00:03:14mit welchen rollenbasierten Zugriffsberechtigungen
00:03:17auch immer der Service-Account dieses Pods ausgestattet war,
00:03:19was in schlecht konfigurierten Clustern
00:03:21extrem weitreichend sein kann,
00:03:22manchmal effektiv Administratorzugriff.
00:03:24Und um das noch schlimmer zu machen,
00:03:25geht sie auch auf HashiCorp Vault los,
00:03:27sammelt alle deine Vault-bezogenen Umgebungsvariablen
00:03:29und Token,
00:03:30nutzt dann welchen Kubernetes-Zugriff auch immer sie hat,
00:03:32um alle deine in Vault verwalteten Geheimnisse abzurufen.
00:03:34Und das alles ist nur das, was sie
00:03:35mit deinen CI-Bereitstellungen macht.
00:03:37Wenn sie auf deiner Workstation ist,
00:03:38geht sie auf alle deine SSH-Schlüssel los,
00:03:39deine NPM-Anmeldedaten,
00:03:41deine Git-Anmeldedaten,
00:03:42Shell-Verlauf,
00:03:43Cloud-Provider-Anmeldedaten,
00:03:44Krypto-Schlüssel,
00:03:45Signal,
00:03:45Slack
00:03:45und Discord-Dateien.
00:03:46Und obendrein all dem
00:03:47extrahiert sie deinen Claude-Code-Sitzungsverlauf.
00:03:49Wenn du also jemals Claude-Anmeldedaten gegeben
00:03:51oder es Dateien hast lesen lassen, die Anmeldedaten enthielten,
00:03:53hat es auch darauf Zugriff.
00:03:55Also ja, wie ich sagte,
00:03:56sie waren hinter absolut allem her,
00:03:57an das sie herankommen konnten,
00:03:58und dann exfiltrierten sie diese Daten
00:04:00über das Session-Messenger-Netzwerk.
00:04:02Und als Backup
00:04:02legten sie diese gestohlenen Daten auch in GitHub-Repos ab.
00:04:04Und passend zum Thema all ihrer Angriffe
00:04:05sind diese Branches nach Dune-Referenzen benannt.
00:04:07Also, es hat deine Anmeldedaten.
00:04:09Es kann nicht schlimmer werden, oder?
00:04:11Nun, ja.
00:04:12Ja, es kann.
00:04:13Obendrein
00:04:14wenn du dich an den Dienst erinnerst,
00:04:15den ich erwähnte, der sich auf deinem Rechner einrichtet,
00:04:16nun, dieser überwacht deine GitHub-Token
00:04:18und exfiltriert sie ständig erneut.
00:04:19Aber er prüft auch jede Minute,
00:04:21ob das Token noch gültig ist.
00:04:22Und wenn nicht,
00:04:24führt er RMRF auf deinem Benutzerverzeichnis aus,
00:04:25und löscht alles.
00:04:27Er versucht auch ein NPM-Token zu erstellen
00:04:28mit deinen Anmeldedaten,
00:04:30mit der Beschreibung:
00:04:31Wenn du dieses Token widerrufst,
00:04:32löschen wir den Computer des Besitzers,
00:04:33was impliziert, dass er dasselbe
00:04:35auch für NPM-Token macht.
00:04:36Wenn du also diese Token widerrufst,
00:04:38bevor du deine Maschine isolierst
00:04:39und diesen Hintergrundprozess entfernst,
00:04:40kann die Nutzlast deinen PC zerstören,
00:04:42was einfach absolut diabolisch ist.
00:04:44Und als Seitenbemerkung hier,
00:04:46die Python-Variante dieses Angriffs
00:04:47tut im Grunde dasselbe,
00:04:48aber sie enthält auch eine Prüfung,
00:04:49um zu sehen, ob die Sprache deiner Maschine Russisch ist.
00:04:51Wenn ja,
00:04:53stoppt sie einfach.
00:04:53Und wenn deine Maschine anscheinend
00:04:54aus Israel oder dem Iran stammt,
00:04:55generiert sie eine Zufallszahl
00:04:56zwischen 1 und 6.
00:04:58Und wenn diese Zahl 2 ist,
00:04:59führt sie einen zerstörerischen Löschbefehl aus
00:05:00und versucht, eine MP3
00:05:01in voller Lautstärke abzuspielen.
00:05:03Leider
00:05:04konnte ich nicht herausfinden,
00:05:05was das für eine MP3 ist.
00:05:05Wie auch immer,
00:05:07jetzt, wo es das alles getan hat,
00:05:07das Schlimmste kommt erst noch,
00:05:08denn das war nur Stufe 1.
00:05:09Stufe 2 ist Selbstverbreitung,
00:05:11und das ist der gefährlichste Teil
00:05:13dieses Angriffs.
00:05:15Zuerst
00:05:16sucht es auf deiner Maschine
00:05:16nach gültigen NPM-Token,
00:05:17mit denen es veröffentlichen kann,
00:05:19ohne Zwei-Faktor-Authentifizierung.
00:05:19Und wenn es eines findet,
00:05:21scannt es alle Pakete,
00:05:22auf die dieses Konto Zugriff hat,
00:05:24verwendet dann diese Anmeldedaten,
00:05:26um sich selbst diesen Paketen hinzuzufügen
00:05:26und neue infizierte Versionen zu veröffentlichen.
00:05:28Das ist offensichtlich ziemlich schlecht,
00:05:30aber du solltest wahrscheinlich auch keine
00:05:32veröffentlichten Token
00:05:33herumliegen haben,
00:05:33die die Zwei-Faktor-Authentifizierung
00:05:34die die
00:05:35Zwei-Faktor-Authentifizierung umgehen können.
00:05:36Die deutlich beängstigendere Version davon
00:05:38ist das,
00:05:39was passiert, wenn es in Ihrer CI/CD läuft.
00:05:41Denn bei CI
00:05:42braucht der Angreifer
00:05:43kein langlebiges NPM-Token,
00:05:44da gute Setups
00:05:45oft auf OIDC setzen,
00:05:47was eigentlich sicherer sein soll.
00:05:48Im Grunde
00:05:49anstatt
00:05:50ein NPM-Token als Geheimnis zu speichern,
00:05:51beweist GitHub Actions gegenüber NPM:
00:05:53Hey,
00:05:53ich bin dieses Repo,
00:05:54das diesen Workflow ausführt,
00:05:55auf diesem Branch,
00:05:56und NPM gibt ihm dann
00:05:57ein kurzlebiges Veröffentlichungs-Token.
00:05:59Das Problem dabei ist jedoch,
00:06:00wenn das Skript Zugriff
00:06:01auf eine vertrauenswürdige GitHub Actions-Umgebung erhält,
00:06:03kann es sich an die gleiche Stelle stellen
00:06:04wie ein legitimer Herausgeber.
00:06:06Die Malware kann also
00:06:07die OIDC-bezogene Umgebung verwenden,
00:06:08die GitHub dem Job bereitstellt,
00:06:10um ein OIDC-JWT-Token anzufordern
00:06:12vom Token-Endpunkt von GitHub,
00:06:14dann tauscht es dieses JWT-Token
00:06:16mit NPM
00:06:17gegen ein kurzlebiges Veröffentlichungs-Token,
00:06:18durch das vertrauenswürdige
00:06:19Veröffentlichungssystem von NPM,
00:06:20und jetzt kann es veröffentlichen,
00:06:22ohne jemals
00:06:22ein permanentes NPM-Token zu stehlen
00:06:24und völlig legitim auszusehen.
00:06:26In diesem Fall
00:06:26bündelt die Malware eine Kopie
00:06:27dieser “router init.js”-Datei
00:06:29in die Tabelle des Pakets,
00:06:30fügt dann die bösartige
00:06:31optionale Abhängigkeit hinzu,
00:06:32dann veröffentlicht es alles
00:06:33als das neueste Tag
00:06:34für dieses Paket,
00:06:35sodass, wenn jemand
00:06:35oder irgendeine CI/CD-Pipeline
00:06:37diese Pakete installiert,
00:06:38der Kreislauf von vorne beginnt,
00:06:40und sich so weit ausbreitet,
00:06:40wie es nur möglich ist.
00:06:42Das ist also
00:06:42ziemlich verrückt, oder?
00:06:43Aber jetzt konzentrieren wir uns
00:06:44auf Patient Null,
00:06:46TanStack.
00:06:46Wie wurden sie überhaupt
00:06:47infiziert?
00:06:48Nun,
00:06:49laut ihrem eigenen Post-Mortem
00:06:50missbrauchte der Angreifer
00:06:51diese GitHub Actions-Pipeline.
00:06:53Sie begannen den Tag
00:06:53bevor die bösartigen Pakete
00:06:54tatsächlich veröffentlicht wurden,
00:06:56indem sie einen Fork
00:06:57von TanStack Router erstellten,
00:06:58aber sie benannten diesen
00:06:59tatsächlich in “configuration” um,
00:06:59um es schwerer zu machen,
00:07:01ihn zu finden, wenn man
00:07:02die offensichtlichen Namen der Forks durchsuchte.
00:07:04Dann fügten sie
00:07:04einen bösartigen Commit
00:07:05zu diesem Fork hinzu,
00:07:06den sie fälschlicherweise als “Claude” autorisierten,
00:07:07und es hatte eine Commit-Nachricht,
00:07:07die mit
00:07:08skip CI
00:07:09präfixiert war,
00:07:10sodass es nicht sofort
00:07:11CI bei einem Push-Event ausführte.
00:07:13Am nächsten Tag
00:07:13eröffneten sie dann einen PR
00:07:14gegen TanStack Router
00:07:15mit dem Namen “Work in Progress
00:07:16Simplify History Build”.
00:07:18Und hier
00:07:18passiert der eigentliche Angriff.
00:07:20Das TLDR ist,
00:07:21dass TanStack einen “bundle-sized”
00:07:22GitHub Actions-Workflow hatte,
00:07:23der “pull request target” verwendete,
00:07:25und das ist bemerkenswert,
00:07:26weil “pull request target”
00:07:27tatsächlich
00:07:28im Sicherheitskontext
00:07:29des Basis-Repos läuft,
00:07:30nicht des Forks.
00:07:31Das bedeutet, dass es Zugriff
00:07:32auf den Cache-Bereich des Basis-Repos
00:07:33und sein GitHub-Token hat.
00:07:35Also dieser Workflow
00:07:35checkte den PR aus,
00:07:36installierte seine Abhängigkeiten,
00:07:38und führte einen Benchmark-Build aus.
00:07:39Das Problem ist jedoch,
00:07:40dass dieser Fork
00:07:40bösartigen Code enthielt.
00:07:41In diesem Fall
00:07:42war es ein V-Setup-Skript,
00:07:43das den
00:07:44PMPM-Paketspeicher vergiftete,
00:07:45unter dem exakten Cache-Schlüssel,
00:07:47den die Release-Aktion
00:07:48später verwenden würde.
00:07:49Sie haben diesen tatsächlich vorausberechnet
00:07:50aus der öffentlichen
00:07:51PMPM-Lock-Datei,
00:07:52unter Verwendung der exakt gleichen Formel,
00:07:54die auch der Workflow verwendet.
00:07:56Sobald dieser vergiftete Cache
00:07:57gespeichert war,
00:07:57setzten sie diesen Branch
00:07:58tatsächlich zurück,
00:07:59um ihn an den aktuellen
00:07:59Main-Branch anzupassen,
00:08:00sodass der sichtbare PR
00:08:01wie ein Null-Dateien-No-Op aussah,
00:08:02und dann schlossen sie diesen PR
00:08:03und löschten
00:08:04den bösartigen Branch.
00:08:05Von außen betrachtet
00:08:06sieht es also so aus,
00:08:07als ob absolut
00:08:07nichts passiert wäre,
00:08:08aber sie haben
00:08:09den Cache der GitHub-Aktion vergiftet.
00:08:10Das bedeutet,
00:08:11dass acht Stunden später,
00:08:12als ein normaler Maintainer
00:08:13einen nicht damit zusammenhängenden PR
00:08:14in den Main mergte,
00:08:15er TanStacks
00:08:16Release-Workflow auslöste,
00:08:17der den
00:08:18vergifteten PMPM-Cache wiederherstellte,
00:08:19und nun vom Angreifer kontrollierter Code
00:08:20innerhalb dieser Release-Aktion lief.
00:08:22Er verwendete dann die gleiche Logik
00:08:23mit OIDC,
00:08:24um ein NPM-Veröffentlichungstoken zu erhalten,
00:08:25und schaffte es,
00:08:2684 Versionen seiner selbst
00:08:28über 42 TanStack-Pakete zu veröffentlichen,
00:08:29und es musste nicht einmal
00:08:30den Schritt der Paketveröffentlichung
00:08:32der Aktion erreichen.
00:08:33Witzigerweise
00:08:34schlug die Aktion tatsächlich fehl,
00:08:35weil einige Tests fehl schlugen,
00:08:36also erreichte sie diesen Schritt nie,
00:08:36aber der bösartige Code wurde trotzdem ausgeführt
00:08:37und veröffentlichte alle trotzdem.
00:08:39Der Angreifer schaffte es also,
00:08:40drei Vertrauensgrenzen zu verknüpfen.
00:08:41Zuerst
00:08:43konnte der PR-Fork-Code
00:08:43den Cache des Basis-Repos vergiften,
00:08:44dann wurde dieser Cache
00:08:46innerhalb des echten
00:08:47Release-Workflows wiederhergestellt,
00:08:47dann hatte der echte
00:08:48Release-Workflow OIDC-Berechtigungen,
00:08:49die sich in
00:08:51NPM-Veröffentlichungszugriff verwandelten,
00:08:52sodass sie das veröffentlichen konnten,
00:08:53was wie vollkommen legitime Pakete aussieht.
00:08:54Und das ist es,
00:08:56was ich gerade
00:08:57an Supply-Chain-Angriffen
00:08:58wirklich beängstigend finde.
00:08:59Sie gehen weg davon,
00:08:59das Token eines Maintainers zu stehlen,
00:09:01hin zum Missbrauch
00:09:02des gesamten CI/CD-Systems selbst,
00:09:03und das bedeutet,
00:09:05dass all unsere Vertrauenssignale
00:09:05anfangen,
00:09:06für den Angreifer zu arbeiten.
00:09:07Dies war ein signiertes Paket
00:09:08mit gültiger Provenienz,
00:09:10veröffentlicht durch einen echten Workflow.
00:09:11Also da haben wir es,
00:09:12das ist ShaiHalud4,
00:09:13und wenn Sie prüfen wollen,
00:09:14ob Sie von irgendeinem dieser Pakete
00:09:15kompromittiert wurden,
00:09:16werde ich unten Links
00:09:18zu Blog-Posts hinterlassen,
00:09:19das ist ShaiHalud4,
00:09:20wie Sie das herausfinden können
00:09:21und was Sie tun können,
00:09:21falls Sie eines davon
00:09:23installiert haben.
00:09:23Lassen Sie mich in den Kommentaren wissen,
00:09:25was Sie
00:09:25über all das
00:09:26und das NPM-Ökosystem denken,
00:09:27während Sie da unten sind,
00:09:28abonnieren Sie,
00:09:29und wie immer,
00:09:30wir sehen uns
00:09:30beim nächsten Mal.
00:09:31und das NPM-Ökosystem,
00:09:33und wenn du schon dabei bist,
00:09:33...
00:09:34und wie immer,
00:09:34sehen wir uns beim nächsten Mal.
Community Posts
No posts yet. Be the first to write about this video!
Write about this video