- Nachdem auf LinkedIn eine Stelle als Software Engineer angeboten wurde, wurde ein privates GitHub-Repository als scheinbar normale React/Web3-Aufgabe übermittelt; beim Ausführen lief auf dem Entwicklerrechner JavaScript-Malware, die in
tailwind.config.jsversteckt war - Die 30.987 Byte große Konfigurationsdatei versteckte nach Tausenden Leerzeichen 27 KB obfuskierten Code, lud von einem Remote-Server eine mit AES-256-CBC verschlüsselte Stage-2-Payload herunter, speicherte sie unter
%TEMP%\packund führte sie anschließend mitnode packaus - Eine etwa 10-minütige Beobachtung in einer isolierten Windows-11-ARM-VM zeigte, dass die Payload vier Komponenten startete: eine Remote-Control-Backdoor, einen Browser- und Wallet-Stealer, einen rekursiven Dateiscanner und einen Clipboard-Monitor
- Über Socket.IO wurden Terminal, SSH, Bildschirm, Tastatur und Maus gesteuert; außerdem wurden Chromium-Datenbanken, Speicher von Wallet-Erweiterungen, SSH-Keys, Quellcode, Konfigurationsdateien und weitere Daten gesammelt. Auf dem Datei-Upload-Port wurden 2.588 Anfragen beobachtet
- Aufgaben-Repositories von unbekannten Personen sollten als nicht vertrauenswürdiger Code behandelt und in einer Einweg-VM oder einem Container ohne echte Browserprofile, SSH-Keys, Cloud-Zugangsdaten oder Wallets geprüft werden. Bei einer Infektion sollten nach Netzwerktrennung und Beweissicherung auch Geheimnisse rotiert werden
Als normale Web3-Recruiting-Aufgabe getarntes Repository
- Der LinkedIn-Nutzer Wayan Adrian bot eine Software-Engineer-Stelle bei shrapnel.com an und übermittelte als Aufgabe das private GitHub-Repository
tech-active-workplace-frontend-maindes Accountsyevhen-o - Die NFT-Kampagnenplattform namens BLAIEXS wirkte nach außen wie ein gewöhnliches React/Web3-Projekt
- Das React-Frontend bot ein Marken- und Admin-Dashboard, Kampagnenverwaltung, einen Ablauf zur NFT-Erstellung und Ähnliches
- Die Express-API verarbeitete Authentifizierung, Dashboard-Daten, KYB-Prüfungen, NFT-Erstellung und -Claims, Datei-Uploads sowie einige Stub-Endpunkte
- Das Seed-Skript erzeugte Demo-Konten für Superadmin, Marke und Verbraucher, eine Kampagne
Demo NFT Dropsowie ein NFTDemo Collectiblemit 100 verfügbaren Exemplaren
- Der tatsächliche Aufgabenumfang war eine einfache MetaMask-Netzwerkanzeige
- Die asynchrone Funktion
getChainId()insrc/utils/ethereum.jssollte so implementiert werden, dass sieeth_chainIdaufruft und den geparsten Hex-Wert odernullzurückgibt getNetworkLabel(chainId)in derselben Datei sollte so implementiert werden, dass sie im bestehenden ObjektNETWORKSeinen lesbaren Netzwerknamen findetsrc/components/Wallet/ConnectWalletButton.jssollte so geändert werden, dass nach dem Verbinden der Wallet beide Funktionen aufgerufen werden
- Die asynchrone Funktion
- Nach Abschluss der Implementierung wurde der Entwicklungsserver gestartet, fuhr aber lange nicht hoch; als der Nutzer etwas Verdächtiges bemerkte, zog er das Internetkabel ab
In tailwind.config.js versteckter Ausführungscode
- Laut
ls -lawartailwind.config.js30.987 Byte groß, im Editor waren jedoch nur 97 Zeilen zu sehen;wc -cbestätigte dieselbe Größe - In der Nähe von Zeile 95 war hinter Tausenden Leerzeichen ein großer, kaum lesbarer JavaScript-Blob versteckt
- Der Code nutzte typische JavaScript-Obfuskationstechniken
- Wichtige Strings wurden in einem großen Array gespeichert
- Das Array wurde rotiert, bis die Prüfsumme stimmte
- Der Zugriff auf Strings wurde hinter Decoder-Funktionen versteckt
- Eindeutige Namen wurden durch numerische Indizes und Wrapper-Aufrufe ersetzt
- Einer der beiden Decoder stellte Strings in Base64-Form wieder her, der andere wendete einen stringspezifischen Schlüssel und eine RC4-ähnliche Stromchiffre an; zudem wurde das String-Array rotiert, bevor die Decoder-Indizes stimmten
- Auch ohne die Malware auszuführen, ließ sich die Obfuskation in folgender Reihenfolge entfernen
- Das String-Array extrahieren
- Die Array-Rotation bis zur erwarteten Prüfsumme nachbilden
- Die Decoder-Funktionen neu implementieren
- Aufrufe wie
b(0x214),c(0x2f1, "key")durch die tatsächlichen Strings ersetzen - Wrapper-Objekte und Hilfsfunktionen vereinfachen, um die Ausführungsabsicht offenzulegen
Verhalten des Stage-1-Droppers
- Der deobfuskierte Code lud
child_process,os,fs,pathundcryptound installierteaxiossowiesocket.io-clientim temporären Verzeichnis - Handler auf Prozessebene für
uncaughtExceptionundunhandledRejectionwaren so konfiguriert, dass Fehler ignoriert werden - Der Ablauf zur Ausführung der Remote-Payload war wie folgt
- Die UID lautet
59e605dd78fb2aafccd1b622f06a00ca - Daten werden von
http://45.146.252.17/api/service/59e605dd78fb2aafccd1b622f06a00caabgerufen - UID und der String
saltwerden ancrypto.scryptSyncübergeben, um einen 32-Byte-Schlüssel abzuleiten - Die Antwort wird im Format
base64_iv:base64_ciphertextgetrennt und mitaes-256-cbcentschlüsselt - Der Klartext wird als Datei
packim temporären Verzeichnis geschrieben - Ausführung per
child_process.execSync("node pack", { windowsHide: true, cwd: os.tmpdir() })
- Die UID lautet
- Es handelt sich um einen Malware-Dropper, der statt eigener Funktionalität andere Schadsoftware herunterlädt und ausführt
- Der heruntergeladene Code hatte weder Signaturprüfung noch Hash-Allowlist, Herkunfts-Pinning, Pfadbeschränkung oder Schutz vor Ausführung, sodass der Remote-Endpunkt Code mit den Rechten des Betriebssystemkontos ausführen konnte, das die Tailwind-Konfiguration geladen hatte
Dynamische Analyse in einer isolierten VM
- Um das Host-System nicht offenzulegen, wurde mit UTM eine Einweg-Windows-11-ARM-VM eingerichtet
- Arbeitsspeicher
4096 MiB - Festplatte
64 GiB shared/NAT-Networking- Gemeinsame Ordner deaktiviert
- Arbeitsspeicher
- Es wurden Tools installiert, um das Malware-Verhalten aus mehreren Perspektiven zu erfassen
- Wireshark: Erfassung von Paketen sowie C2- und Exfiltrations-Traffic
- Sysinternals Sysmon: dauerhafte Windows-Event-Telemetrie
- Procmon: Erfassung laufender Prozesse sowie Registry- und Dateisystemaktivitäten
- Um die Sammelziele der Malware zu prüfen, wurden Köderdaten platziert
- SSH-Schlüsselpaar
- Privates GitHub-Repository
- Kryptowährungs-Wallet
- Browserdaten
- Weitere Dateien, die für einen Infostealer interessant sein könnten
- In der VM wurde
yarn startausgeführt und etwa 10 Minuten lang beobachtet; anschließend wurdenrun1-full.pcapng,run1-sysmon.evtxundstage2-pack.bingesichert
Im Netzwerk bestätigter Infektionsablauf
- Die HTTP-Anfragen an
45.146.252.17waren je nach Port nach Rollen aufgeteilt- Port
80: Abruf der Stage-1-Payload, Host-Registrierung, Log-Übertragung - Port
7641: Socket.IO-Command-and-Control-Backdoor - Port
7646: 2.588 Datei-Uploads - Port
7649: 3 größere, aber zahlenmäßig wenige Uploads von Browserdaten
- Port
- Die erste Anfrage war
GET /api/service/59e605dd78fb2aafccd1b622f06a00ca; die Antwort lag im Formatbase64_iv:base64_ciphertextmitContent-Length: 150897vor tailwind.config.jsentschlüsselte die Antwort mit AES-256-CBC, schrieb den Klartext nach%TEMP%\packund führte ihn mitnode packaus- Die Merkmale der gesicherten Stage-2-Payload waren wie folgt
- SHA-256:
68a64d8c015c06fd70bcb8c5878c1e430da827dd00b62f8e6ef69e76bb94de5b - Größe:
113136Byte - Format: einzeiliges ASCII-JavaScript
- SHA-256:
- Auch das entschlüsselte
packwar erneut obfuskiert, ließ sich aber mit derselben Technik wie in der ersten Stage nach demselben Verfahren deobfuskieren
Zweistufige Payload aus vier Programmen
packwar kein einzelnes Skript, sondern ein kleiner Prozessbaum, der die folgenden vier Programme ausführte- schreibt die Command-and-Control-Backdoor
scdatain ein temporäres Verzeichnis und führt sie aus - schreibt den Browser- und Wallet-Stealer
ldatain ein temporäres Verzeichnis und führt ihn aus - führt einen rekursiven Dateiscanner mit
node -edirekt im Speicher aus - führt einen Clipboard-Monitor mit
node -edirekt im Speicher aus
- schreibt die Command-and-Control-Backdoor
- Die wichtigsten Einstellungen waren UID
59e605dd78fb2aafccd1b622f06a00ca, Benutzerschlüssel308, Host45.146.252.17, Socket.IO-Port7641, Key-Port7648, Browser-Upload-Port7649und Datei-Upload-Port7646
scdata: interaktive Remote-Control-Backdoor
scdatawird als Datei nach%TEMP%geschrieben und dann mitnpm i axios socket.io-client ... && node scdataausgeführt; es bleibt als lang laufender Kindprozess aktiv- Nach dem Start richtet es sich so ein, dass es wie ein legitimer Prozess wirkt
- Prozessname:
vhost.ctl - Markerdatei für eine Einzelinstanz:
%TEMP%\.npm\vhost.ctl - Host-Registrierung:
http://45.146.252.17/api/service/… - Log-Übertragung:
http://45.146.252.17/api/service/makelog - Socket.IO-C2:
http://45.146.252.17:7641
- Prozessname:
- Außerdem installiert es zusätzliche Pakete, die für Remote-Control-Funktionen nötig sind
socket.io-client,ssh2,node-pty: Terminal- und SSH-ähnliche Funktionensharp,screenshot-desktop,clipboardy,@nut-tree-fork/nut-js: Screenshots, Clipboard, Mausbewegungen/-klicks/-scrollen, Tastatureingaben
- Socket.IO-Events zeigen den Umfang der Fernsteuerung direkt
- Terminal:
start-terminal,terminal-input,terminal-resize,stop-terminal,command - Host-Prüfung und Erfassung:
whour,capture - Eingabesteuerung:
mouseMove,mouseClick,mouseScroll,keyTap,keyCombo - Clipboard:
copyText,pasteText - SSH und Beenden:
start_ssh,ssh_input,kill
- Terminal:
- Im PCAP waren das Polling und der WebSocket-Handshake auf Port
7641sowie das erste Server-Eventwhourzu sehen; in Sysmon wurden nacheinandernode.exe scdata, PowerShell-Abfragen von Systeminformationen und die Installation zweier Gruppen von npm-Paketen erfasst - Über einfachen Informationsdiebstahl hinaus stellt es dem Angreifer sogar Shell- und Desktop-Steuerungsfunktionen bereit
ldata: Stealer für Browser- und Wallet-Daten
ldatawird nach%TEMP%geschrieben und mitnpm i axios && node ldataausgeführt; der Prozessname lautetnpm-cache- Es sammelt Browserprofile und Speicher von Wallet-Erweiterungen und sendet sie an
http://45.146.252.17:7649/upload; den LevelDB-Status prüft es unter/cldbs - Die Ziel-Browser sind je nach Betriebssystem breit angelegt
- Windows: Chrome, Edge, Brave, LT Browser
- macOS: Chrome, Brave, Opera, LT Browser, Edge und der lokale Login-Schlüsselbund
- Linux: entsprechende Profilordner Chromium-basierter Browser
- Aus den Verzeichnissen
DefaultoderProfile*lädt es die folgenden Chromium-Datenbanken hochLogin DataLogin Data For AccountWeb Data
- Anschließend durchsucht es
Local Extension Settings/<extension-id>; unter den hartcodierten Wallet-Erweiterungs-IDs befindet sich auch MetaMasksnkbihfbeogaeaoehlefnkodbefgpgknn - Bei den ersten acht Wallet-Erweiterungspfaden wird das LevelDB-Verzeichnis in einen temporären Ordner kopiert, einzelne Dateien werden hochgeladen, und anhand der
cldbs-Antwort des Servers wird entschieden, ob der Vorgang abgeschlossen ist oder erneut versucht wird - Die drei auf Port
7649beobachteten Uploads waren die folgenden DatenbankenLogin_Data.sqlite: 51.200 ByteLogin_Data_For_Account.sqlite: 51.200 ByteWeb_Data.sqlite: 262.144 Byte
- Die Testdaten enthielten keine gespeicherten Passwörter oder Kartenzeilen, aber sechs Autofill-Werte und Browser-Metadaten
- Chromium-basierte Browser verschlüsseln einige Felder lokal, daher lassen sich allein aus den Datenbanken nicht immer Klartext-Geheimnisse rekonstruieren
- In Kombination mit Betriebssystem-Secrets, Cookies, Erweiterungsspeichern und einem entsperrten Browser wird es jedoch Teil einer Pipeline zum Diebstahl von Zugangsdaten
- Nachdem die benötigten Browserdaten und LevelDBs hochgeladen wurden oder der Server den Vorgang als abgeschlossen markiert, beendet es sich und wartet nicht auf weitere Befehle des Operators
Rekursiver Dateiscanner und Clipboard-Monitor
- Der rekursive Dateiscanner erstellt keine separate Datei, sondern wird mit
node -eausgeführt und beginnt die Suche im Home-Verzeichnis des Benutzers- Unter Windows zählt er mit
Get-CimInstance Win32_LogicalDiskLaufwerksbuchstaben auf und prüft auch das Stammverzeichnis jedes Laufwerks - Zu den Sammelmustern für Dateien gehören
*.env*,*.md,*.pem,*.ini,*.secret,*.json,*.js,*.ts,*.csv,*.txt,*.doc,*.docx,*.pdf,*.xlsx,.zsh_history,.bash_history ~/.ssh,~/.aws,~/.azure,~/.config,~/.foundrywerden automatisch als interessante Ordner behandelt- Auch Namen wie
metamask,bitcoin,btc,solana,secret phrase,private keywerden gesucht - Ergebnisse werden an
http://45.146.252.17:7646/uploadübertragen
- Unter Windows zählt er mit
- In der Köderumgebung wurden unter anderem
id_ed25519,id_ed25519.pub,History.txt,seed.js,password.js,tokens.js,ConnectWalletButton.js,ExportWallet.js,RegisterWallet.js,tailwind.config.js,aptos-cli.jsontatsächlich hochgeladen - Während
ldataBrowser- und Wallet-Speicher übernimmt, sammelt der Dateiscanner breit SSH-Schlüssel, Konfigurationen, Quellcode, lokale Secrets, Shell-Historien und Projektdateien - Auch der Clipboard-Monitor wird mit
node -eausgeführt; sein Prozessname istnpm-compiler.log- Nach einigen Sekunden Wartezeit liest er wiederholt die Zwischenablage aus
- Unter macOS verwendet er
pbpaste, unter Windowspowershell -NoProfile -NonInteractive Get-Clipboard - Geänderte Werte werden an
http://45.146.252.17/api/service/makeloggesendet
- Auch ohne das Format zu interpretieren, kann er Passwörter, Recovery-Phrasen, private Schlüssel, API-Tokens, Einmalcodes, GitHub-URLs, Wallet-Adressen und Deployment-Secrets, die der Benutzer kopiert, unverändert erfassen
Grundsätze vor dem Ausführen einer Recruiting-Aufgabe
- Aufgaben-Repositories von unbekannten Personen sollten bis zur Sicherheitsprüfung als nicht vertrauenswürdiger ausführbarer Code behandelt werden
- Vor
yarn install,npm install,yarn build,yarn startsollten die folgenden Punkte geprüft werdenpackage.json- Lifecycle-Skripte
- Konfigurationsdateien
- offensichtliche Dependency-Hooks
- In diesem Fall versteckte sich der Schadcode in
tailwind.config.js, das viele leicht übersehen; Konfigurationsdateien, Dependencies und Build-Tools können ebenfalls als Code ausgeführt werden - Interview-Projekte sollten in einer Einweg-VM oder einem Container ausgeführt werden, in der bzw. dem keine echten Secrets eingebunden sind
- persönliches Browserprofil
- Passwortmanager
- SSH-Schlüssel
- Kryptowährungs-Wallet
- GitHub-Token
- Cloud-Zugangsdaten
- Banking-Sitzung
- primäres E-Mail-Konto
- Für Aufgaben, die ein Konto oder eine Wallet erfordern, sollte eine neue Testidentität verwendet werden, die kein Guthaben enthält und bei keinem anderen Dienst wiederverwendet wird
- Bei Web3-Aufgaben sollte ausschließlich ein Testnet genutzt werden; selbst wenn es harmlos wirkt, sollte man eine echte Wallet nicht mit unbekannten Projekten verbinden
Indikatoren zur Prüfung einer Infektion
- Unter macOS und Linux sollten zuerst die folgenden Punkte geprüft werden
- laufende Prozesse im Zusammenhang mit
node,pack,scdata,ldata,npm-compiler,vhost.ctl - Verbindungen zu
45.146.252.17oder zu den Ports7641,7646,7649 pack,scdata,ldata,vhost.ctlin temporären Verzeichnissen sowie unter Downloads, Desktop, Documents und Library- Markierungsdatei
*/.npm/vhost.ctl - Zeichenketten wie IP, UID,
/api/service/makelog,node scdata,node ldata,node packinnerhalb des heruntergeladenen Projekts
- laufende Prozesse im Zusammenhang mit
- Unter Windows sollten die folgenden Punkte geprüft werden
- Prozesse
node,npm,cmd,powershell, deren Befehlszeilepack,scdata,ldata,node -e, IP-Adressen oderGet-Clipboardenthält - offene TCP-Verbindungen zu
45.146.252.17oder zu den Remote-Ports7641,7646,7649 pack,scdata,ldata,vhost.ctl,.npm\vhost.ctlunter%TEMP%- bekannte C2-Zeichenketten im Verzeichnis, in das das Interview-Repository geklont wurde
- Prozesse
- Wenn ein laufender Node-Prozess, eine Verbindung zu dieser IP oder eines der Artefakte
pack,scdataoderldatagefunden wird, muss das System als kompromittiert betrachtet werden - Diese Indikatoren sind eine erste, auf die analysierten Samples zugeschnittene Prüfung und kein vollständiges forensisches Verfahren
Bereinigung infizierter Systeme und Austausch von Geheimnissen
- Zuerst sollte der Computer vom Netzwerk getrennt werden; in der infizierten Umgebung sollte man nicht weiter suchen, debuggen oder neue Geheimnisse kopieren
- Wenn Beweise benötigt werden, sollten vor dem Löschen die folgenden Daten gesichert werden
- Prozessliste
- Netzwerkverbindungen
- verdächtige Dateien
- Browserverlauf
- bösartiges Repository
- Danach die Prozesse im Zusammenhang mit
node pack,node scdata,node ldata,node -e,npm-compiler,vhost.ctlbeenden undpack,scdata,ldata,.npm/vhost.ctlaus den temporären Verzeichnissen entfernen - Wenn es sich um eine Wegwerf-VM handelt und normale Node-Arbeiten nicht erhalten werden müssen, kann unter macOS und Linux
pkill nodeoder unter Windows das erzwungene Beenden allernode-Prozesse verwendet werden - Das bösartige Repository und
node_moduleslöschen; falls eine weitere Analyse nötig ist, eine ZIP-Kopie offline aufbewahren - Das Löschen von Dateien allein reicht nicht aus; die folgenden Geheimnisse müssen ersetzt bzw. verworfen werden
- SSH-Schlüssel
- GitHub- und npm-Token
- Cloud-Schlüssel und API-Schlüssel
- Deployment-Geheimnisse
- im Browser gespeicherte Passwörter
- aktive Login-Sitzungen
- Falls Wallet-Seeds oder private Schlüssel mit dem infizierten System in Berührung gekommen sein könnten, sollte auf einem sauberen Gerät eine neue Wallet erstellt und das Guthaben übertragen werden
Angriff auf die Vertrauensgrenzen von Entwicklungswerkzeugen
- Klassische Antivirenprodukte erkannten dieses Repository nicht, und auch ein beliebter AI Coding Agent, der zur Bearbeitung der Aufgabe genutzt wurde, identifizierte den im Projekt versteckten Schadcode nicht
- Da Tailwind JavaScript-Konfigurationsdateien als Node-Module auswertet, wird die IIFE in Zeile 95 ausgeführt, sobald Entwicklungswerkzeuge, Build-Skripte, Editor-Integrationen, die Tailwind CLI, Bundler oder CI-Jobs die Konfiguration laden
- Die normale Tailwind-Konfiguration reichte bis Zeile 94; dahinter waren etwa 27 KB obfuskierter Code angehängt
- Die heruntergeladene Payload wird mit denselben Betriebssystemrechten ausgeführt wie der Benutzer, der die Konfiguration geladen hat
- Sie kann auf lokale Dateien, Browserprofile, gespeicherte Zugangsdaten, Daten von Wallet-Erweiterungen, SSH-Schlüssel, Umgebungsvariablen, Paket-Token, Cloud-Zugangsdaten, Quellcode und die Zwischenablage zugreifen
- Wird sie in CI ausgeführt, können auch Deployment-Geheimnisse, Build-Artefakte, Registry-Zugangsdaten und Produktions-Access-Token offengelegt werden
- Die notwendige Korrektur besteht darin, den obfuskierten JavaScript-Blob aus
tailwind.config.jsvollständig zu entfernen
Noch keine Kommentare.