Un sito WordPress italiano compromesso nascondeva JavaScript offuscato capace di interrogare la blockchain tramite RPC Polygon. Lo smart contract restituiva il dominio dello stage successivo, permettendo al loader di recuperare il payload senza inserirne direttamente l’indirizzo nel sito. Un’analisi ricostruisce l’intera catena dell’attacco.
Negli ultimi giorni stavo cercando campagne attive da analizzare per la mia attività di threat research. L’obiettivo era trovare qualcosa che fosse ancora osservabile e che mi permettesse di lavorare direttamente sulle evidenze, senza limitarmi a riprendere indicatori già pubblicati in altri report.
Tra i risultati che stavo controllando mi sono imbattuto in destinationweddinglazio.com, un sito WordPress italiano che compariva associato a indicatori ClearFake ed EtherHiding. Ho deciso di partire da lì.
La prima verifica l’ho fatta in sandbox, utilizzando un ambiente Windows con Chrome. In questa fase non avevo ancora un’ipotesi particolare: volevo soprattutto capire se l’attività segnalata fosse ancora presente e raccogliere abbastanza traffico da poterla ricostruire.
Il sito veniva caricato normalmente, ma durante la navigazione il browser iniziava a contattare diversi endpoint RPC. La sandbox associava parte dell’attività a ClickFix, TerminalFix ed EtherHiding.
Tra il traffico comparivano richieste verso Polygon.
Una delle prime che ho controllato era diretta a à rpc.ankr.com/polygon
Non è stata particolarmente utile perché Ankr ha restituito un errore relativo all’autorizzazione API.
Poco dopo, però, ho trovato una richiesta simile verso QuickNode che era andata a buon fine.
La risposta conteneva questa stringa:
A quel punto sapevo che il browser stava ottenendo un dominio attraverso una richiesta RPC, ma non ancora esattamente da quale parte del codice partisse quella richiesta.
Ho quindi acquisito l’HTML restituito dal sito e ho iniziato a lavorare sul JavaScript.

All’interno della pagina era presente JavaScript offuscato. Il primo livello utilizzava Base64 e una trasformazione XOR; il risultato veniva poi ricostruito con TextDecoder ed eseguito attraverso new Function.
Nel campione che avevo acquisito la chiave XOR era 202.
Tolto questo primo livello, sono comparsi nel codice gli stessi endpoint che avevo visto nel traffico della sandbox:

Il fatto che fossero otto mi ha fatto inizialmente pensare a una semplice lista di alternative. Guardando meglio il codice, però, c’era effettivamente una gestione degli errori che permetteva al loader di provare il provider successivo.
Questo spiegava anche quello che avevo visto nella sandbox: Ankr aveva risposto con un errore, ma l’esecuzione non si era fermata.
Il codice continuava provando un altro RPC.
Ogni tentativo aveva inoltre un timeout di circa cinque secondi. Se il provider non forniva una risposta utilizzabile, la funzione passava ricorsivamente al successivo.
A questo punto sono tornato alla richiesta JSON-RPC che avevo catturato.
Il browser stava effettuando una normale eth_call.
Il contratto interrogato era

Cercando questo selector nella ricerca pubblica esistente sono arrivato a precedenti analisi che lo documentavano come getDomain().
Questo mi ha aiutato a mettere in ordine quello che stavo vedendo.
Il loader non conteneva direttamente fingerprint-veri[.]info. Conteneva invece il contratto e le istruzioni necessarie per interrogarlo.
La risposta dello smart contract veniva trattata come una stringa ABI, decodificata dal JavaScript e successivamente utilizzata per costruire lo stage seguente.
Il dominio che avevo trovato nel traffico della sandbox proveniva quindi da lì.
Una volta ottenuto il dominio, il codice creava dinamicamente un nuovo elemento <script>.
L’URL aveva una struttura simile a questa

Potrebbe avere una funzione legata al caching o alla freshness delle richieste, ma non avendo visibilità sul backend non posso stabilirlo. Nel codice posso vedere come viene generato; non posso vedere come viene interpretato dal server.
Lo stesso discorso valeva per s.
In questa prima fase non sapevo cosa rappresentasse quella stringa. Poteva essere un identificatore della campagna, del sito, di una configurazione o qualcos’altro.
Me la sono semplicemente segnata e ho continuato.
È stato utile non attribuirle subito un significato perché, più avanti, l’ipotesi più immediata si è rivelata poco convincente.
Una volta ricostruito il loader del primo sito ho iniziato a cercare altre osservazioni che condividessero gli stessi elementi.
Non mi interessava trovare necessariamente lo stesso JavaScript. Avevo già abbastanza elementi per aspettarmi che alcuni dettagli potessero cambiare.
Mi sono concentrato soprattutto su contratto, selector, utilizzo degli RPC Polygon e struttura della richiesta verso /api.php.
Durante questa fase è comparso edih4dt.it.
Il sito mi ha attirato l’attenzione per il contesto: EDIH4DT è un European Digital Innovation Hub italiano orientato alla trasformazione digitale sicura della Pubblica Amministrazione.
Non ho però dato per scontato che il codice fosse lo stesso.
Ho acquisito separatamente l’HTML restituito dal sito e ho ricominciato l’analisi.
La prima cosa evidente nell’HTML di EDIH4DT era la presenza ripetuta del marker à <!– wpmbchik –>
Nel campione che ho conservato ne ho contate 24 occorrenze.
Non erano concentrate tutte nello stesso punto della pagina. Il pattern compariva in più parti dell’HTML restituito insieme al codice JavaScript offuscato.
Ho estratto uno dei blocchi e iniziato a rimuovere l’offuscamento.
La struttura ricordava immediatamente quella del primo sito: Base64, XOR, TextDecoder, new Function.
Il codice, però, non era identico.
La chiave XOR era 36, contro 202 osservato su Destination Wedding Lazio.

Cambiavano anche i nomi utilizzati internamente e il guard che impediva esecuzioni multiple. Sul campione EDIH4DT compariva à _85b267f2a3
Anche l’ordine degli RPC era differente.
Sul primo sito avevo trovato Ankr come terzo provider e QuickNode come quarto. Su EDIH4DT la sequenza era stata modificata e QuickNode compariva più avanti.
Continuando a deoffuscare, però, sono arrivato alla parte che mi interessava.
Il contratto era à 0xB6bC9e1D0b2fB96Ab7C47E04Cb0BE477410bC1f2
Il selector à 0xb68d1809
Gli endpoint RPC erano ancora otto.
Era presente la stessa logica di fallback.
La risposta veniva nuovamente decodificata come stringa ABI e il risultato utilizzato per creare uno script con à /api.php?s=…&_v=…
Questa volta il valore di s era à a3946e3ded820e3d2f02885bf63c8a3a176d58bb9403b402
Quindi non avevo trovato una copia dello stesso script.
Avevo trovato un secondo loader con differenze abbastanza evidenti a livello superficiale, ma con lo stesso funzionamento sotto.
A questo punto volevo verificare che il comportamento ricostruito staticamente fosse effettivamente quello eseguito dal browser.
Ho quindi analizzato EDIH4DT anche in sandbox.
Nel traffico ho trovato la richiesta RPC che stavo cercando:

La risposta, una volta decodificata, portava ancora a à https://fingerprint-veri[.]info
Questo eliminava almeno un dubbio: non stavo correlando i due siti soltanto perché avevano qualche stringa in comune.
Durante le mie osservazioni entrambi interrogavano lo stesso contratto con lo stesso selector e ottenevano lo stesso dominio.
Il percorso osservato su EDIH4DT era quindi, in termini molto semplici:

Sul caso EDIH4DT credo sia importante delimitare bene il risultato.
Quello che ho verificato è la presenza di codice JavaScript malevolo nel sito web pubblico e la relativa catena di comunicazione.
Non ho elementi per sostenere che siano stati compromessi sistemi interni del CINI, infrastrutture dei partner di EDIH4DT, sistemi della Pubblica Amministrazione, account o dati personali.
Non ho nemmeno provato a verificarlo.
L’analisi è rimasta sul contenuto pubblicamente accessibile e sull’esecuzione in ambiente sandbox. Non ho effettuato exploitation, scansioni invasive o tentativi di accesso all’infrastruttura server-side.
Questa limitazione è importante anche per quello che viene dopo, perché alcune delle domande più interessanti non possono essere risolte guardando soltanto ciò che WordPress restituisce al browser.
A questo punto avevo due valori differenti di s.

La prima interpretazione che ho considerato era abbastanza semplice: una chiave diversa per ogni vittima.
Ho quindi iniziato a cercare il secondo valore in osservazioni precedenti.
Mi aspettavo eventualmente di trovare altre acquisizioni di EDIH4DT.
Invece sono comparsi siti completamente differenti.
Ho verificato la presenza dello stesso valore in osservazioni pubbliche relative, tra gli altri, a:
Le osservazioni erano distribuite tra luglio e agosto 2026, quindi precedenti alla mia analisi di settembre.
Inoltre il dominio downstream non era sempre fingerprint-veri[.]info.
In alcune osservazioni comparivano infrastrutture differenti, tra cui domini con nomi legati a verifica/autenticazione.
Quindi l’idea che a394… identificasse EDIH4DT non funzionava.
La stessa chiave sopravviveva a vittime diverse e a cambi del dominio utilizzato più avanti nella catena.
Ho trovato anche un altro valore, che inizia con 8402…, con un comportamento simile. In almeno un’analisi relativa a seedworks.com.ng comparivano entrambi.
Questo rende ancora più difficile interpretare s come semplice identificatore univoco del sito.
Nel report avevo bisogno di chiamare queste stringhe in qualche modo e ho usato Persistent Delivery Key, o PDK.
È soltanto un’etichetta di lavoro.
Non conosco il nome utilizzato da chi gestisce l’infrastruttura e, soprattutto, non conosco l’esatta semantica server-side del parametro.
Nell’articolo preferisco quindi parlare semplicemente di chiave di delivery quando possibile.
Continuando a seguire le osservazioni pubbliche dello stesso cluster ho trovato anche richieste con una struttura leggermente diversa à /api.php?k=<chiave>&d=<dato>
In almeno uno dei campioni relativi a Seedworks è stato possibile ricostruire dal valore trasportato in d una struttura contenente campi come:

Questo è abbastanza per dire che, almeno in quella variante, il parametro veniva utilizzato per trasferire informazioni relative al client o alla sessione.
Non ho però ottenuto lo stesso risultato su ogni valore d incontrato.
Per questo non considero corretto descriverlo genericamente come “JSON Base64”, perché potrebbe essere vero soltanto per alcune varianti.
La cosa che mi interessava era un’altra: dopo aver recuperato la configurazione attraverso Polygon, il loader poteva comunicare al backend informazioni sull’ambiente che stava visitando il sito.
Questo è coerente con un’infrastruttura che effettua una forma di selezione o qualificazione del traffico.
Quale sia esattamente la logica utilizzata dal server non posso saperlo dall’esterno.
Arrivato a questo punto ho iniziato a confrontare in maniera più sistematica quello che avevo trovato con le ricerche già disponibili.
Era importante farlo anche per capire quale parte del lavoro fosse effettivamente nuova.
Il concetto di EtherHiding non lo è.
L’utilizzo di Polygon come livello di configurazione non lo è.
Nemmeno il contratto e il selector che avevo trovato erano completamente nuovi.
FileScan ha documentato la stessa coppia contratto/selector e il relativo modello di risoluzione. Altre ricerche hanno analizzato loader con otto RPC, offuscamento JavaScript e richieste /api.php?s=….
Report URI ha osservato lo stesso contratto in altri contesti e, a inizio settembre, un dominio molto simile ma distinto da quello che stavo vedendo io à fingerprint-verification[.]info
che non va confuso con à fingerprint-veri[.]info
osservato nelle mie esecuzioni.
eSentire ha pubblicato analisi sull’ecosistema ErrTraffic, descrivendo compromissioni WordPress, JavaScript offuscato, utilizzo di Polygon e un modello di delivery molto vicino a quello che stavo ricostruendo.
Altre ricerche pubbliche collegano parti dell’infrastruttura e del tooling a un soggetto indicato come LenAI.
Queste fonti mi hanno permesso di dare un contesto migliore ai campioni, ma ho cercato di non usarle per estendere automaticamente le conclusioni.
Ad esempio, se un’altra ricerca osserva un determinato RAT alla fine di una catena simile, non significa che lo stesso RAT sia stato consegnato durante la mia visita a EDIH4DT.
Allo stesso modo, se una ricerca attribuisce lo sviluppo di un toolkit a LenAI, non significa che LenAI sia necessariamente la persona che ha compromesso i WordPress che ho analizzato.
Sono cose diverse.
Nel mio caso considero molto solida la corrispondenza con l’ecosistema ErrTraffic/BW-style.
Non ho invece evidenze sufficienti per identificare l’operatore che ha compromesso i singoli siti.
Durante la ricerca ho analizzato anche unitranscond.com.
Il sito mostrava nuovamente lo stesso contratto, lo stesso selector e lo stesso downstream durante l’esecuzione in sandbox.
Non ho però raccolto su questa vittima lo stesso livello di materiale statico che ho conservato per Destination Wedding Lazio ed EDIH4DT.
Per questo non la considero allo stesso livello dei due casi principali.
È utile come ulteriore osservazione del cluster, ma non voglio trasformare un’evidenza secondaria nella terza colonna dell’analisi solo per rendere il dataset più grande.
I due casi sui quali posso fare il confronto più completo rimangono quelli per cui ho HTML originale, deoffuscazione e osservazione dinamica.
Dopo aver ricostruito il loader ho iniziato inevitabilmente a guardare anche la superficie WordPress di EDIH4DT.
Il sito utilizza il tema Roneous.
Tra le risorse pubblicamente visibili ho identificato inoltre:
Questo rende plausibile che il sito utilizzi una release non recente del tema, ma non permette di stabilire con certezza la versione installata.
Roneous è inoltre interessato da vulnerabilità pubblicamente documentate. Tra queste c’è CVE-2025-69177, relativa a versioni vulnerabili del tema.
Naturalmente ho considerato la possibilità che ci fosse un collegamento.
Ma qui mi sono fermato.
Dal fatto che un sito utilizzi Roneous e che Roneous abbia una vulnerabilità non segue che quella vulnerabilità sia stata utilizzata per compromettere il sito.
Per dimostrarlo servirebbero almeno la versione effettiva installata, log del web server, file modificati, informazioni sul database o altri elementi forensi.
Non li ho.
Quindi nel mio materiale Roneous rimane una pista da verificare, non la spiegazione dell’incidente.
Il vettore iniziale rimane sconosciuto.
Anche questo è un punto sul quale è facile andare oltre quello che i dati permettono.
Sul campione HTML di EDIH4DT ho verificato 24 occorrenze del marker.
Sono abbastanza da far pensare che l’iniezione non sia semplicemente una singola stringa aggiunta manualmente a una pagina.
Il codice compare in differenti regioni dell’output WordPress.
Ma dal browser vedo il risultato finale del rendering, non la sorgente della persistenza.
Non posso dire se il codice risieda nel database, nei file del tema, in un plugin, in un mu-plugin o in un altro componente.
Alcune ricerche su ErrTraffic hanno documentato specifici metodi di persistenza WordPress in altri incidenti.
Sono ottimi elementi da cercare durante un’analisi forense.
Non sono però automaticamente applicabili a EDIH4DT.
A questo punto sono tornato ai due campioni iniziali per capire cosa avesse realmente senso usare come indicatore.
Le differenze erano:

Quindi una firma costruita sulla chiave XOR sarebbe già stata poco utile.
Lo stesso vale per i nomi delle variabili, per il guard e per l’hash dell’intero blocco.
Quello che invece non cambiava era:
È da qui che ho iniziato a costruire la parte di detection.
Una regola sperimentale sul contenuto JavaScript può, ad esempio, richiedere contemporaneamente eth_call, b68d1809, /api.php?s= e la presenza di almeno due RPC Polygon appartenenti alla lista osservata.
Un’altra possibilità è cercare direttamente la combinazione contratto + selector nelle chiamate eth_call.
Sul contenuto WordPress wpmbchik può essere un ulteriore marker, soprattutto quando compare insieme a atob, TextDecoder e new Function.
Quello che eviterei è trattare gli RPC come domini malevoli.
QuickNode, Ankr, PublicNode e gli altri servizi coinvolti sono provider legittimi.
Il dato interessante non è à host contacted QuickNode
ma qualcosa più vicino a

È una sequenza molto più difficile da confondere con il normale utilizzo di un singolo provider RPC.
Una volta capito il funzionamento, il vantaggio operativo è abbastanza evidente.
Supponiamo che oggi il contratto restituisca à fingerprint-veri[.]info
e che domani quel dominio venga sospeso.
Se il dominio fosse scritto direttamente nei JavaScript già iniettati, sarebbe necessario aggiornare i siti compromessi o mantenere un altro meccanismo di redirect.
Con il resolver on-chain, invece, la configurazione può essere aggiornata in un punto separato.
Il loader presente sul WordPress continua a fare quello che faceva prima: interroga il contratto e utilizza quello che riceve.
È anche il motivo per cui considero più utile descrivere Polygon come livello di configurazione/indirezione piuttosto che dire semplicemente che “il malware è sulla blockchain”.
Nel codice che ho analizzato la blockchain non contiene il payload finale.
Fornisce al loader l’informazione necessaria a trovare l’infrastruttura successiva.
L’11 settembre ho deciso di congelare la raccolta.
A quel punto avevo:
Avrei potuto continuare a cercare altri siti.
Probabilmente ne avrei trovati altri.
Ma il numero di vittime non avrebbe risposto alle domande che a quel punto mi interessavano maggiormente.
Non so come sia avvenuto l’accesso iniziale.
Non so dove risieda la persistenza sul server.
Non conosco la semantica esatta delle chiavi passate a s.
Non conosco la logica completa utilizzata dal backend per qualificare il traffico.
E non ho attribuito un payload finale alle visite che ho analizzato.
Per rispondere seriamente almeno alle prime due domande servirebbe la collaborazione di chi gestisce i sistemi coinvolti.
Continuare dall’esterno avrebbe rischiato di produrre soprattutto ipotesi.
Una volta congelata la ricerca ho iniziato a contattare i soggetti interessati.
Ho segnalato il caso EDIH4DT attraverso i contatti disponibili e ho preparato un pacchetto tecnico contenente le evidenze raccolte. Le evidenze sono state trasmesse a CERT-AgID. L’11 settembre CERT-AgID mi ha comunicato di aver censito le campagne malevole segnalate e di aver diramato i relativi Indicatori di Compromissione agli enti accreditati al proprio flusso IoC. La responsible disclosure verso i soggetti direttamente interessati rimane in corso.
Ho inoltre cercato di raggiungere il CINI per individuare un referente tecnico al quale far arrivare direttamente la segnalazione.
Al momento in cui sto scrivendo questa parte, il processo di segnalazione è ancora in corso.
Per questo motivo mantengo separato il materiale utilizzato per la gestione dell’incidente — HTML originali, artefatti completi e altri dettagli — da ciò che può essere pubblicato.
Se avrò modo di confrontarmi con chi gestisce il server, le prime cose che vorrei verificare sono molto semplici: da dove è partita l’iniezione e dove viene mantenuto il codice che continua a comparire nell’HTML.
Sono le due parti dell’incidente che, lavorando soltanto dall’esterno, non posso vedere.
Per ora quello che posso documentare direttamente è il resto: due siti WordPress italiani, due varianti differenti del loader, lo stesso contratto Polygon, lo stesso selector e, durante le osservazioni, lo stesso dominio restituito dal resolver.
Ed è su queste evidenze che preferisco fermare le conclusioni.
Sono ufficialmente aperte le adesioni al Program Sponsor della Red Hot Cyber Conference 2027, la sesta edizione dell’evento annuale gratuito promosso dalla community di Red Hot Cyber per diffondere cultura, competenze e consapevolezza sui temi della cybersecurity, dell’innovazione e delle tecnologie digitali. La Conference si terrà a Roma, martedì 18 e mercoledì 19 maggio 2027, presso l’Auditorium del Seraphicum, nel cuore del quartiere EUR, con una giornata dedicata ai workshop pratici e alle attività tecniche e una seconda giornata interamente dedicata alla conferenza.
Anche per il 2027, le aziende potranno scegliere di sostenere concretamente il progetto attraverso il Program Sponsor, partecipando alla crescita di un appuntamento che mette in relazione professionisti, aziende, istituzioni, studenti, ricercatori e appassionati di tecnologia. Il programma prevede la possibilità di aderire come Sponsor Sostenitore, una formula pensata per le aziende che desiderano essere tra le prime realtà a credere e contribuire alla realizzazione della nuova edizione, oppure attraverso i tre consueti livelli di sponsorizzazione Platinum, Gold e Silver. Ogni livello di sponsorizzazione acquistato, sarà accompagnato da un pacchetto Advertising, con l'opportunità di visibilità attraverso articoli, banner e contenuti all’interno del circuito editoriale di Red Hot Cyber.
Le aziende interessate a conoscere le formule disponibili, il Media Kit e tutte le opportunità previste dal Program Sponsor 2027 possono richiedere informazioni scrivendo a [email protected].