PhantomBot : Du vol d'identifiants aux botnets

PhantomBot : une campagne de typosquattage qui est passée du vol d’identifiants à un kit de botnet clé en main

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.

Titre CIO Toute version d'axois-utils ou de chalk-template de l'éditeur deadcode09284814

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 :

  1. 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.
  2. 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.
  3. 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.
  4. 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

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 (axoisaxios, modèlemodè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.

sca-tools-logiciel-outils-d'analyse-de-composition
Priorisez, corrigez et sécurisez vos risques logiciels
Obtenez votre compte gratuit.
Aucune carte de crédit requise.

Sécurisez le développement et la livraison de vos logiciels

avec la suite de produits Xygeni