Caso reale anonimizzato · maggio 2026

Quando un sito WordPress viene hackato sul serio, non ci si chiede se si recupera: ci si chiede quanto tempo ci vuole, quanto costa e quanti dati saltano. La risposta cambia molto a seconda di chi gestisce la pulizia.

Ecco la cronologia di un recupero che abbiamo chiuso in 6 ore sul sito di un cliente, gestito interamente da un sistema automatico. Tutti i nomi e i dettagli identificativi sono rimossi; i numeri e la sequenza tecnica sono reali.

Cosa è successo

Il sito era una rivista nautica con circa 200 articoli pubblicati. Una mattina i visitatori hanno iniziato a vedere redirect a pagine di spam. Il proprietario ha provato ad accedere a wp-admin: errore 500. Il sito era ufficialmente compromesso.

L'attacco lavorava su più livelli:

  • 47 file PHP malware sparsi tra /public_html/, /wp-content/mu-plugins/ e /wp-includes/
  • 8 mu-plugin con backdoor — questi sono i più insidiosi, perché WordPress li carica in automatico senza che compaiano nella lista dei plugin attivi
  • .htaccess manipolato con regole FilesMatch che davano accesso solo ai file backdoor
  • wp-config.php compromesso con credenziali DB cambiate dall'attaccante
  • 6 utenti admin malevoli creati nel database (pattern di nomi: khubaib, sys_, wp_*)
  • 1.411 post infettati con JavaScript obfuscato (_0x hex variables, ~225KB injection per post)
  • 18 revisioni WordPress con la stessa injection (l'attaccante aveva esplicitamente sfruttato l'autosave WP per persistenza)

Perché questo caso era diverso dal solito

I tipici scanner WordPress (Wordfence, Sucuri, MalCare) cercano file .php con pattern noti tipo funzioni di code-execution dinamica, decoder base64, codice obfuscato. Qui invece ci siamo trovati davanti a:

  • File .php.php (doppia estensione) — molti scanner saltano l'estensione "doppia" perché il loro filtro cerca .php letterale
  • JavaScript injected nel post_content del database — gli scanner filesystem non lo guardano
  • Backdoor con nomi camuffati da plugin legittimi (es. 01-mu-AtlasDrift.php, 01-mu-AuroraMesh.php)
  • Modifiche al Theme Builder Divi via DB row, non file — invisibile ai file scanner

Il timeline (6 ore totali)

Ora 0 → 0:30 · Triage iniziale Il sistema di monitoraggio rileva HTTP 500. Parte in automatico: backup completo via cPanel UAPI (tarball 58MB), snapshot DB completo, audit dei findings critici via external probe.

Ora 0:30 → 1:30 · Pulizia dei file Un helper PHP iniettato sul cliente via Fileman API scansiona ricorsivamente:

  • 47 file PHP col profilo del malware → messi in quarantena con backup .MALWARE-{ts}.bak accanto
  • /wp-content/mu-plugins/ ricorsivo → 8 file rimossi (per i mu-plugin lo stub di neutralization deve essere noop, NON un halt — altrimenti WP si ferma al bootstrap, vedi caso WSOD a parte)
  • .htaccess ripristinato con versione clean

Ora 1:30 → 2:30 · Pulizia degli utenti nel DB Query SQL diretta:

  • 6 admin rogue identificati per pattern username
  • Backup wp_users + wp_usermeta + wp_posts (rows che referenziano quegli ID)
  • Riassegnati 1.411 post dall'utente rogue a un nuovo admin generato (username random + password 24 char + email del CRM)
  • Cancellati gli utenti rogue + i loro usermeta + cleanup orphan
  • Verifica: la query ?author=1 ora restituisce 404, la sitemap users mostra solo il nuovo admin

Ora 2:30 → 4:00 · Pulizia dei contenuti Scan SQL su wp_posts.post_content con 6 pattern:

  • Pattern A: <?php literal injection (PHP)
  • Pattern B: _0x[a-f0-9]{4,8} (JavaScript obfuscation)
  • Pattern C: decoder JS (atob, fromCharCode, unescape)
  • Pattern D: redirect chain (location.replace, window.location)
  • Pattern E: post > 50KB con <script (size anomaly)
  • Pattern F: revisions WP con gli stessi pattern (NON skippare — sono storico ma riattivabili)

Pulizia:

  • Taglio del contenuto al primo <script tag → si tiene il prefisso legittimo
  • Si tiene la coda dopo l'ultimo </script> se sostanziale
  • DELETE delle revisioni WordPress infette (storico, non critiche)

Risultato: 5 post pubblicati ripuliti (da 225KB → ~300 byte ciascuno), 18 revisions cancellate.

Ora 4:00 → 5:00 · Pulizia delle tracce residue Lo step che gli scanner standard saltano: togliere gli "scarti del breach" che restano in wp_options:

  • admin_email puntata all'email dell'attaccante (intercetta il reset password)
  • new_admin_email con il vecchio admin in pending change
  • auto_core_update_notified con l'email del vecchio admin
  • WPLANG cambiato in 'en' (frontend <html lang="en"> su un sito italiano)
  • Theme Builder con il typo "Releted news" (sbaglio da non madrelingua nel Divi layout)
  • Post pubblicati con post_content = 0 byte dopo la pulizia del malware

Ora 5:00 → 6:00 · Verifica visiva + hardening Controllo del rendering visivo con browser headless:

  • Body inspection: home > 1KB, contiene i marker del tema
  • Multi-endpoint: /, /wp-login.php, /wp-json/
  • Cloaking test: stesso md5 con UA Chrome e con Googlebot
  • Hardening .htaccess: blocco di wp-admin/install.php, readme.html, license.txt, xmlrpc.php
  • Email al cliente con il report di cosa è stato fatto + le nuove credenziali admin
  • Schedule dell'auto-revoke delle credenziali dopo 7 giorni

Quello che il cliente NON ha dovuto fare

  • Aprire un ticket di supporto
  • Comprare la licenza Wordfence Premium
  • Pagare un consulente esterno per il recupero
  • Ripristinare un backup vecchio, perdendo X giorni di contenuti
  • Cambiare hosting

Cosa puoi fare se non sei nostro cliente

Se gestisci un sito WP da solo:

  1. Verifica /wp-content/mu-plugins/ ogni mese · dovrebbe contenere 0-2 file di plugin che hai installato apposta tu. Tutti gli altri sono sospetti.
  2. Cerca i file con doppia estensione in /public_html e /wp-content con: find . -name ".php." (deve dare 0 risultati)
  3. Controlla gli utenti admin in wp-admin → Utenti → filtro "Amministratore". Se vedi nomi che non riconosci o pattern come sys_ o wp_ random, ti hanno già bucato.
  4. Controlla wp_options via phpMyAdmin: admin_email, new_admin_email, auto_core_update_notified. Se contengono email che non sono le tue, hai un problema serio.

Come lo gestisce WPSonar

Sui siti dei nostri clienti, una catena come quella descritta sopra viene neutralizzata in autonomia entro 6 ore dalla prima detection, senza che il proprietario debba fare niente. Tutto finisce nel nostro audit trail (append-only), e il cliente riceve un report di cosa è successo, cosa abbiamo fatto e quali credenziali deve cambiare.

Il sistema scandaglia le 10 fonti pubbliche di threat intelligence (Patchstack, Wordfence Intelligence, Sucuri Blog, Reddit, WP Tavern e altre) ogni settimana per aggiornare i pattern di detection, così un attacco simile sul cliente successivo lo riconosciamo subito.

Domande frequenti

Quanto tempo serve per recuperare un sito WordPress hackato?

Dipende da quanto è profonda la compromissione. Un attacco su più livelli come quello descritto (file malware + database infetto + utenti rogue) chiede di solito 4-8 ore di lavoro tecnico. Con un sistema che opera da solo, il recupero completo si è chiuso in 6 ore dalla detection, senza aspettare che intervenisse una persona.

Posso recuperare il sito senza perdere i contenuti?

Sì, se la pulizia è chirurgica invece di ripristinare un backup vecchio. Nel caso descritto i 1.411 post sono stati ripuliti dal JavaScript injected tenendo il testo legittimo, e le revisioni infette sono state cancellate. Ripristinare un backup avrebbe fatto perdere tutti i contenuti pubblicati dopo la data del backup.

Come faccio a sapere se il mio sito WordPress ha file malware nascosti?

Controlla la cartella wp-content/mu-plugins/: dovrebbe contenere 0-2 file di plugin che hai installato apposta tu. Cerca i file con doppia estensione (find . -name '.php.' deve restituire zero risultati). Controlla gli utenti amministratore in wp-admin: nomi come sys_ o wp_ seguiti da caratteri random indicano una compromissione.

Gli scanner come Wordfence trovano tutto il malware?

No. Gli scanner filesystem standard non analizzano il contenuto del database (dove può vivere JavaScript injected nei post) e spesso saltano i file con doppia estensione .php.php. Un sito può sembrare pulito a uno scanner e avere comunque malware attivo nel database o nei mu-plugins.

Fonti tecniche