Ectoplasm npm-Installation Hooks Diese Methode zum Stehlen von AWS-Zugangsdaten

Ektoplasma: npm install hooks die AWS-Anmeldeinformationen hinter einem reinen Container-Trigger sammeln

TL; DR

Eine Gruppe von fünf npm-Pakete, veröffentlicht über zwei Account-Handles, versandt postinstall Ein Hook, der Cloud-Zugangsdaten vom Host ausliest und sie extern versendet. Die Pakete tragen kryptische Namen. coral-wraith, ecto-corsair-whisper-6f3b9, ecto-corsair-flag-x9m4, ecto-rust-read-f3a9c1, ecto-nightly-spirit — und alles, was sie sammeln, in eine gefälschte Serie umzuwandeln ecto_module: YAML-Manifest vor der Übertragung. Wir verfolgen den Cluster als Ektoplasma.

Die Nutzlast wird nur ausgeführt, wenn eine bestimmte Umgebung erkannt wird: ein Host, dessen Name ein 12-stellige Hexadezimalzeichenkette und ein Arbeitsverzeichnis unter /app/node_modules — die Struktur eines containerisierten Builds oder CI-Workers. Wenn diese Hürde genommen wird, fragt der Hook die AWS-Instanzmetadatendienst (IMDSv2) für IAM-Rollenanmeldeinformationen, listet auf AWS Secrets Manager in drei Regionen, gibt Umgebungsvariablen aus, liest Dateien unter /appund durchsucht nach Capture-the-Flag-Zeichenketten. Anschließend werden die Ergebnisse auf zwei Arten exfiltriert: über ein Beacon an ein webhook.site Collector und ein Manifest-PUT an einen Raw-IP-Endpunkt, mit einer Liste von Localhost-zuerst-Fallbacks.

Die späteren Paketbeschreibungen lauteten: „CTF-Payload für Verdaccio-Lieferkettentests“. Wir berichten über diese Selbstbeschreibung als beobachtbare Tatsache. Das Verhalten selbst – Live-Zugriff auf eine öffentliche IP-Adresse, tatsächliche IMDS-Anmeldeinformationen, tatsächliche Secrets-Manager-Aufrufe – ist unabhängig von der Bezeichnung unverändert und der Grund, warum diese Versionen als bösartig eingestuft wurden.

Ein Name in der Gruppe, coral-wraith, beließ es nicht bei einer einzigen Veröffentlichung. Es wurde innerhalb weniger Stunden in Dutzenden von Versionen neu aufgelegt – 1.0.0 Klettern zu 6.0.0 — und eine frühere Auflage desselben Titels hatte aufgeblähte 9999.0.x Versionsnummern, die klassische Form eines Versuch der AbhängigkeitsverwirrungTrotz dieser Umstrukturierung hat sich die Nutzlast sichtbar weiterentwickelt: von einem einmaligen Host-Enumerations-Beacon zu einem vollständigen AWS-Credential-Pivot, der in Umgebungsprüfungen eingebettet ist, die ihn außerhalb seines beabsichtigten Ziels unauffällig halten.

Pakete 5 Namen; coral-wraith allein wurde es in Dutzenden von Versionen neu veröffentlicht
Ökosystem npm
Vektor installieren postinstall Lebenszyklusskript
Hauptziel AWS IAM-Rollenanmeldeinformationen + Secrets Manager-Geheimwerte, Umgebungsvariablen, /app Dateien
Exfil webhook.site Beacon + Raw-IP C2 PUT
Triggergate 12-stelliger Hexadezimal-Hostname + /app/node_modules Das aktuelle Arbeitsverzeichnis (cwd) sowie eine Umgebungsprüfung, die die Nutzdaten außerhalb dieses Kontextes unterdrückt.
Schwere Highs — Offenlegung von Cloud-Anmeldeinformationen und verwalteten Geheimnissen durch containerisierte Build- und Laufzeitumgebungen

Angriffsanatomie

Jedes Paket im Cluster wird auf die gleiche Weise erstellt: ein nahezu leerer index.js (module.exports = {}), eine Einzeiler paket.json Drehbuch — “postinstall”: “node postinstall.js” — und die Nutzlast in postinstall.jsDie Installation des Pakets genügt, um den Hook auszuführen; ein Import oder Aufruf ist nicht erforderlich.

Das Targeting-Gate. Bevor die Nutzlast der Ecto-Familie irgendetwas unternimmt, überprüft sie ihre Umgebung:

function isAppWorker():   host = os.hostname()   if host does NOT match /^[0-9a-f]{12}$/  -> exit   if cwd does NOT contain "/app/node_modules" -> exit   if cwd contains "/tmp/npm-safe"            -> exit   otherwise -> proceed

Ein 12-stelliger Hexadezimal-Hostname ist die Standardform, die Docker einem Container zuweist, und /app/node_modules ist ein herkömmlicher Installationspfad innerhalb eines Containers. Die dritte Klausel bricht ab, wenn der Pfad wie ein isoliertes Extraktionsverzeichnis aussieht. Der Effekt ist, dass die Nutzdaten auf einem Entwickler-Laptop oder in einer Analyse-Sandbox inaktiv bleiben und erst innerhalb eines containerisierten Build- oder Runtime-Workers aktiviert werden – also genau in der Umgebung, die am ehesten aktive Cloud-Zugangsdaten enthält. Das erste Paket im Cluster, Korallengeist, verfügt über kein solches Gate und führt seine (einfachere) Sammlung bedingungslos aus.

KollektionWenn das Tor passiert wird, fährt der Haken aus. execFileSync(„/bin/sh“, [„-c“, …]) und führt einen einzelnen zusammengesetzten Befehl aus, der in folgender Reihenfolge ausgeführt wird:

1. PUT /latest/api/token to 169.254.169.254          (IMDSv2 token request) 2. GET .../iam/security-credentials/                  (IAM role name) 3. GET .../iam/security-credentials/<role>            (temporary credentials) 4. dump env | sort                                    (environment variables) 5. list /app (excl. node_modules) + cat first 15      (application files) 6. aws secretsmanager list-secrets                    (us-east-1, eu-west-1, eu-central-1) 7. scrape readable files for HTB{...}                 (capture-the-flag strings)

Die Schritte 1–3 entsprechen einem Lehrbuchbeispiel für den IMDSv2-Abruf: ein Sitzungstoken anfordern und dieses dann als … anhängen. X-aws-ec2-metadata-token Header zum Abrufen der IAM-Rolle der Instanz und deren temporären Zugriffsschlüsseln. Die Entscheidung für die Implementierung von IMDSv2 anstelle des einfacheren, nicht authentifizierten IMDSv1. STARTE Bemerkenswert ist, dass die Nutzlast selbst auf Instanzen funktioniert, die für tokenbasierten Metadatenzugriff konfiguriert sind – die von AWS empfohlene Sicherheitsmaßnahme. Die in Schritt 3 zurückgegebenen Anmeldeinformationen sind nur kurzlebig. AccessKeyId/SecretAccessKey/Token Tripel sind auf die Rolle der Instanz beschränkt; alles, was diese Rolle tun kann, kann der Inhaber dieser Schlüssel während der gesamten Lebensdauer der Anmeldeinformationen tun.

Die Schritte 4–6 erweitern den Betrachtungsbereich. env Der Dump erfasst alles, was der Build- oder Laufzeitprozess geerbt hat – in der Praxis befinden sich hier meist Registry-Token, Datenbankverbindungszeichenfolgen und API-Schlüssel. / app Der Dateidurchlauf liest bis zu fünfzehn Anwendungsdateien außerhalb des Dateibereichs. node_modules, welche Oberflächenkonfigurationen ermöglichen, .env Dateien oder Quelle. Schritt 6 ruft auf aws secretsmanager list-secrets In drei Regionen werden die in den Schritten 1–3 abgerufenen Anmeldeinformationen zur Authentifizierung dieser Aufrufe verwendet, sodass der IMDS-Lesevorgang und die Enumerationskette des Secrets Managers zu einer einzigen Eskalation zusammengeführt werden: Instanzrolle → verwaltetes Geheimnisinventar. Schritt 7 ist eine Anspielung auf das Capture-the-Flag-Schema – wenn ein HTB{…} Wird eine Flagge gefunden, wird sie allein gesendet, andernfalls wird der gesammelte Rohdaten-Blob in vier Teile aufgeteilt und gesendet.

Spätere Versionen im Cluster treiben die Eskalation weiter voran. Anstatt bei einer Inventarisierung stehen zu bleiben, analysieren sie die IMDS-Antwort und exportieren die temporären Schlüssel als AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN Umgebungsvariablen, bestätigen Sie die Identität mit aws sts get-caller-identityund dann durchlaufen Sie alle von zurückgegebenen Geheimnisse. Liste Geheimnisse Aufruf aws secretsmanager get-secret-value bei jedem einzelnen - um den geheimen Inhalt und nicht nur dessen Namen abzurufen. Dieselben Versionen lesen auch prozesssubstituierte Flag-Binärdateien (/readflag und Freunde) und versuchen Sie Ladelauf gegen jedes Rust-Projekt, das unter / appund erweitert so die Erfassung über Cloud-Zugangsdaten hinaus auf alles, was die Build-Umgebung offenlegt.

Diese späteren Versionen schützen sich auch aggressiver vor Zugriffen. Zusätzlich zum 12-stelligen Hexadezimal-Hostnamen und /app/node_modules Die Payload prüft die Konfiguration der aktiven Paketregistrierung und den Arbeitsverzeichnispfad und beendet sich stillschweigend, wenn diese auf einen Analyse- oder Spiegelungskontext anstatt auf ein aktives Ziel hinweisen. Dadurch verhält sich die Payload in den meisten Prüfumgebungen unauffällig und führt ihre vollständige Datenerfassung nur dann durch, wenn sie sich auf einem echten Container-Host befindet.

ExfiltrationDie gesammelten Daten verlassen den Host über zwei Kanäle. Erstens über ein Beacon. jetzt lesen zu einem festen webhook.site Ein Collector enthält den Hostnamen, die numerische UID, das Arbeitsverzeichnis und bis zu 120 KB gesammelter Daten. Anschließend werden die Daten in ein gefälschtes YAML-„Modulmanifest“ eingebunden. SETZEN zu /api/modules/ auf einem Zielserver:

ecto_module:   name: "<flag-or-chunk-0>"   version: "1.0.0"   power_level: "<chunk-1>"   ship_deck: "<chunk-2>"   cargo_hold: "<chunk-3>"

Die Manifestfeldnamen (Leistungsstufe, Schiffsdeck, Frachtraum) sind Dekoration – die gestohlenen Daten sind in den Zeichenkettenwerten versteckt, weshalb ein Netzwerkmonitor eher einen harmlosen Upload eines Paketregistrierungsmanifests als einen offensichtlichen Datenabfluss erkennt. Der Beacon-Kanal überträgt mehr: die jetzt lesen Körper zu webhook.site Beinhaltet den Hostnamen, die numerische UID, das Arbeitsverzeichnis und bis zu 120 KB des gesammelten Blobs, sodass bereits ein einziger erfolgreicher Beacon die vollständige Erfassung liefert. webhook.site ist ein kostenloser Anfrageprüfungsdienst; die Verwendung als Sammler bedeutet, dass der Betreiber niemals eine eigene Empfangsinfrastruktur für diesen Kanal aufbauen muss, und die aufgezeichneten Anfragen bleiben im Speicher des Dienstes erhalten.

Das Manifest SETZEN geht eine Ausweichliste durch, die mit mehreren beginnt 127.0.0.1/localhost Häfen und fällt dann zu drei öffentlichen Adressen im `154.57.164.0/24` Der Bereich wird durchlaufen, wobei der erste Endpunkt mit einem 2xx-Statuscode antwortet. Die Reihenfolge, bei der localhost zuerst berücksichtigt wird, entspricht der Selbstbeschreibung des „Verdaccio-Tests“ (eine lokale Registry auf Loopback), aber die Fallbacks auf öffentliche IP-Adressen bedeuten, dass die Daten den Host verlassen, sobald Loopback nicht aktiv ist – also auf jedem Rechner, der nicht der Testrechner des Autors ist.

Geschichte

Das Cluster zeigt ein schrittweises Leistungswachstum anstelle eines einzelnen Leistungsabfalls. Wir ordnen es nach dem beobachteten Verhalten, nicht nach der veröffentlichten Systemzeit:

Praktikum Pakete / Versionen Verhalten
Früher Lauf coral-wraith 9999.0.x Aufgeblähte Versionsnummern deuten auf einen Versuch der Abhängigkeitsverwirrung hin; Aufzählung und Exfiltration während der Installation.
Samen coral-wraith 1.0.0 postinstall sammelt ID-, Umgebungs- und Flag-Dateien; ein einzelner PUT-Befehl wird ausgeführt. 154[.]57[.]164[.]71:30782, Marker ECT-472839
Schnelle Iteration coral-wraith 1.0.1 → 6.0.0 Dutzende Veröffentlichungen innerhalb weniger Stunden; Nutzlastzuwachs isAppWorker() Gate, IMDSv2-Anmeldeinformationen abrufen, das vollständige get-secret-value Pivot-Punkte, die Überprüfung der Registry-/Pfadumgebung und Dual-Sink-Markierungen
Parallele Namen ecto-corsair-whisper-6f3b9 1.0.14–1.0.18 Gleiche Nutzlast mit Sperre; webhook.site Beacon- und Multi-Endpunkt-Fallback-Liste
Varianten ecto-rust-read-f3a9c1 1.0.1–1.0.2 Fügt zusätzliche Spülbeckenmarkierungen hinzu ECT-987654, ECT-654321, ECT-839201
Varianten ecto-corsair-flag-x9m4 1.0.0, ecto-nightly-spirit 1.1.0 Gleiche Nutzlast mit Zugangskontrolle, gleiches C2 und Beacon

Das charakteristische Merkmal des Clusters ist sein Veröffentlichungsrhythmus: Anstatt eines Pakets und einer Version wird derselbe Name in schneller Folge immer wieder neu veröffentlicht, wobei jede Version eine kleine Variation der vorherigen darstellt, zusammen mit einer Handvoll anders benannter Versionen, die dieselbe Nutzlast enthalten. Innerhalb des Flüstern Die Codefamilie spaltete sich in zwei eng verwandte Varianten auf – eine löste zwei kritische Erkennungen aus, die andere drei (eine zusätzliche Dateilesesenke) –, aber beide führen zur gleichen Nutzlast; der Unterschied liegt in einer Codeabweichung, nicht in einer Verhaltensänderung. Versionen von Flüstern Werte außerhalb des analysierten Bereichs (bis mindestens 1.0.25 zum Zeitpunkt der Erstellung dieses Dokuments) wurden live im Register beobachtet, und die Korallengeist Der Name stieg im selben Fenster weiterhin seine eigene Versionsleiter hinauf.

Kompromissindikatoren

Alle unten aufgeführten Indikatoren wurden aus dem Quellcode des Pakets auf der Festplatte extrahiert. Netzwerkindikatoren sind deaktiviert.

Netzwerk

Indikator Funktion / Rolle (Role) *
hxxp://154[.]57[.]164[.]71:30782 C2 PUT-Ziel (coral-wraith)
hxxp://154[.]57[.]164[.]80:30543 C2 PUT Fallback (ecto-*)
hxxp://154[.]57[.]164[.]82:31250 C2 PUT Fallback (ecto-*)
hxxp://154[.]57[.]164[.]71:31289 C2 PUT Fallback (ecto-*)
hxxps://webhook[.]site/602a4c72-7033-4e28-92ea-dc66e59206e5 Beacon-Sammler
169[.]254[.]169[.]254/latest/... IMDSv2-Anmeldeinformationen lesen (Zielseite, AWS-Metadaten)

Verhaltens-/Datei

Indikator Funktion / Rolle (Role) *
"postinstall": "node postinstall.js" Vektor installieren
ecto_module: YAML mit power_level / ship_deck / cargo_hold Tasten Exfil-Manifestschema
Spülbeckenmarkierungen ECT-472839, ECT-987654, ECT-654321, ECT-839201 C2-Pfadsegment /api/modules/<marker>
isAppWorker() Gate: Host /^[0-9a-f]{12}$/, cwd enthält /app/node_modules Aktivierungsbedingung
aws secretsmanager list-secrets gegenüber us-east-1, eu-west-1, eu-central-1 Aufzählung von Geheimnissen
HTB{...} Regex-Scraping Capture-the-Flag-Ernte

Dateihashes (sha256, erfasst zum Analysezeitpunkt)

Reichen Sie das sha256
coral-wraith/postinstall.js ce5ff035cfdfed1d0015446424b352c27b66bcb77e9fdb0a51e4245199146824
ecto-corsair-whisper-6f3b9 1.0.18/postinstall.js b58432acba376aa6976f0490d9a1c04257ccdbc856d8390260c50322d63e31c3

Attribution und beobachtetes Verhalten

Die fünf Paketnamen wurden unter zwei npm-Accounts veröffentlicht, aber sie teilen genügend Infrastruktur, um sie als einen Cluster zu behandeln: denselben ecto_module Manifestschema, das gleiche ECT-472839 primärer Senkenmarker, derselbe webhook.site Collector-ID und C2-Endpunkte im selben 154.57.164.0/24` Block. Das Seed-Paket (`coral-wraith, einfacher und nicht eingeschränkt) und die eingeschränkte Ecto-Familie lesen sich daher eher wie Iterationen eines Werkzeugkastens als wie unabhängige Bemühungen.

Die Pakete beschreiben sich in späteren Versionen selbst als „CTF-Payload für Verdaccio-Lieferkettentests.“ Wir präsentieren diese Kennzeichnung als beobachtbare Tatsache und stellen sie nicht als Erkenntnis über den Zweck dar. Die Funktion des Codes ist eindeutig und unabhängig von seiner Kennzeichnung: Er liest IAM-Rollenanmeldeinformationen aus dem Instanzmetadatendienst, listet verwaltete Geheimnisse in drei AWS-Regionen auf und übermittelt die Ergebnisse an eine öffentliche IP-Adresse und einen externen Webhook-Collector. Ein reines Loopback-Testframework bräuchte weder die Fallback-Liste der öffentlichen IP-Adressen noch das Auslesen der IMDS-Anmeldeinformationen oder die regionsübergreifenden Secrets-Manager-Aufrufe. Da der ausgehende Datenverkehr und die Reichweite der Anmeldeinformationen real sind, wurden die eingeschränkten Versionen als schädlich eingestuft.

Die Container-basierte Zugriffskontrolle ist das operativ wichtigste Merkmal. Sie dient sowohl der Verschleierung – sie bleibt auf Laptops und in Analyse-Sandboxes unauffällig – als auch der gezielten Überwachung, da sie nur dort aktiv wird, wo mit hoher Wahrscheinlichkeit eine echte IAM-Rolle und sensible Daten vorhanden sind. Analysten, die diese Pakete in einer generischen Sandbox ausführen, würden nichts feststellen; das Verhalten manifestiert sich nur unter einem Docker-ähnlichen Hostnamen und einem Installationspfad innerhalb des Containers.

Die hier bestehende Schwachstelle besteht in der Offenlegung von Cloud-Anmeldeinformationen und Geheimnissen innerhalb von Build- und Laufzeitcontainern. Eine aus IMDS abgerufene IAM-Rollenanmeldeinformation enthält alle Berechtigungen, die dieser Rolle zustehen; secretsmanager:ListSecrets (und alle Folge-) GetSecretValue) erweitert dies auf gespeicherte Anwendungsgeheimnisse. Ausgelesene Umgebungsvariablen enthalten häufig Registry-Tokens, Datenbank-URLs und API-Schlüssel. In einer CI- oder Containerumgebung – genau dem, worauf das Gate abzielt – genügt eine einzige transitive Installation eines dieser Pakete, um diese Daten preiszugeben.

Ectoplasm folgt einem Muster, das wir immer wieder beobachten: Installations-Payloads, die auf Cloud-Metadaten und verwaltete Geheimnisse anstatt auf lokale Dateien zugreifen und sich so konfigurieren, dass sie nur in sensiblen Umgebungen ausgeführt werden. Daraus ergeben sich zwei defensive Beobachtungen.

  • Die Form ist erkennbarEin npm/PyPI-Installations-Hook, dessen Aufrufgraph sowohl eine Cloud Secrets API als auch eine Cloud Secrets API erreicht (AWS Secrets Manager, gcloud secrets, az keyvault) oder die IMDS-Adresse und ein Netzwerkausgangssink ist ein schmales, starkes Signalmuster – es kommt in einem legitimen Lebenszyklusskript fast nie vor. Analyse der statischen Strömung kann es kennzeichnen, ohne von einer bestimmten Domain oder IP-Adresse abhängig zu sein.
  • Eine Verfestigung der Umgebung dämpft diesen Effekt. Die Erzwingung von IMDSv2 mit einem Hop-Limit von 1 verhindert, dass Container-Workloads auf Instanzmetadaten zugreifen; die Beschränkung von IAM-Rollen auf das Minimum an Berechtigungen begrenzt den Wirkungsbereich etwaiger durchgesickerter Anmeldeinformationen; und die Ausführung von Installationen mit –Ignore-Skripte In CI wird der install-hook-Vektor für Pakete, die ihn nicht benötigen, vollständig entfernt.

Für die Sicherheitsverantwortlichen ergeben sich folgende praktische Prüfungen: Warnung bei ausgehenden Verbindungen von Build-/CI-Containern zu nicht zugelassenen öffentlichen IP-Adressen während npm installierenAchten Sie auf IMDS-Zugriffe, die von Paketlebenszyklusskripten ausgehen; und behandeln Sie jeden Installations-Hook, der eine Cloud-CLI aufruft, als verdächtig, bis das Gegenteil bewiesen ist.

Zwei weitere Anmerkungen speziell zu diesem Cluster: Erstens, da die Aktivierung an containerisierte Umgebungen gebunden ist, kann ein Paket, das bei der Überprüfung auf einer Workstation inaktiv erscheint, in der Produktionsumgebung dennoch aktiv sein. Die Überprüfung muss daher die Hostnamen- und Pfadbedingungen des Containers reproduzieren oder den Quellcode direkt lesen, anstatt sich auf die Aussage „Ich habe es installiert und es ist nichts passiert“ zu verlassen. Zweitens bedeutet die Verwendung eines öffentlichen Dienstes zur Anforderungsprüfung als Beacon-Collector, dass einige der exfiltrierten Daten für die Reaktion auf Sicherheitsvorfälle wiederhergestellt werden können: Eine Organisation, die eines dieser Pakete in ihrem Abhängigkeitsbaum findet, kann anhand der Erfassungslogik der Nutzdaten ableiten, welche Daten ein erfolgreicher Beacon enthalten hätte, und sollte alle IAM-Rollenanmeldeinformationen, Registry-Token und verwalteten Geheimnisse, die von der betroffenen Build- oder Laufzeitumgebung aus erreichbar waren, rotieren. Rotation der QualifikationsnachweiseDie operative Abhilfemaßnahme nach einer Installation ist nicht die Paketentfernung.

SCA-Tools-Software-Zusammensetzungs-Analyse-Tools
Priorisieren, beheben und sichern Sie Ihre Softwarerisiken
Sichern Sie sich Ihr kostenloses Konto.
Keine Kreditkarte erforderlich.

Sichern Sie Ihre Softwareentwicklung und -bereitstellung

mit der Xygeni-Produktsuite