Caso reale anonimizzato · giugno 2026
Un sito WordPress ripulito che torna sporco nel giro di ore ti dice una cosa sola: hai tolto i sintomi e lasciato in vita la causa.
Questo cliente ci ha fatto lavorare tre volte sullo stesso attacco prima che capissimo dove guardare. Le prime due volte abbiamo fatto quello che si fa: scansione del filesystem, backdoor rimosse, permessi risistemati, sito di nuovo pulito. Poche ore dopo, curl sulla home tornava a scaricare payload. La terza volta abbiamo smesso di guardare i file.
Da dove entrava
Il punto d'ingresso era un plugin dell'elenco chiuso da WordPress.org ad aprile 2026, uno dei 31 sospesi dalla directory nel giro di pochi giorni. Il cliente lo teneva installato da mesi, aggiornato all'ultima versione disponibile, che però non esisteva più: il plugin era stato ritirato. Nessun aggiornamento in arrivo, nessuna patch, una vulnerabilità nota e sfruttabile lasciata aperta.
Da lì l'attaccante caricava una webshell e prendeva il controllo. Fin qui, un attacco ordinario. Fuori dall'ordinario era il modo in cui il malware restava vivo.
Il centro di comando su blockchain
Il malware moderno ha bisogno di un centro di comando, un C2 in gergo, da cui scaricare le istruzioni e il payload aggiornato. Di solito è un dominio. Lo blocchi, e il malware resta orfano: non sa più dove chiamare, e muore.
Qui invece il centro di comando viveva su uno smart contract Ethereum.
Il downloader piazzato sul sito, a ogni esecuzione, interrogava un nodo pubblico della rete Ethereum e leggeva un dato scritto dentro un contratto: l'indirizzo del server da cui scaricare il payload di turno. Quel dato l'attaccante lo cambiava quando voleva, con una transazione. Nessun dominio da mettere in blacklist. Un contratto su una blockchain pubblica non lo spegni, non lo sequestri, non chiami il registrar per farlo sospendere. Resta lì, scritto nel registro distribuito, per sempre.
Ecco perché pulire i file non bastava. Anche cancellando ogni traccia dal filesystem, al primo passaggio di un job pianificato il sito rileggeva l'indirizzo dal contratto, tornava a scaricare il downloader e si reinfettava da solo.
La cronologia, giorno per giorno
Giorno 1 · Prima pulizia Scansione euristica del filesystem: about.php, un paio di file con nomi da backdoor sotto /wp-content/uploads/, il classico offuscamento con decodifica base64 dentro una eval. Rimossi, backup, permessi corretti, sito pulito. HTTP 200, home regolare. Chiuso.
Giorno 1, sera · Reinfezione Il monitoraggio rileva di nuovo traffico in uscita anomalo verso un IP mai visto. Ricontrollo: la webshell è tornata, con un nome diverso. Ripuliamo di nuovo. Torna di nuovo.
Giorno 2 · Cambio di rotta Basta rincorrere i file. Se il malware si riscarica da solo, il meccanismo che lo richiama vive da qualche parte che sopravvive alla pulizia del filesystem. In WordPress quel posto è il database.
Giorno 2 · Audit del database Due reperti, ed erano la vera testa dell'attacco:
- una option in
wp_optionsconautoload = yes, quindi caricata a ogni singola richiesta al sito, che conteneva il downloader offuscato - un hook in
wp_cron, un finto evento pianificato, che a ogni passaggio del cron di WordPress eseguiva quel downloader, risolveva l'indirizzo dallo smart contract Ethereum e riscaricava il payload
Il filesystem era solo la scena del delitto. Il movente e l'arma stavano nel database.
Giorno 2 · Rimozione della persistenza Rimossa la option malevola da wp_options, ripulita la voce di cron avvelenata, neutralizzato il downloader. A ogni passaggio abbiamo tenuto un backup della tabella prima di toccarla: mai un DELETE a occhi chiusi su un database di produzione.
Giorno 2 · Blocco in uscita Ultimo passo, il più importante contro un C2 su blockchain: il sito non deve poter parlare con i nodi Ethereum. Abbiamo bloccato le connessioni in uscita verso gli endpoint RPC pubblici della rete, filtrando le chiamate HTTP che WordPress fa verso l'esterno. Se anche fosse rimasto un frammento di downloader da qualche parte, non aveva più modo di chiedere al contratto dove scaricare.
Giorno 3 · Verifica Ventiquattro ore di osservazione. Zero traffico anomalo in uscita, zero webshell riapparse, wp_cron pulito, wp_options senza autoload sospetti. Le reinfezioni si erano fermate.
Cosa ci ha insegnato
Un attacco che ritorna dopo la pulizia ha una radice più in basso di dove hai tagliato. E la radice, nel malware WordPress serio, è quasi sempre la stessa coppia: una option in wp_options con autoload che ricarica il codice a ogni richiesta, e una voce di wp_cron che lo rilancia da sola. Sul filesystem il malware si vede; nel database resiste. Chi pulisce solo quello che vede lo ritrova il giorno dopo.
Lo smart contract come centro di comando alza l'asticella. È la stessa resilienza per cui la blockchain esiste, rivolta contro di te: un indirizzo che nessuno può oscurare, sequestrare o togliere. Contro un C2 del genere la mossa che chiude la partita lavora su due fronti insieme, e nessuno dei due sta nei file. Da un lato togli al sito la voce per chiamare all'esterno, bloccandogli l'uscita verso quei nodi. Dall'altro strappi la persistenza dal database. Pulire i file e sperare lascia intatto tutto quello che conta.
Come lavora WPSonar su questo
Un cliente su un piano di manutenzione attiva non avrebbe avuto il plugin ritirato ancora installato: la sospensione dalla directory di WordPress.org è uno degli eventi che teniamo d'occhio, e un plugin che sparisce dalla directory va rimosso subito, non tenuto perché «tanto è aggiornato». E dopo ogni intervento su un sito compromesso l'audit non si ferma al filesystem: wp_options, wp_cron, gli utenti amministratori e il traffico in uscita passano tutti sotto controllo prima di chiamare pulito un sito. Perché un sito è pulito quando smette di tornare sporco, non un minuto prima.