TL; DR
Un singolo editore npm, deadcode09284814, ha condotto una campagna typosquat contro il legittimo axios and chalk-template pacchetti da metà maggio 2026.
La campagna è iniziata come un convenzionale furto di credenziali e portafogli, esfiltrando dati a un Tunnel HTTPS di Serveo.
On 2026-05-17, con axois-utils:1.0.9, l'operatore ha sostituito completamente il payload: stesso scaffold di triple install-hook, stesso publisher, stesso nome del pacchetto.
Ma lo script di installazione è ora diventato un recluta per una botnet DDoS multipiattaforma.
Il carico utile parla a un localhost.run crea un tunnel e accetta comandi di flooding, trasformando gli ambienti infetti in parte di una botnet in grado di effettuare attacchi DDoS.
L'operatore ha persino spedito il Binario del server C2 All'interno del file tarball, si nota una chiara escalation dal furto di credenziali a un'infrastruttura botnet attiva.
Due pacchetti, quattro versioni ancora attive nel registro e un unico operatore che ora esegue entrambi i moduli in parallelo.
Gravità: elevata.
L'attacco: come funziona
La campagna è costruita su un'impalcatura di consegna volutamente noiosa: due nomi di pacchetti typosquat, con una sola lettera di differenza rispetto ai pacchetti con centinaia di milioni di download settimanali (Axios, modello di gesso), e tripla installazione hooks che garantiscono l'esecuzione. Ciò che è interessante è ciò che l'impalcatura porta — e il fatto che l'operatore abbia cambiato il carico senza cambiare nient'altro.
L'impalcatura condivisa
Ogni versione pubblicata di entrambi i pacchetti dichiara lo stesso ciclo di vita di tre hooks in pacchetto.json:
Elenco del carico utile sotto tutti e tre hooks è eccessivo — post-installazione da solo verrebbe eseguito in un'impostazione predefinita installazione di npmLa scelta è importante: npm install –ignore-scripts salta gli script, ma diversi flussi di lavoro comuni (ripristini della cache CI che rieseguono il ciclo di vita) hooks in modo selettivo, o sviluppatori che effettuano solo audit post-installazione) rendere una dichiarazione a tripla ridondanza la scelta più sicura per l'attaccante.
modello di gesso aggiunge un secondo meccanismo: dichiara axois-utils:^1.0.7 come runtime dipendenza. Installazione del typosquatted modello di gesso Pertanto, include anche il relativo typosquat e entrambi i payload vengono eseguiti. I due pacchetti costituiscono una coppia coordinata, non elenchi indipendenti.
Fase A — furto di credenziali/portafogli (15/05/2026 → presente)
La fase A è il carico utile originale. Il caricatore è un corto postinstall.js che punta a un tunnel inverso HTTPS di Serveo:
Il sottodominio Serveo codifica l'IP di destinazione (80.200.28.28) direttamente nel nome host — una convenzione riconoscibile per quel servizio. L'operatore ruota il prefisso di sottodominio casuale tra le versioni per eludere le liste di blocco di domini ingenue, ma l'IP sottostante non si sposta mai.chalk-template:1.0.14 utilizzato 8a3e818ea8f11186-80-200-28-28…; 1.0.16 / 1.0.19 / 1.0.20 utilizzare f04a273bd84c0622-….)
postinstall.js mani libere a phantom.js, un modulo “collector” raggruppato di 7,667 righe. phantom.js accompagna il presentatore per:
chiavi private SSH (~/.ssh/*) |
.npmrc contenuti e qualsiasi npm_* token ambientali |
| File delle credenziali di AWS, GCP e Azure |
regex del token di accesso personale di GitHub (ghp_*, gho_*, ghu_*, ghs_*) |
| Artefatti di portafogli di criptovalute per Bitcoin, Exodus, Electrum, Monero, Litecoin, Dogecoin, Zcash, Dash |
Un ricorsivo .env* Procedura dettagliata ~/projects, ~/dev, ~/code, ~/workspacee la directory di installazione |
Storie Shell e il completo process.env |
Il pacco viene spedito tramite POSTA al tunnel Serveo a /raccogliereNon c'è offuscamento, nessuna logica anti-VM, nessuna fase di staging: l'operatore punta su volume e velocità.
Fase B — Reclutamento DDoS PhantomBot (2026-05-17, solo axois-utils:1.0.9)
La Fase B sostituisce phantom.js + postinstall.js con un singolo file chiamato distrube.js (l'errore di battitura è dell'operatore). Lo scaffold a triplo hook in package.json rimane invariato; il pacchetto mantiene lo stesso nome, ambito e schema di aggiornamento della versione. Dall'esterno, axois-utils:1.0.9 sembra un piccolo seguito della versione 1.0.6. All'interno, si tratta di una famiglia di malware diversa.
distrube.js Si apre con un blocco di configurazione che riporta il marchio dell'operatore:
// 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')}`; |
I commenti sono rivolti a un futuro operatore che eseguirà il kit ("Usa il tuo URL HTTPS localhost.run"). Questo, insieme a ciò che viene fornito insieme al client del bot, è l'indizio che non si tratta solo di un payload per la vittima, ma del kit stesso.
Il flusso:
- Persistenza viene eseguito per primo. Lo script si installa in tre modi diversi per sistema operativo (registro Correre + Cartella di avvio + compiti su Windows; crontab + phantom-bot.service unità systemd + .bashrc/.zshrc aggiungi + /etc/rc.local su Linux; LaunchAgent com.phantom.bot.plist su macOS). Il nome del servizio di persistenza e l'etichetta LaunchAgent sono entrambi robot fantasma / com.phantom.bot, da cui deriva anche il nome della campagna.
- Informazioni di sistema esfiltrate Viene eseguita una sola volta: una richiesta POST di fingerprinting a b94b6bcfa27554.lhr.life:443/collect contenente hostname, piattaforma, architettura, nome utente, CPU/RAM, interfacce di rete, process.env, directory corrente, directory home, versione del nodo e IP pubblico. Questa fase è molto meno aggressiva della Fase A: niente SSH, niente wallet, niente ricorsione di .env. Il compito del bot è quello di registrarsi, non di rubare.
- Ciclo del battito cardiaco Apre una richiesta HTTPS POST ogni 30 secondi all'indirizzo b94b6bcfa27554.lhr.life:443/. Lo User-Agent è PhantomBot/1.0. La verifica TLS è esplicitamente disabilitata (rejectUnauthorized: false). La risposta C2 viene analizzata come JSON nel formato {tipo, destinazione, porta, durata, thread, metodo} e inoltrata.
- Arsenale delle inondazioni è collegato a sei comandi:
| Tipo di comando | Moduli | Note |
|---|---|---|
| ping | Risposta in diretta | Il bot si identifica |
| http | Inondazione HTTP | richiesta di inondazione di livello 7 |
| https | Afflusso di HTTPS | Uguale a http, incapsulato in TLS. |
| tcp | TCP inondazione | 65 KB di spam con payload casuale |
| udp | UDP alluvione | Pacchetti UDP da 65,507 byte |
| veloce | Attacco DoS con ripristino rapido HTTP/2 | La tecnica CVE-2023-44487 del 2023 |
Tutti e cinque i moduli di allagamento prendono un bersaglio, porto, duratae fili Argomentazione: il bot è un flooder generico a pagamento, non mirato a una vittima specifica. L'elenco delle vittime dell'operatore si trova sul server C2, non nel pacchetto.
Cosa c'è di nuovo qui: il binario C2 distribuito
La fase A ha una forma familiare: furto di credenziali, installazione di un gancio, C2 incapsulato dal fornitore. La fase B è anche una forma familiare: le botnet DDoS sono state una presenza fissa nei pacchetti npm dannosi per anni. Ciò che è insolito è che l'operatore ha distribuito il lato server Il kit contenuto nell'archivio tarball di npm:
- c2 — un binario Go ELF compilato da 4 megabyte
- c2.go — il codice sorgente Go di 426 righe per quel binario
Nessuno dei due file viene richiamato da alcun hook di installazione. Non fanno parte del payload della vittima. Si trovano nella directory del pacchetto, proprio come un file di documentazione. L'interpretazione più plausibile è che l'operatore abbia caricato il proprio albero di lavoro di sviluppo su npm senza curare l'elenco dei file — una vera e propria falla nella sicurezza operativa — e che ciò che è stato distribuito sia il kit completo a due lati: il client eseguito dalla vittima e il server eseguito dall'operatore.
Questa è la parte della storia che giustifica l'inquadratura del "kit botnet chiavi in mano". Chiunque abbia scaricato axois-utils:1.0.9 Prima di procedere all'arresto, non hanno solo un campione della vittima, ma anche un server C2 funzionante.
Il punto di svolta, in una frase
Stesso editore, stessi nomi di pacchetto, stessa impalcatura a triplo gancio, stesso marchio "fantasma" — ma il modello di monetizzazione del payload è cambiato da un giorno all'altro: da “raccogli segreti che posso rivendere” a “affitta capacità di inondazione che posso noleggiare”. Le TTP in fase di installazione che i difensori dovrebbero monitorare sono quasi identiche in entrambe le fasi; difese basate sulla firma in base alle stringhe del percorso del portafoglio della Fase A o a phantom.jsIl collettore di 7,667 linee avrebbe completamente saltato la Fase B.
| Data (UTC) | Event |
|---|---|
| 2026-05-15 | Prima pubblicazione: axois-utils:1.0.4 (build di test LAN, postazione di sviluppo a 192.168.129.19) |
| 2026-05-15 | axois-utils:1.0.6 pubblicato — Fase A C2 scambiata a 80.200.28.28 tramite il tunnel di Serveo; il commento della fonte // Change to '80.200.28.28' for public conferma lo scambio dev→prod |
| 2026-05-16 | chalk-tempalte:1.0.14 and 1.0.16 pubblicato — caricatore incatenato che dichiara axois-utils:^1.0.7 come dipendenza di runtime; sottodominio Serveo ruotato |
| 2026-05-16 | Campagna di Fase A scoperta durante una scansione di routine di npm; emessi i verdetti di attività dannosa confermata. |
| 2026-05-17 | axois-utils:1.0.9 pubblicato — perno del payload: reclutamento DDoS PhantomBot tramite tunnel localhost.run; lato operatore c2 binario e c2.go fonte spedita nella palla di catrame |
| 2026-05-17 | chalk-tempalte:1.0.19 and 1.0.20 pubblicato — ancora Fase A (ladro); l'operatore ora esegue entrambi i moduli in parallelo |
| 2026-05-17 | Scoperta della Fase B durante la scansione di routine; verdetti applicati a tutti 2026-05-17 versioni |
| (In corso) | Segnalazioni di rimozione in sospeso; tutti e quattro i pacchetti pubblicati rimangono disponibili sul registro al momento della stesura del presente documento. |
Indicatori di compromesso
personalizzati
| Ecosistema | CONFEZIONE | versioni |
|---|---|---|
| npm | axois-utils (tipo di axios) | 1.0.4, 1.0.6, 1.0.9 |
| npm | chalk-tempalte (tipografia di modello di gesso) | 1.0.14, 1.0.16, 1.0.19, 1.0.20 |
Identità dell'autore
| Settore | Valore |
|---|---|
| npm publisher | deadcode09284814 |
| E-mail di pubblicazione | phantomdeadcode@tutamail.com |
| SCM verifica | nessuna |
Comando e controllo
| Fase | endpoint | Trasporti |
|---|---|---|
| A | f04a273bd84c0622-80-200-28-28.serveousercontent.com:443/collect | Tunnel HTTPS di Serveo |
| A | 8a3e818ea8f11186-80-200-28-28.serveousercontent.com:443/collect | Tunnel HTTPS di Serveo (versione precedente) |
| A | 80.200.28.28:443/collect | Endpoint VPS sottostante |
| B | b94b6bcfa27554.lhr.life:443/ | localhost.run Tunnel inverso HTTPS |
Digest dei file (SHA-256)
| Compila il | SHA-256 | Note |
|---|---|---|
c2 (Go ELF, 4 MB) | 165fa92d237fd017c227d00da06ab788212a62be94bf61e95df2d22d00377ef2 | Server C2 lato operatore, spedito all'interno axois-utils:1.0.9 |
c2.go (426 righe) | 7d0ae79fdb1e9968f3323a3712b624643a782ba3efb2cf3a2cb9c4c5513cea30 | Vai alla fonte per il binario C2 |
distrube.js | 308b15c023088a7188dea4ef609010ac2493eb4c365b103053d7621a9ca5b935 | Client bot Fase B |
phantom.js (chalk-tempalte:1.0.19) | 9e380ec88d3ccf3929e1a104e3b868d4d7b59ca189a8a431a54e9f3357dfdd81 | Raccolta di credenziali/portafogli Fase A |
phantom.js (chalk-tempalte:1.0.20) | d1c9e3f296ee9f7d5032f73f9c504cede50334bc14c394055fd5cb9c3a6e08b3 | Collettore di fase A (variante 1.0.20) |
postinstall.js (chalk-tempalte:1.0.19 = 1.0.20) | ffba9bdd6793edd5b38e12900252c1813a693f59c25af51c3b658cf3f27b6162 | Caricatore di fase A, identico a livello di byte in entrambe le versioni |
Attribuzione e motivazione
Monitoriamo questa campagna come Robot fantasma, prendendo il marchio proprio dell'operatore dal User-Agent: PhantomBot/1.0 intestazione del battito cardiaco, il phantom-bot.service unità systemd, l com.phantom.bot Etichetta LaunchAgent e phantomdeadcode@ Nome utente e-mail. L'operatore utilizza questo nome in modo coerente in almeno quattro documenti.
Catalogo dei segnali
- Publisher - codice morto09284814 su npm. Account a gestione singola, email usa e getta Tutamail, no SCM Verifica. Nessuna pubblicazione precedente a questa campagna.
- Riutilizzo del marchio — “phantom” appare nell’e-mail dell’editore, nel nome del file del raccoglitore della Fase A (phantom.js), nel nome del servizio di persistenza della Fase B (phantom-bot.service), nell'etichetta LaunchAgent (com.phantom.bot), e nello User-Agent del bot (PhantomBot/1.0).
- Infrastruttura — Un singolo VPS a 80.200.28.28 la Fase A si sposta tramite la rotazione del sottodominio Serveo; la Fase B si sposta su un localhost.run tunnel inverso (b94b6bcfa27554.lhr.lifeEntrambi i servizi del fornitore sono gratuiti e richiedono solo connessioni SSH in uscita dal lato dell'operatore, in linea con configurazioni a basso budget e con bassa sicurezza operativa.
- Stile del codice — JavaScript puro ovunque; nessuna offuscamento, nessuna codifica di stringa, nessun controllo anti-VM. I nomi delle variabili sono descrittivi (stealSystemInfo, eseguiComando, httpInondazione). Commenti in distrube.js Il file si rivolge direttamente a un futuro operatore ("Usa il tuo URL HTTPS localhost.run"), suggerendo che fosse destinato a essere ridistribuito come un kit, non utilizzato da un singolo attaccante.
- errore di sicurezza operativa — Il file tarball della Fase B contiene sia il client del bot che il server C2 lato operatore (c2 ELFO + c2.go fonte). Ciò è coerente con un operatore che ha caricato il proprio albero di lavoro su npm senza controllare l'elenco dei file. O l'operatore è inesperto, oppure il kit è significava da distribuire pubblicamente e il binario C2 è parte integrante del prodotto.
- Autoconferma - axois-utils:1.0.4 contiene il commento sorgente // Cambia in '80.200.28.28' per pubblico alla riga 12, confermando la progressione di sviluppo/staging/produzione che gli operatori in genere negano.
Motivazione
Il payload della Fase A è un furto finanziario diretto: credenziali, chiavi cloud, token GitHub e portafogli di criptovalute hanno tutti mercati di rivendita liquidi. La Fase B è anch'essa finanziaria, ma indiretta: i servizi di attacchi DDoS a pagamento ("booter") affittano capacità di flooding al minuto e i bot come quello spedito qui sono l'inventario su cui funzionano questi servizi. Il battito cardiaco di 30 secondi, il generico bersaglio/porto/durata schema di comando e l'arsenale di inondazione a cinque protocolli sono il standard prodotto di un operatore di boot.
Esecuzione di entrambi i moduli in parallelo — chalk-template:1.0.19 and 1.0.20 continuare a spedire il ladro mentre axois-utils:1.0.9 spedisce il bot — suggerisce che l'operatore sta coprendo i flussi di entrate piuttosto che abbandonare la Fase A. Il pivot è un aggiunta, non una sostituzione.
Ciò che non stiamo rivendicando
Non siamo stati in grado di confermare un'identità reale dietro il codice morto09284814 Non attribuiamo questa campagna ad alcun attore, gruppo o paese specifico. Il marchio "fantasma" è sufficientemente coerente tra i vari artefatti da suggerire un singolo operatore, ma la distribuzione del binario C2 in kit lascia aperta la possibilità che futuri pacchetti provenienti da handle non correlati riutilizzino lo stesso codice.
Impatto, tendenze e cosa dovrebbero fare i difensori
Impact
Gli obiettivi legittimi dello squat Axios and modello di gesso sono ampiamente utilizzati nell'ecosistema JavaScript; Axios solo si trova tra i trenta pacchetti npm più scaricati. I nomi typosquat sono a un solo tasto di distanza da quelli reali (assi ↔ Axios, modello ↔ modello), ed entrambe sono ortografie linguisticamente plausibili.
Non siamo stati in grado di ottenere statistiche di download affidabili per le versioni dannose prima della rimozione: npm non conserva i conteggi di download per versione dopo che un pacchetto è stato rimosso dalla pubblicazione e npms.ioI proxy in stile - sono rumorosi a questa scala. Qualsiasi organizzazione il cui file di blocco si risolve in un pacchetto denominato axois-utils or modello di gesso dal giornale codice morto09284814 deve essere trattato come compromesso: ruotare ogni credenziale presente in processo.env Sull'host interessato, verificare i vettori di persistenza per ciascun sistema operativo (vedere "Cosa dovrebbero fare i responsabili della difesa" di seguito) e rimuovere la dipendenza.
Modelli emergenti
Questa campagna esemplifica un cambiamento che abbiamo osservato in diversi recenti incidenti relativi a npm: il ponteggio con gancio di installazione è un bene durevole; il carico utile è intercambiabileLo stesso editore, lo stesso pacchetto, lo stesso preinstallare / install / post-installazione triplo, e persino la stessa cadenza di aggiornamento della versione: l'unica cosa che è cambiata tra axois-utils:1.0.6 and axois-utils:1.0.9 era il file il hooks esecuzione. Rilevamento basato sulla firma in base al payload della Fase A (stringhe del percorso del portafoglio, phantom.jsIl sistema di raccolta dati da 7,667 righe (l'host Serveo C2) avrebbe segnalato le prime tre versioni e perso completamente la Fase B.
Lo stesso schema si ripete in altre campagne del 2026 che abbiamo monitorato: un singolo operatore con una struttura stabile, che alterna furto di credenziali, clienti che imbrogliano agli esami, esfiltrazione di dati tramite bot di Telegram e ora reclutamento per attacchi DDoS. Chi si affida alle firme dei payload continuerà a perdere il secondo round di ogni campagna.
Il corollario è che Le TTP in fase di installazione sono il segnale migliore. Dichiarazioni triple install-hook, installa script che importano https or processo_figlio, installa script che scrivono nelle cartelle di avvio utente e installa script che risolvono i nomi host sui servizi di tunnel inverso gratuiti (Serveo, localhost.run, ngrok, cloudflared) sono tutti rari nei pacchetti legittimi e comuni in quelli dannosi.
Cosa dovrebbero fare i difensori
- Verifica del file di blocco. Cerca ogni Pacchetto-lock.json / filato.lock / pnpm-lock.yaml nella tua organizzazione per le stringhe esatte axois-utils and modello di gessoConsidera ogni partita come un compromesso.
- Ruota i segreti sugli host interessati. Fase A: raccolta in blocco di credenziali SSH, cloud, GitHub, npm e wallet. Si presume che ogni credenziale mai presente in processo.env, ~/.ssh, ~/.aws, ~/.npmrc, ~ / .config, o qualsiasi .env* Il file sull'host interessato è esposto.
- Eliminare la persistenza (Fase B). Su Windows, elimina HKCU\Software\Microsoft\Windows\CurrentVersion\Run\SystemUpdate, rimuovi %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\system-update.bate schtasks /delete /tn SystemUpdate /f. Su Linux, crontab -e e rimuovi @reboot node …, systemctl –user disable –now phantom-bot.service quindi elimina ~/.config/systemd/user/phantom-bot.service, strofinare .bashrc / .zshrc / /etc/rc.local. Su macOS, launchctl unload ~/Library/LaunchAgents/com.phantom.bot.plist quindi elimina il file plist.
- Blocca gli host C2. Aggiungi i quattro endpoint C2 presenti nella tabella IOC alla tua lista di blocco in uscita. *.serveroutercontent.com and *.lhr.life Il servizio può essere bloccato integralmente se il vostro ambiente non prevede un utilizzo legittimo per i servizi di tunneling inverso.
- Caccia tramite TTP in fase di installazione, non il carico utile. Voci del file di blocco dell'inventario di cui pacchetto.json dichiara preinstallare, installe post-installazione Tutti puntano allo stesso script. Verificare l'età del pacchetto e lo stato di verifica dell'editore. Questo schema è raro nei pacchetti legittimi ed è il segnale più affidabile che PhantomBot riutilizza.
- Verifica per il binario C2. Chiunque abbia scaricato axois-utils:1.0.9 ha il server C2 dell'operatore (c2 ELF, sha256 165fa92d…) sul disco. Scansiona le cache e gli archivi degli artefatti CI. Il binario è inattivo di per sé, ma la sua presenza su una workstation è una prova inequivocabile che il pacchetto è stato installato.
Linea di chiusura
Lo stesso operatore, lo stesso pacchetto e lo stesso hook di installazione possono diffondere minacce completamente diverse nell'arco di 48 ore. Concentrati sulla struttura, non sul payload.





