TL; DR
Zwanzig npm-Pakete, die Ende Juli und Anfang August 2026 innerhalb von zwei Tagen veröffentlicht wurden, präsentieren sich als interne UI-Komponentenbibliotheken und gemeinsam genutzte Backend-Hilfsprogramme. Keines von ihnen implementiert jedoch die beworbene Funktionalität. Jedes Paket enthält eine Stub-Klasse, eine README-Datei, die das Paket als intern beschreibt, und eine Datei namens „…“. _polyfill.js.
Das Interessante daran ist, von wo aus diese Datei aufgerufen wird. Es handelt sich nicht um einen Installationshaken. — Die Manifeste deklarieren weder Vorinstallation, Installation noch Nachinstallation. Stattdessen lautet die letzte Zeile index.js lautet: try { require("./_polyfill"); } catch (_) {}Die Nutzlast wird beim ersten Import des Pakets durch den Anwendungscode ausgeführt. Installation mit --ignore-scripts, hat das standard Ratschläge zur Reduzierung des Lieferkettenrisikos zum Zeitpunkt der Installation verhindert es nicht.
Was _polyfill.js Es ruft eine plattformspezifische ausführbare Datei von einem der drei Cloudflare Workers-Hosts ab, speichert sie unter einem zufälligen Namen in einem temporären Verzeichnis, kennzeichnet sie als ausführbar und startet sie unabhängig vom übergeordneten Prozess. Diese ausführbare Datei selbst ist ein Loader: Sie listet Endpoint-Security-Produkte anhand ihres Prozessnamens auf, überprüft den aktuellen Benutzernamen anhand bekannter Konten in Analyseumgebungen, patcht die AMSI- und ETW-Telemetrieschnittstellen im Speicher, installiert Persistenz unter dem Namen einer Windows-Audiokomponente und ruft eine dritte, mehrere Megabyte große Binärdatei ab. Die dritte Stufe wird verschlüsselt übertragen und ist Die Entschlüsselung und Ausführung erfolgte im Arbeitsspeicher, anstatt auf die Festplatte geschrieben zu werden..
Am 1. August, etwa vier Stunden nachdem die Pakete bei einer manuellen Überprüfung als schädlich eingestuft worden waren, wurden neunzehn der zwanzig Namen innerhalb von fünfundzwanzig Sekunden von ihrem jeweiligen Herausgeber aus npm entfernt. Am 2. August wurde einer dieser Namen erneut registriert – von einem anderen Konto mit demselben Code. Die Auslieferungsinfrastruktur bediente zum Zeitpunkt der Erstellung dieses Textes alle drei Phasen.
| Pakete | 20 npm-Namen, ~74 veröffentlichte Versionen |
| Namensthemen | beaver-ui-* (13) accounts-* (3), plus afisha-storybook-default, bcore-bravo-eslint-config, arbocrate-sla-prober-arbocrate-sla-prober-core, a.poltoradnev-package-c |
| Auslösen | Modulimport (require), kein npm-Lebenszyklusskript |
| Stufe 1 | _polyfill.js — Bergung und Start |
| Stufe 2 | Statisch gelinkter Loader, UPX-gepackt unter Linux; Endpunktsicherheits-Enumeration, AMSI/ETW-Patching, Persistenz |
| Stufe 3 | beacon_linux.bin / beacon_mac.bin / update_win.exe4–13 MB; verschlüsselt übermittelt, im Speicher ausgeführt |
| Plattformen | Linux x64 und arm64, macOS Universal, Windows x64 |
| Publisher | Zwei Accounts, eine Codebasis |
| Status | 19 von 20 Namen unveröffentlicht vom Betreiber; 1 erneut veröffentlicht und live; Bereitstellungsinfrastruktur live |
Angriffsanatomie
Phase 1 – das Paket
Alle Mitglieder versenden die gleiche dreiteilige Dateiform. index.js exportiert eine Klasse mit einem drin() das einen booleschen Wert festlegt, einen Ausführung()Und eine konfigurieren() Das führt zu einer Zusammenführung eines Optionsobjekts. Sonst nichts. README.md gibt eine Installationszeile an, eine erfordern Zeile und der Satz „Internes Paket. Siehe CONTRIBUTING.md für Richtlinien“ — BEITRAGEN.md ist nicht im Tarball enthalten.
_polyfill.js ist etwas unter 5 KB groß und liest sich wie gewöhnlicher Infrastrukturcode. Es beginnt mit drei Umgebungsprüfungen:
if (process.env.DISABLE_TELEMETRY ||
process.env.ANALYTICS_OPT_OUT ||
process.env.DO_NOT_TRACK)
return; Diese Variablen stellen herkömmliche Datenschutzmaßnahmen dar. Sie steuern hier, ob eine Binärdatei heruntergeladen und ausgeführt wird. Eine Maschine, die diese Variablen setzt, … NICHT VERFOLGEN wird komplett übersprungen.
Als Nächstes folgt ein einmalig ausgeführter Stempel: eine Datei bei /tmp/.analytics_stateden Analysestatus für % TEMP% Unter Windows wird die Änderungszeit mit einem Zeitfenster von 20,357 Sekunden verglichen. Innerhalb dieses Zeitfensters gibt das Modul sofort eine Antwort zurück, sodass wiederholte Importe während eines Build-Prozesses nur einen Abrufversuch anstatt dutzender erfordern.
Die Zielhosts liegen nicht als Literale vor. Sie werden zur Laufzeit aus Fragmenten zusammengesetzt:
["oob-worker.cf102-","baf.workers.d","ev"].join("") Drei Hosts werden auf diese Weise konfiguriert und vor der Verwendung neu angeordnet, sodass die Reihenfolge bei jeder Ausführung variiert. Der Abruf erfolgt über einen HTTPS-GET-Request, der an IPv4 gebunden ist. User-Agent of node-fetch/2.6 — ein plausibler Wert, den ein Node-Prozess ausgeben sollte. Eine Antwort unter 1,000 Bytes wird verworfen und der nächste Host versucht.
Wenn alle drei Versuche fehlschlagen, greift das Modul auf DNS zurück. Es sendet eine TXT-Anfrage an die zuständige Stelle. C. um die Anzahl der Datenblöcke zu ermitteln, werden dann Anfragen gestellt. 0. - durch Konsolidierung, N. Die Antworten werden in Zehnergruppen zusammengeführt und das Ergebnis Base64-dekodiert. Dieser Pfad überträgt dieselbe ausführbare Datei über DNS-TXT-Einträge, wodurch die Funktionalität auch in Umgebungen erhalten bleibt, in denen ausgehender HTTP-Verkehr gefiltert, die DNS-Auflösung jedoch nicht gefiltert wird.
Die abgerufenen Bytes werden geschrieben nach /var/tmp/.cache_<8-hex> unter Unix, oder %TEMP%\dotnet_diag_<8-hex>.exe Unter Windows handelt es sich um einen Dateinamen, der als .NET-Diagnoseartefakt interpretiert wird. Unter Unix erhält die Datei den Modus 0755. Startvorgang: laichen und abgetrennt: wahr, stdio: “ignore” und unref()Der Kindprozess überlebt also den Node-Prozess, der ihn gestartet hat; unter Windows fügt der Aufruf hinzu Fenster ausblenden: wahr.
Zwei Details vervollständigen das Bild. Ein Helfer, definiert als const _l = (…a) => process.stderr.write(“”) wird bei jedem Abrufschritt aufgerufen – es schreibt eine leere Zeichenkette und verwirft seine Argumente; es belegt die Position, an der normalerweise die Protokollierung erfolgen würde. Und jedes Paket enthält eine 81 KB große Datei unter lib/telemetry.js Der Header-Kommentar beschreibt ein „Analytics SDK“ mit „HTTPS-Transport mit Endpunktrotation und Wiederholungsversuchen“ sowie „DNS-basierter Diensterkennung für Failover“. Im aktuellen Build wird dies nicht benötigt.
Phase 2 – der Lader
Die Linux-x64-Binärdatei ist eine statisch gelinkte ELF-Datei, komprimiert mit UPX 3.96. Die macOS-Version ist eine universelle Binärdatei, die x86_64 und arm64 abdeckt; die Windows-Version ist eine abgespeckte PE32+-Konsolenanwendung. Alle vier Dateien wurden heruntergeladen und statisch untersucht; keine wurde ausgeführt.
Die Importe und die Stringtabelle des Windows-Builds beschreiben sein Verhalten eindeutig. Es löst auf IsDebuggerPresent, Remote-Debugger prüfen und NtQueryInformationProcessund liest SYSTEM\CurrentControlSet\Services\Disk\Enum — ein Registrierungspfad, dessen Werte virtuelle Festplattencontroller identifizieren. Er ruft GetDiskFreeSpaceExW und GlobalMemoryStatusEx, im Einklang mit der Überprüfung, ob die Ressourcen des Hosts mit einer kurzlebigen Analyseinstanz übereinstimmen.
Es enthält eine Liste von Benutzernamen: AktuellerBenutzer, IT-Administrator, Hong Lee, TESTBOX, hapubws, Milozs, timmy, Admin, Malware, Sample, Virus, UmweltEinige davon sind Artefakte öffentlich dokumentierter Analyseumgebungen.
Es enthält außerdem eine Liste von Endpoint-Security-Produkten und deren Prozessnamen, die durch folgende Schritte aufgelistet werden: CreateToolhelp32Snapshot und Process32FirstW/Prozess32NächstesW:
- CrowdStrike Falcon (
csfalconservice,CSFalconContainer) - Carbon Black (
cb.exe) - Cylance (
cylancesvc.exe) - Bitdefender (
bdagent.exe) - Kaspersky (
avp.exe,kavfs.exe) - Trend Micro und Deep Security (
coreServiceShell,ds_agent.exe) - FireEye/Trellix (
xagt.exe) - Tanium (
taniumclient.exe) - HitmanPro (
hmpalert.exe) - Elastisch (
elastic-agent.exe,elastic-endpoint,filebeat.exe,winlogbeat.exe) - Wazuh und OSSEC (
wazuh-agent.exe,ossec-agent.exe) - Check Point
- Windows Defender
Zwei weitere Symbole sind vorhanden: AmsiScanBuffer, der von Windows bereitgestellte Einstiegspunkt für die Speicherinhaltsprüfung, und EtwEventWriteDie Funktion, mit der die Ereignisablaufverfolgung für Windows Ereignisse aufzeichnet, wird häufig im laufenden Prozess modifiziert, um die Telemetriedaten zu unterdrücken, die diese Schnittstellen andernfalls erzeugen würden.
Persistenz tritt unter Windows zweimal auf. Die Binärdatei wird kopiert nach %APPDATA%\Microsoft\Windows\Themes\SystemSoundsService.exeund zwei Mechanismen beziehen sich darauf: ein Wert unter SOFTWARE\Microsoft\Windows\CurrentVersion\Runund eine geplante Aufgabe, die als registriert ist
schtasks /Create /F /SC ONLOGON
/TN "\Microsoft\Windows\Multimedia\SystemSoundsService"
/TR "\"%s\""
/RL HIGHEST Der Aufgabenpfad, der Aufgabenname und der Name der ausführbaren Datei spiegeln allesamt eine originale Windows-Audiokomponente wider. /RL HÖCHSTE fordert die höchste verfügbare Berechtigungsstufe an.
Der macOS-Build folgt dem gleichen Muster mit plattformgerechten Namen: Er schreibt eine Eigenschaftsliste in ~/Library/LaunchAgents/com.apple.windowserver.helper.plist und platziert seine ausführbare Datei unter ~/.local/share/runtime/com.apple.runtimeEs prüft auf /Applications/VMware Fusion.app und /Bibliothek/Anwendungsunterstützung/VMware Tools.
Die Netzwerkfähigkeit erstreckt sich über drei Transporttechnologien: WININET.dll für HTTPS mit einem https://%s:%d%s Formatzeichenfolge, WS2_32.dll Steckdosen und DNSAPI.dll und DnsQuery_A neben einem c.%s.%s Formatzeichenfolge – die gleiche Chunk-Count-Abfragestruktur, die in der ersten Phase verwendet wird.
Die obige Beschreibung zeigt, was die Importe, Zeichenketten und Registrierungspfade der Binärdatei bei genauerer Betrachtung offenbaren. Eine öffentlich zugängliche Multi-Engine-Analyse desselben Windows-Beispiels liefert weitere Details, die durch statisches Lesen einer Importtabelle allein nicht ermittelt werden können. Diese Ergebnisse werden hier als Referenz und nicht als eigene Beobachtung wiedergegeben. Die Analyse zeigt, dass die AMSI- und ETW-Referenzen nicht nur aufgelöst, sondern auch gepatcht wurden. AmsiScanBuffer in amsi.dll und EtwEventWrite in ntdll.dll — wodurch das Scannen von Inhalten im Arbeitsspeicher und die Ereignisverfolgung für den Prozess unterdrückt werden. Es meldet die Anti-Analyse-Prüfungen zusätzlich zu zeitbasiert. Remote-Debugger prüfenund identifiziert die GetThreadContext Es wird ein Hardware-Breakpoint-Aufruf durchgeführt, der die Debug-Register ausliest. Außerdem wird ein Single-Instance-Mutex gemeldet. Global\{7A3B9E1F-C2D4-4F8A-B5E6-D7A1F0C3E2B9}und Namen SystemSoundsService als Run-Key-Wert. Dieser Mutex-Wert war nicht unter den hier wiederhergestellten Zeichenketten – der verwendete Extraktionsfilter schloss geschweifte Großbuchstaben-Hexadezimal-Token aus – und ist aufgrund dieser öffentlichen Analyse und nicht aufgrund direkter Beobachtung in der Indikatortabelle vermerkt.
Stufe 3
Der Loader verweist auf weitere Pfade auf denselben Hosts. Alle waren während der Analyse erreichbar: beacon_linux.bin bei 5.3 MB beacon_mac.bin bei 13.3 MB update_win.exe bei 10.3 MB und arm.bin bei 4.3 MB. Diese konnten nicht abgerufen werden, und ihr Verhalten ist unbekannt.
Für den Windows-Pfad beschreibt die öffentliche Analyse des Loaders, wie die dritte Phase abläuft: Sie wird über WinINet abgerufen, kommt verschlüsselt an und wird im Speicher entschlüsselt und reflektiv ausgeführt – Speicher wird allokiert, Importe aufgelöst, Relokationen verarbeitet und die Kontrolle über WinINet an einen neuen Thread übergeben. Thread erstellenAus diesem Grund wird die dritte Phase nie im Dateisystem gespeichert, sodass dateibasierte Erkennung und forensische Untersuchungen nach einem Vorfall keine Daten wiederherstellen können. Das bedeutet auch, dass das Abrufen der Bytes vom Zielrechner verschlüsselten Text und keine analysierbare ausführbare Datei liefern würde.
Geschichte
Alle Zeitstempel sind UTC und stammen aus den Metadaten der npm-Registry, die die Erstellung und Nicht-Veröffentlichung von Paketen unabhängig von jeglichem Beobachter aufzeichnen.
| Wenn die Funktion | Was |
|---|---|
| 2026-07-31 09:25:05 → 09:29:56 | Zehn Namen erstellt, jeder beginnend mit Version 0.0.1, im Abstand von etwa dreizehn Sekunden. |
| 2026-08-01 09:38 → 11:29 | Bestehende Namen steigen durch aufgeblähte Versionsnummern. 6.1.9 - durch Konsolidierung, 6.1.12, 9.9.9 - durch Konsolidierung, 9.9.12, 8.9.3 - durch Konsolidierung, 8.9.6, 5.4.6 - durch Konsolidierung, 5.4.9. |
| 2026-08-01 13:04:14 → 13:04:18 | Neun weitere beaver-ui-* Die Namen wurden innerhalb von vier Sekunden generiert und jeweils direkt in einer 12.x-Version ohne vorherige Historie veröffentlicht. |
| 2026-08-01 ~13:00–14:30 | Versionen, die bei der manuellen Überprüfung als schädlich eingestuft wurden. |
| 2026-08-01 17:39:49 → 17:40:14 | Neunzehn der zwanzig Namen wurden innerhalb von fünfundzwanzig Sekunden nacheinander, im Abstand von etwa 1.2 Sekunden, nicht veröffentlicht. |
| 2026-08-02 18:58:41 | a.poltoradnev-package-c Erneut erstellt unter einem anderen Wartungskonto, Version 0.0.2. |
| 2026-08-02 19:20:28 | Version 33.9.5 unter demselben Namen veröffentlicht. |
| 2026-08-02 20:14 | Alle drei Auslieferungshosts bedienen die Phasen zwei und drei; DNS-Fallback antwortet mit Chunk-Zählern. |
Zwei dieser Einträge verdienen es, näher betrachtet zu werden.
Der 13:04-Schub platzierte innerhalb von vier Sekunden neun Pakete im Register, jedes mit einer einzigen Version im zwölften Bereich und ohne 0.0.1 Darunter. Versionsnummern dieser Größenordnung, bei Namen, die erst einen Tag alt sind, beschreiben keine Release-Historie.
Die Sequenz zum Entfernen aus der Veröffentlichung ist ebenso mechanisch: neunzehn Namen, fünfundzwanzig Sekunden, gleichmäßige Leerzeichen. npm protokolliert dies als gewöhnliche Entfernungsereignisse und nicht als Platzhalter, den eine von der Registry initiierte Entfernung hinterlässt. Dadurch wird die Aktion dem veröffentlichenden Konto und nicht der Registry zugeordnet.
Kompromissindikatoren
Hosts und Pfade sind deaktiviert. Sie dürfen nicht in einem Produktivsystem aufgelöst oder abgerufen werden.
| Typ | Wert |
|---|---|
| Zusteller | oob-worker[.]cf99-9b3[.]workers[.]dev |
| Zusteller | oob-worker[.]cf102-baf[.]workers[.]dev |
| Zusteller | oob-worker[.]cf103-070[.]workers[.]dev |
| DNS-Transport | tin[.]dl[.]well1[.]site (Linux x64), tina[.] (arm64), ldr[.] (Mac OS), win[.] (Windows) — Anzahl der Datenblöcke bei c.<domain>, Daten bei <n>.<domain> |
| Pfade der Stufe 2 | /pkg/package, /pkg/package-arm64, /pkg/loader_mac, /pkg/package.exe |
| Pfade der Stufe 3 | /pkg/beacon_linux.bin, /pkg/beacon_mac.bin, /pkg/update_win.exe, /pkg/arm.bin |
| Pfad löschen (Unix) | /var/tmp/.cache_<8-hex> |
| Drop-Pfad (Windows) | %TEMP%\dotnet_diag_<8-hex>.exe |
| Persistenz (Windows) | %APPDATA%\Microsoft\Windows\Themes\SystemSoundsService.exe; Aufgabe \Microsoft\Windows\Multimedia\SystemSoundsService; Run-Key-Wert SOFTWARE\Microsoft\Windows\CurrentVersion\Run\SystemSoundsService |
| Mutex (Windows) | Global\{7A3B9E1F-C2D4-4F8A-B5E6-D7A1F0C3E2B9} |
| Persistenz (macOS) | ~/Library/LaunchAgents/com.apple.windowserver.helper.plist; binär bei ~/.local/share/runtime/com.apple.runtime |
| Einmalstempel | /tmp/.analytics_state, %TEMP%\analytics_state (20,357 s Fenster) |
| Unterschrift anfordern | HTTPS GET, IPv4-fixiert, User-Agent: node-fetch/2.6 |
| Stage-1-Datei | _polyfill.js, SHA-256 392dc9ec85042ce1796bfa9b8c7bf6e05c7710579aab8b7b1eb73788683883af |
| Nicht referenzierte Datei | lib/telemetry.js, SHA-256 2266c9b8e199daebe31a9afcb61d9b0d76706b63c92312fc8223d22de42e63c7 |
| Stufe 2 (Linux x64) | SHA-256 7e486657f30594afda379b97030252a09a19fe8055e25c9e371544f59bd8e9e3 |
| Phase 2 (Linux arm64) | SHA-256 aafc37589c0d21fb729761a1579ca3b278b95bce152aacfa29243ffd27f5eeb7 |
| Stufe 2 (macOS) | SHA-256 c214746c74cae8ece8bdaf69aa05da4db6ce013f9e77452d1eed1a002fd9ba00 |
| Phase 2 (Windows) | SHA-256 d632c2c0c7801c3da57cf849fe4b4ca8351d9a7fe73c31050bf5dbcc96a16791 |
Paketnamen
Attribution und beobachtetes Verhalten
Es sind zwei npm-Konten beteiligt. Die neunzehn unveröffentlichten Namen wurden von einem Konto veröffentlicht; a.poltoradnev-package-c Die Registrierung erfolgte am 2. August unter einem anderen Kontonamen und einer anderen E-Mail-Domain. Der Quellcode ist in beiden Fällen identisch, und die zweite Registrierung verwendet dieselben Zustellungshosts, dieselben DNS-Fallback-Domains, dieselbe Drop-Path-Struktur und denselben Run-Once-Stempel.
Das neu veröffentlichte Paar zeigt auch, wie es zusammengebaut wurde. Versionen 0.0.2 und 33.9.5 sind bis auf die Versionszeichenfolge byteidentisch in paket.jsonund die index.js versendet als 0.0.2 erklärt const VERSION = “33.9.5”Beide Artefakte wurden von einem einzigen Baum abgetrennt und anschließend nummeriert. Es gibt keine 0.0.2 Entwicklungsgeschichte für die 0.0.2 Freigabe zur Darstellung.
Die Versionsnummerierung des gesamten Sets folgt derselben Logik. Die Paketnamen dieser Kampagne beschreiben Komponenten, die eher innerhalb einer Organisation als in einer öffentlichen Registry existieren: ein UI-Komponentenset, eine ESLint-Konfiguration, ein SLA-Prober, ein nach einer Person benanntes Paket. Wenn ein Build eine Abhängigkeit anhand ihres Namens auflöst und sowohl eine öffentliche als auch eine private Registry konsultiert, ist die Version mit der höheren Versionsnummer maßgebend. Ein Name, der am erstellt wurde 0.0.1 am Montag und tragen 12.9.6 Der Dienstag bietet sich für diesen Vergleich an.
Die beiden Veröffentlichungswellen unterscheiden sich auch in einer Weise, die auf Iteration hindeutet. Der frühere Code benannte seine Nutzdatendatei setup.js und listete fünf Auslieferungshosts auf; die aktuelle Datei heißt _polyfill.js und listet drei auf. Die frühere Version entfernte die abgelegte Datei fünf Sekunden nach dem Start, sodass der Prozess von einem gelöschten Inode aus weiterlief; die aktuelle Version tut dies nicht. Die nicht referenzierte lib/telemetry.js verbleibt in beiden Fällen im Tarball, wird weiterhin versendet, ist aber nicht mehr verkabelt.
Eine Anmerkung zu den Not-Aus-Schaltern ist es wert, vorab erwähnt zu werden.cisely, weil es einer gängigen Interpretation widerspricht. TELEMETRIE DEAKTIVIEREN, ANALYTIK_ABMELDEN und NICHT VERFOLGEN Diese Einstellungen werden beachtet und überprüft, bevor irgendetwas anderes geschieht. Ein Forscher, dessen Analyseumgebung eine dieser Einstellungen vornimmt, beobachtet ein Paket, das keinerlei Funktion ausführt.
Auswirkungen und was Verteidiger tun können
Die praktischen Konsequenzen des Importzeit-Triggers sind eng gefasst und verdienen es, gesondert erwähnt zu werden. npm install --ignore-scripts Das verhindert die Ausführung von Lebenszyklusskripten und ist ein sinnvoller Ratschlag. Hier hat es jedoch keine Auswirkung, da dieser Code kein Lebenszyklusskript verwendet. Die Nutzlast wird ausgeführt, sobald Anwendungscode, ein Testlauf, ein Bundler oder ein Linter das Modul importiert. Auf einem CI-Runner, der die Installation durchführt und anschließend sofort kompiliert, liegen zwischen diesen beiden Ereignissen nur wenige Sekunden.
Für die Suche sind die dauerhaften Signale eher struktureller als wörtlicher Natur. Die Hosts, der Dateiname und die Ablagepfade ändern sich; diese Strukturen sind schwieriger zu variieren:
- Ein Moduleinstiegspunkt, dessen letzte Anweisung ein try { require("./x"); } catch (_) {} um eine Datei herum, die nicht Teil der exportierten API ist. Ein Paket mit einem gültigen Polyfill importiert dieses am Anfang der Datei und verwendet dessen Ergebnis. Das Ignorieren aller Fehler bei einem Import am Ende der Datei ist keine Fehlerbehandlung.
- Host-Strings zusammengesetzt von .verbinden("") aus einer Reihe von Fragmenten. In legitimem Code gibt es keinen Grund, einen Hostnamen über mehrere Array-Elemente aufzuteilen.
- Ein Paket, dessen deklarierte Abhängigkeiten leer sind, das aber dennoch nach ... sucht https, dns und child_process zum Importzeitpunkt. Das gesamte Ergebnis besteht darin, dass das Abrufen und Ausführen in einem Paket erfolgt, das eine UI-Komponente bewirbt.
- Versionsnummern, die nicht mit dem Alter des Pakets übereinstimmen. Ein Name, der vor wenigen Tagen erstmals bei einer zweistelligen Hauptversionsnummer veröffentlicht wurde, ohne dass es dazwischen weitere Veröffentlichungen gab, beschreibt etwas anderes als seine Entwicklung.
- Schreibt an / var / tmp or % TEMP% gefolgt von einem chmod bis 0755 und ein abgetrennter Spawn. Die Sequenz ist kurz, geordnet und verläuft selten unproblematisch.
Auf Windows-Hosts gibt es zwei kostengünstige und zuverlässige Prüfungen. Die persistenten Artefakte sind feste Zeichenketten, die auf einem sauberen System nicht hingehören: eine geplante Aufgabe bei \Microsoft\Windows\Multimedia\SystemSoundsService, ein Run-Key-Wert namens SystemSoundsServiceund eine ausführbare Datei mit diesem Namen unter %APPDATA%\Microsoft\Windows\Themes\Der originale Windows-Audiodienst befindet sich an keinem dieser Orte. Zweitens verwendet der Loader einen festen Einzelinstanz-Mutex. Global\{7A3B9E1F-C2D4-4F8A-B5E6-D7A1F0C3E2B9}; seine Präsenz auf einem Host ist ein Indikator, und da der Loader einen vorhandenen Mutex als „bereits aktiv“ behandelt, ist dessen Vorab-Erstellung eine praktikable kurzfristige Maßnahme, während die Behebung geplant wird.
Die Erkennung in der dritten Phase stellt ein komplexeres Problem dar, das genauer betrachtet werden sollte. Laut öffentlich zugänglichen Analysen werden die Daten entschlüsselt und im Arbeitsspeicher abgelegt, anstatt auf die Festplatte geschrieben zu werden. Daher sind sie weder durch Dateiscans noch durch forensische Festplattenanalysen nachweisbar. Beobachtbar bleiben lediglich die Spuren des Loaders selbst – die Persistenzeinträge, der Mutex und ausgehende Anfragen an die Auslieferungshosts oder die DNS-TXT-Domains.
In Umgebungen, die Abhängigkeiten sowohl aus einer privaten als auch aus einer öffentlichen Registry auflösen, bleibt die Abhilfemaßnahme unverändert: Interne Namen werden so eingeschränkt, dass ein öffentlicher Name diese nicht erfüllen kann, und die Auflösung wird für diese Bereiche auf die interne Registry beschränkt. Das oben beschriebene Verhalten der Versionsinflation funktioniert nur, wenn eine höhere öffentliche Version einen Namen erhalten kann.
Abschließend sei angemerkt, dass die Löschung nicht als endgültiger Abschluss, sondern als aufmerksame Lektüre zu verstehen ist. Neunzehn Namen wurden innerhalb von fünfundzwanzig Sekunden aus der Registry entfernt, einer kehrte einen Tag später unter einem neuen Konto zurück, wobei die Auslieferungsinfrastruktur unverändert blieb. Die Entfernung von Paketen bedeutet nicht das Ende des Vorgangs; die Hosts bedienten weiterhin alle Phasen, während dieser Text verfasst wurde. Jeder Abhängigkeitsbaum, der einen dieser Namen zwischen dem 31. Juli und dem 1. August aufgelöst hat, sollte so behandelt werden, als hätte er die Möglichkeit gehabt, Phase eins auszuführen, unabhängig davon, ob der Name noch existiert.
Referenzen
- Multi-Engine-Analyse des Windows-Loaders — Quelle für das oben genannte AMSI/ETW-Patching, die reflexive In-Memory-Ausführung und die Mutex-Details.
- npm-Skriptdokumentation — die Lebenszyklusereignisse, die diese Kampagne nicht verwendet.
- npm install-Dokumentation — deckt ab –Ignore-Skripte und dessen Umfang.




