TL; DR
Un seul éditeur npm, deadcode09284814, a mené une campagne de typosquattage contre le légitime axios et chalk-template colis à partir de mi-mai 2026.
La campagne a débuté comme un voleur d'identifiants et de portefeuilles classique, exfiltrant des données vers un Tunnel HTTPS Serveo.
On 2026-05-17(la prise en charge axois-utils:1.0.9L'opérateur a entièrement remplacé la charge utile : même structure triple install-hook, même éditeur, même nom de paquet.
Mais le script d'installation est désormais un outil de recrutement pour un botnet DDoS multiplateforme.
La charge utile communique avec un localhost.run Il crée un tunnel et accepte les commandes d'inondation, transformant les environnements infectés en une partie d'un botnet capable d'effectuer des attaques DDoS.
L'opérateur a même expédié le Serveur binaire C2 À l'intérieur de l'archive tar, on observe une nette escalade, du vol d'identifiants à une infrastructure de botnet active.
Deux paquets, quatre versions encore actives sur le registre, et un opérateur exécutant désormais les deux modules en parallèle.
Gravité : élevée.
L'attaque : comment elle fonctionne
La campagne repose sur une structure de diffusion délibérément ennuyeuse : deux noms de paquets typosquats, à une lettre près de paquets comptant des centaines de millions de téléchargements hebdomadaires (axios, gabarit à la craie), et triple installation hooks qui garantissent l'exécution. Ce qui est intéressant, c'est ce que l'échafaudage porte — et le fait que l'opérateur ait changé la cargaison sans rien changer d'autre.
L'échafaudage partagé
Chaque version publiée des deux packages déclare les mêmes trois cycles de vie hooks in package.json:
"scripts": { "preinstall": "node <payload>.js", "install": "node <payload>.js", "postinstall": "node <payload>.js" } Liste des charges utiles sous les trois hooks c'est excessif — post-installation seul fonctionnerait par défaut npm installerLe choix compte : npm install --ignore-scripts ignore les scripts, mais plusieurs flux de travail courants (le cache CI restaure ce cycle de vie de réexécution) hooks de manière sélective, ou des développeurs qui n'auditent que post-installation) faire une déclaration triplement redondante est le pari le plus sûr pour l'attaquant.
gabarit de craie ajoute un deuxième mécanisme : il déclare axois-utils:^1.0.7 en tant que temps d'exécution dépendanceInstallation du typosquatté gabarit à la craie Par conséquent, le typosquat frère est également inclus, et les deux charges utiles s'exécutent. Les deux paquets forment une paire coordonnée, et non des listes indépendantes.
Phase A — vol d'identifiants / de portefeuille (15/05/2026 → présent)
La phase A correspond à la charge utile d'origine. Le chargeur est court. postinstall.js qui pointe vers un tunnel inverse HTTPS Serveo :
// chalk-tempalte/postinstall.js:11-13 const C2_HOST = "f04a273bd84c0622-80-200-28-28.serveousercontent.com"; const C2_PORT = 443; const C2_PATH = '/collect'; Le sous-domaine Serveo encode l'adresse IP de destination (80.200.28.28) directement dans le nom d'hôte — une convention reconnaissable pour ce service. L'opérateur fait tourner le préfixe de sous-domaine aléatoire entre les versions pour contourner les listes de blocage de domaines naïves, mais l'adresse IP sous-jacente ne change jamais. (chalk-template:1.0.14 d'utiliser 8a3e818ea8f11186-80-200-28-28…; 1.0.16 / 1.0.19 / 1.0.20 utiliser f04a273bd84c0622-….)
postinstall.js Laissez tomber. phantom.js, un module « collecteur » groupé de 7 667 lignes. phantom.js accompagne l'hôte pendant :
clés privées SSH (~/.ssh/*) |
.npmrc contenu et tout npm_* jetons d'environnement |
| Fichiers d'identification AWS, GCP et Azure |
GitHub personal-access-token regex (ghp_*, gho_*, ghu_*, ghs_*) |
| Outils pour portefeuilles crypto : Bitcoin, Exodus, Electrum, Monero, Litecoin, Dogecoin, Zcash, Dash |
Une récursive .env* procédure pas à pas ~/projects, ~/dev, ~/code, ~/workspaceet le répertoire de travail d'installation |
Histoires des coquillages et l'intégralité process.env |
Le paquet est envoyé par la méthode POST au tunnel Serveo à l'adresse suivante : /collecterIl n'y a pas d'obfuscation, pas de logique anti-VM, pas de mise en scène — l'opérateur mise sur le volume et la vitesse.
Phase B — Recrutement DDoS PhantomBot (17/05/2026, axois-utils : 1.0.9 uniquement)
La phase B remplace phantom.js et postinstall.js par un seul fichier nommé distrube.js (erreur de frappe). La structure à trois points d'accroche dans package.json reste inchangée ; le paquet conserve le même nom, la même portée et le même modèle de mise à jour de version. De l'extérieur, axois-utils:1.0.9 ressemble à une simple mise à jour de la version 1.0.6. En réalité, il s'agit d'un logiciel malveillant appartenant à une famille différente.
distrube.js s'ouvre sur un bloc de configuration qui indique la marque propre à l'opérateur :
// axois-utils-1.0.9/distrube.js:11-15 |
// Use your localhost.run HTTPS URL (the tunnel handles HTTP internally) |
const C2_HOST = 'b94b6bcfa27554.lhr.life'; // Your localhost.run tunnel |
const C2_PORT = 443; // HTTPS port - tunnel handles SSL |
const BOT_ID = `${os.hostname()}_${Date.now()}_${crypto.randomBytes(4).toString('hex')}`; |
Les commentaires s'adressent à un futur opérateur qui exécutera le kit (« Utilisez votre URL HTTPS localhost.run »). Ceci, ainsi que le contenu fourni avec le client bot, indique qu'il ne s'agit pas simplement d'une charge utile destinée à la victime, mais bien du kit lui-même.
Le flux :
- Persistence Le script s'exécute en premier. Il s'installe de trois manières différentes selon le système d'exploitation (registre). Courir + Dossier de démarrage + schtasks sous Windows ; crontab + service phantom-bot unité systemd + .bashrc/.zshrc ajouter + /etc/rc.local sous Linux ; Agent de lancement com.phantom.bot.plist (sur macOS). Le nom du service de persistance et l'étiquette LaunchAgent sont tous deux robot fantôme / com.phantom.bot, ce qui explique également le nom de la campagne.
- Informations système exfil Exécution unique : une requête POST unique d'empreinte digitale est envoyée à b94b6bcfa27554.lhr.life:443/collect, contenant le nom d'hôte, la plateforme, l'architecture, le nom d'utilisateur, le processeur/la RAM, les interfaces réseau, le fichier process.env, le répertoire de travail courant, le répertoire personnel, la version du nœud et l'adresse IP publique. Cette méthode est beaucoup moins agressive que la phase A : pas de SSH, pas de portefeuilles numériques, pas de récursion dans les fichiers .env. Le rôle du bot est d'enregistrer des comptes, pas de voler des données.
- boucle de battements cardiaques Une requête HTTPS POST est envoyée toutes les 30 secondes à b94b6bcfa27554.lhr.life:443/. L'agent utilisateur est PhantomBot/1.0. La vérification TLS est explicitement désactivée (rejectUnauthorized: false). La réponse du serveur de commande et de contrôle (C2) est analysée au format JSON {type, target, port, duration, threads, method} et transmise.
- arsenal du Déluge est câblé pour six commandes :
| Type de commande | Module | Remarques |
|---|---|---|
| ping | Réponse en direct | Le bot s'identifie |
| http | Inondation HTTP | Inondation de requêtes de couche 7 |
| https | Inondation HTTPS | Identique à HTTP, encapsulé TLS |
| tcp | inondation TCP | spam à charge utile aléatoire de 65 Ko |
| udp | Inondation UDP | Paquets UDP de 65 507 octets |
| RÉPONSE | Attaque par déni de service (DoS) à réinitialisation rapide HTTP/2 | La technique CVE-2023-44487 de 2023 |
Les cinq modules d'inondation prennent tous un l'objectif, port, durée et discussions Argument : le bot est un programme de flooding générique à but lucratif, sans cibler de victime particulière. La liste des victimes de l’opérateur se trouve sur le serveur de commande et de contrôle, et non dans le package.
Nouveautés ici : le binaire C2 livré
La phase A présente un schéma familier : vol d’identifiants, installation d’un point d’entrée, C2 via un tunnel fourni par le fournisseur. La phase B est… aussi Une forme familière : les botnets DDoS sont un élément récurrent des paquets npm malveillants depuis des années. Ce qui est inhabituel, c’est que l’opérateur ait distribué le du côté serveur du kit contenu dans l'archive tar npm :
- c2 — un binaire ELF Go compilé de 4 mégaoctets
- c2.go — le code source Go de 426 lignes pour ce binaire
Aucun de ces fichiers n'est requis par un quelconque processus d'installation. Ils ne font pas partie de la charge utile de la victime. Ils se trouvent dans le répertoire du paquet, au même titre qu'un fichier de documentation. L'explication la plus plausible est que l'opérateur a déployé son environnement de développement sur npm sans vérifier la liste des fichiers — une véritable erreur de sécurité opérationnelle — et que le produit distribué est l'ensemble du kit double face : le client exécuté par la victime et le serveur exécuté par l'opérateur.
C’est cette partie de l’histoire qui justifie l’expression « kit botnet clé en main ». Quiconque a téléchargé axois-utils:1.0.9 Avant de démanteler le système, ils ne disposent pas seulement d'un échantillon de victime, mais aussi d'un serveur C2 fonctionnel.
Le pivot, en une phrase
Même éditeur, mêmes noms de conditionnement, même structure à triple crochet, même marque « fantôme » — mais Le modèle de monétisation de la charge utile a changé du jour au lendemain.: de « récolter des secrets que je peux revendre » à « louer une capacité de traitement des inondations que je peux louer ». Les TTP (Tactiques, Techniques et Procédures) d'installation que les défenseurs doivent surveiller sont presque identiques dans les deux phases ; des défenses basées sur les signatures, indexées sur les chaînes de chemin de portefeuille de la phase A ou sur phantom.jsLe collecteur de 7 667 lignes de cette entreprise aurait complètement raté la phase B.
| Date (UTC) | Espaces |
|---|---|
| 2026-05-15 | Première publication : axois-utils:1.0.4 (Version de test LAN, configuration de développement à 192.168.129.19) |
| 2026-05-15 | axois-utils:1.0.6 publié — Phase A C2 remplacée par 80.200.28.28 via le tunnel Serveo ; le commentaire source // Change to '80.200.28.28' for public confirme la permutation dev→prod |
| 2026-05-16 | chalk-tempalte:1.0.14 et 1.0.16 publié — chargeur en chaîne déclarant axois-utils:^1.0.7 en tant que dépendance d'exécution ; sous-domaine Serveo pivoté |
| 2026-05-16 | Campagne de phase A découverte lors d'une analyse de routine avec npm ; verdicts de malveillance confirmée appliqués |
| 2026-05-17 | axois-utils:1.0.9 Publié — Pivot de charge utile : recrutement DDoS PhantomBot via un tunnel localhost.run ; côté opérateur c2 binaire et c2.go source expédiée dans l'archive tar. |
| 2026-05-17 | chalk-tempalte:1.0.19 et 1.0.20 Publié — toujours en phase A (voleur) ; l’opérateur exécute désormais les deux modules en parallèle. |
| 2026-05-17 | Découverte de la phase B lors d'un examen de routine ; les verdicts ont été appliqués à l'ensemble des cas. 2026-05-17 versions |
| (en cours) | Des demandes de retrait sont en cours ; les quatre paquets publiés restent disponibles sur le registre au moment de la rédaction. |
Indicateurs de compromis
Forfaits
| Écosystème | Forfait | versions |
|---|---|---|
| NPM | axois-utils (typosquat d'axios) | 1.0.4, 1.0.6, 1.0.9 |
| NPM | chalk-tempalte (typosquat de gabarit à craie) | 1.0.14, 1.0.16, 1.0.19, 1.0.20 |
Identité de l'auteur
| Champ | Valeur |
|---|---|
| éditeur npm | deadcode09284814 |
| Courriel de l'éditeur | phantomdeadcode@tutamail.com |
| SCM vérification | aucun |
Commande et contrôle
| phase | Endpoint | Transports |
|---|---|---|
| A | f04a273bd84c0622-80-200-28-28.serveousercontent.com:443/collect | Tunnel HTTPS Serveo |
| A | 8a3e818ea8f11186-80-200-28-28.serveousercontent.com:443/collect | Tunnel HTTPS Serveo (version antérieure) |
| A | 80.200.28.28:443/collect | Point de terminaison VPS sous-jacent |
| B | b94b6bcfa27554.lhr.life:443/ | localhost.run tunnel inverse HTTPS |
Condensés de fichiers (SHA-256)
| Fichier | SHA-256 | Remarques |
|---|---|---|
c2 (Go ELF, 4 Mo) | 165fa92d237fd017c227d00da06ab788212a62be94bf61e95df2d22d00377ef2 | Serveur C2 côté opérateur, livré à l'intérieur axois-utils:1.0.9 |
c2.go (426 lignes) | 7d0ae79fdb1e9968f3323a3712b624643a782ba3efb2cf3a2cb9c4c5513cea30 | Accédez au code source du binaire C2 |
distrube.js | 308b15c023088a7188dea4ef609010ac2493eb4c365b103053d7621a9ca5b935 | Client bot Phase B |
phantom.js (chalk-tempalte:1.0.19) | 9e380ec88d3ccf3929e1a104e3b868d4d7b59ca189a8a431a54e9f3357dfdd81 | Collecteur de titres d'identité/de portefeuilles de phase A |
phantom.js (chalk-tempalte:1.0.20) | d1c9e3f296ee9f7d5032f73f9c504cede50334bc14c394055fd5cb9c3a6e08b3 | Collecteur de phase A (variante 1.0.20) |
postinstall.js (chalk-tempalte:1.0.19 = 1.0.20) | ffba9bdd6793edd5b38e12900252c1813a693f59c25af51c3b658cf3f27b6162 | Chargeur de phase A, identique octet par octet dans les deux versions |
Attribution et motivation
Nous suivons cette campagne sous Bot fantôme, reprenant la marque propre à l'opérateur de Agent utilisateur : PhantomBot/1.0 En-tête de battement de cœur, le service phantom-bot l'unité systemd, l' com.phantom.bot Le label LaunchAgent et le phantomdeadcode@ Adresse électronique. L'opérateur utilise systématiquement ce nom dans au moins quatre occurrences.
Catalogue des signaux
- Publisher - deadcode09284814 sur npm. Compte à compte unique, adresse e-mail jetable Tutamail, non SCM Vérification effectuée. Aucune publication antérieure en dehors de cette campagne.
- Réutilisation de la marque — « fantôme » apparaît dans l’e-mail de l’éditeur, dans le nom de fichier du collecteur de la phase A (phantom.js), dans le nom du service de persistance de la phase B (service phantom-bot), dans le label LaunchAgent (com.phantom.bot), et dans l'agent utilisateur du bot (PhantomBot/1.0).
- Infrastructure — Un seul VPS à 80.200.28.28 La phase A se déroule via une rotation de sous-domaine Serveo ; la phase B passe à un localhost.run tunnel inversé (b94b6bcfa27554.lhr.vieLes deux services du fournisseur sont gratuits et ne nécessitent qu'une connexion SSH sortante côté opérateur, ce qui est compatible avec les configurations à faible budget et à faible niveau de sécurité opérationnelle.
- Style de code — JavaScript pur de bout en bout ; aucune obfuscation, aucun encodage de chaînes, aucune vérification anti-VM. Les noms de variables sont descriptifs (volerSystemInfo, exécuterCommande, Inondation httpCommentaires dans distrube.js Le message s'adressait directement à un futur opérateur (« Utilisez votre URL HTTPS localhost.run »), suggérant que le fichier était destiné à être redistribué sous forme de kit et non utilisé par un seul attaquant.
- Fiche OpSec — L'archive tar de la phase B contient à la fois le client bot et le serveur C2 côté opérateur (c2 ELFE + c2.go (source). Cela correspond au comportement d'un opérateur ayant transféré son répertoire de travail vers npm sans vérifier la liste des fichiers. Soit l'opérateur est inexpérimenté, soit le kit est défectueux. signifiait Il sera distribué publiquement et le fichier binaire C2 fait partie du produit.
- Auto-confirmation - axois-utils:1.0.4 contient le commentaire source // Remplacer par '80.200.28.28' pour le public à la ligne 12, confirmant la progression développement / préproduction / production que les opérateurs nient généralement.
motivation
La phase A consiste en un vol financier pur et simple : identifiants, clés cloud, jetons GitHub et portefeuilles crypto ont tous des marchés de revente liquides. La phase B est également financière, mais indirecte : les services de location d’attaques DDoS (« booters ») louent de la capacité de saturation à la minute, et les bots comme celui fourni ici constituent le matériel sur lequel ces services fonctionnent. Le signal de 30 secondes, le signal générique l'objectif/port/durée Le schéma de commande et l'arsenal de cinq protocoles d'inondation sont les standard produit d'un opérateur de booter.
Exécution des deux modules en parallèle — chalk-template:1.0.19 et 1.0.20 continuez à expédier le voleur pendant axois-utils:1.0.9 Le déploiement du bot suggère que l'opérateur diversifie ses sources de revenus plutôt que d'abandonner la phase A. Ce pivot est un ajout, pas un remplacement.
Ce que nous ne prétendons pas
Nous n'avons pas été en mesure de confirmer l'identité réelle de la personne. deadcode09284814 Nous n'attribuons pas cette campagne à un acteur malveillant, un groupe ou un pays identifié. La présence d'une signature « fantôme » dans les différents éléments suggère un opérateur unique, mais la distribution du binaire C2 sous forme de kit laisse supposer que d'autres paquets provenant d'autres comptes pourraient réutiliser le même code.
Impact, tendances et actions que doivent entreprendre les défenseurs
Impact
Les cibles légitimes de squat axios et gabarit à la craie sont largement utilisés dans l'écosystème JavaScript ; axios à lui seul figure parmi les trente packages npm les plus téléchargés. Les noms typosquattés sont à une frappe près des vrais noms (axois ↔ axios, modèle ↔ modèle), et les deux sont des fautes d'orthographe linguistiquement plausibles.
Nous n'avons pas pu obtenir de statistiques de téléchargement fiables pour les versions malveillantes avant leur retrait — npm ne conserve pas le nombre de téléchargements par version après la dépublication d'un paquet, et npms.ioLes proxys de type -style sont bruyants à cette échelle. Toute organisation dont le fichier de verrouillage correspond à un paquet nommé axois-utils or gabarit de craie de l'éditeur deadcode09284814 doivent être considérés comme compromis : faire tourner tous les identifiants présents dans processus.env sur l'hôte affecté, auditez les vecteurs de persistance par système d'exploitation (voir « Ce que les défenseurs doivent faire » ci-dessous) et supprimez la dépendance.
Modèles émergents
Cette campagne illustre un changement que nous avons constaté dans plusieurs incidents récents liés à npm : L'échafaudage à crochets d'installation est un atout durable; la charge utile est interchangeableLe même éditeur, le même emballage, le même préinstaller / installer / post-installation triple, et même la même cadence de mise à jour de version — la seule chose qui ait changé entre axois-utils:1.0.6 et axois-utils:1.0.9 était le fichier hooks Exécution. Détection basée sur la signature et liée à la charge utile de la phase A (chaînes de chemin du portefeuille, phantom.jsLe collecteur de 7 667 lignes (l'hôte Serveo C2) aurait signalé les trois premières versions et aurait complètement manqué la phase B.
On observe le même schéma dans d'autres campagnes de 2026 que nous avons suivies : un seul opérateur, disposant d'une infrastructure stable, alternant entre le vol d'identifiants, les logiciels de triche aux examens, l'exfiltration via des bots Telegram et, désormais, le recrutement par DDoS. Les équipes de défense qui s'appuient sur la signature des charges utiles perdront systématiquement la seconde phase de chaque campagne.
Le corollaire est que Les TTP d'installation constituent le meilleur signal. Déclarations de hook d'installation triples, scripts d'installation qui importent https or enfant_processus, installer des scripts qui écrivent dans les dossiers de démarrage de l'utilisateur, et installer des scripts qui résolvent les noms d'hôtes sur des services de tunnel inverse gratuits (Serveo, localhost.run, ngrok, cloudflared) sont tous rares dans les packages légitimes et courants dans les packages malveillants.
Ce que les défenseurs devraient faire
- Audit des fichiers de verrouillage. Recherchez chaque package-lock.json / fil.lock / pnpm-lock.yaml au sein de votre organisation pour les chaînes exactes axois-utils et gabarit de craieConsidérez tout match comme un compromis.
- Rotation des secrets sur les hôtes affectés. Phase A : collecte massive d'identifiants SSH, cloud, GitHub, npm et portefeuilles numériques. Supposons que tous les identifiants jamais présents dans processus.env, ~ / .ssh, ~/.aws, ~/.npmrc, ~ / .configOu toute .env* Un fichier sur l'hôte concerné est exposé.
- Supprimer la persistance (Phase B). Sous Windows, supprimez HKCU\Software\Microsoft\Windows\CurrentVersion\Run\SystemUpdate, retirer %APPDATA%\Microsoft\Windows\Menu Démarrer\Programmes\Démarrage\system-update.bat et schtasks /delete /tn SystemUpdate /fSous Linux, crontab -e et supprimer @reboot nœud …, systemctl --user disable --now phantom-bot.service puis supprimer ~/.config/systemd/user/phantom-bot.service, frotter .bashrc / .zshrc / /etc/rc.localSur macOS, launchctl décharger ~/Library/LaunchAgents/com.phantom.bot.plist Supprimez ensuite le fichier plist.
- Bloquez les hôtes C2. Ajoutez les quatre points de terminaison C2 du tableau IOC à votre liste de blocage de sortie. *.serveusercontent.com et *.lhr.vie peuvent être bloqués en bloc si votre environnement n'a aucune utilisation légitime des services de tunnel inverse.
- Recherche par TTP d'installation, pas de charge utile. Entrées du fichier de verrouillage d'inventaire dont package.json déclare préinstaller, installer et post-installation Tous ces éléments pointent vers le même script. Vérifiez l'ancienneté du paquet et le statut de vérification de l'éditeur. Ce schéma est rare dans les paquets légitimes et constitue le signal le plus fiable que PhantomBot réutilise.
- Audit du binaire C2. Quiconque a téléchargé axois-utils:1.0.9 possède le serveur C2 de l'opérateur (c2 ELF, sha256 165fa92d…) sur disque. Analyse les caches et les archives d'artefacts CI. Le binaire est inactif en soi, mais sa présence sur un poste de travail prouve sans équivoque que le paquet a été installé.
Ligne de fermeture
Un même opérateur, un même package et un même outil d'installation peuvent générer des menaces totalement différentes en l'espace de 48 heures. Concentrez-vous sur la structure, pas sur la charge utile.




