Perché i plugin di sicurezza non trovano tutto: limiti degli scanner a firme

Firme, euristica e punti ciechi: perché uno scanner che gira dentro WordPress non vede malware offuscato, trigger SQL, cron e processi, e come usarlo bene.

Un pannello di scansione con tutti i file segnati come puliti sotto una lente d’ingrandimento, accanto a tre riquadri tratteggiati in rosso per crontab, trigger SQL e processi, fuori dal campo visivo dello scanner

«Ho fatto la scansione e non risulta niente.» È una delle frasi che sentiamo più spesso da chi ci contatta, di solito subito prima di «eppure il sito continua a reindirizzare su un sito di scommesse». Non è un paradosso e non significa che il plugin di sicurezza installato sia di cattiva qualità: significa che ogni scanner ha un campo visivo, e che il malware moderno è scritto apposta per stare fuori da quel campo.

Strumenti come Wordfence, Sucuri, MalCare o iThemes Security (oggi Solid Security) fanno un lavoro utile e bloccano ogni giorno una quantità enorme di attacchi automatici. Capire dove finisce il loro raggio d’azione serve a usarli meglio, non a buttarli via. In questo articolo vediamo come funzionano, perché certe infezioni restano invisibili e cosa bisogna aggiungere per considerare davvero pulito un sito.

Come funziona uno scanner a firme

Il cuore della maggior parte degli scanner è un archivio di firme: impronte e schemi che descrivono malware già visto e analizzato. Una firma può essere l’hash di un file intero, una stringa esatta, oppure un’espressione regolare che riconosce una famiglia di varianti. Lo scanner legge i file del sito, li confronta con l’archivio e segnala le corrispondenze.

Accanto alle firme quasi tutti eseguono un controllo di integrità: confrontano i file del nucleo di WordPress, e dei plugin e temi pubblicati su WordPress.org, con le versioni originali, e segnalano ciò che è stato modificato o aggiunto. È lo stesso principio dei comandi di verifica di WP-CLI, che conviene conoscere perché si possono lanciare da riga di comando senza installare nulla:

# Confronta i file del nucleo con le impronte pubblicate da WordPress.org
wp core verify-checksums --skip-plugins --skip-themes

# Stessa verifica per i plugin presenti nel repository ufficiale
wp plugin verify-checksums --all --skip-plugins --skip-themes

Anche il controllo di integrità ha un perimetro preciso. Funziona solo per ciò di cui esiste un originale pubblico con le relative impronte: il nucleo e i componenti del repository ufficiale. Un tema acquistato su un marketplace o un plugin commerciale non hanno impronte pubblicate, e un file aggiunto in wp-content/uploads o in una cartella creata apposta non ha alcun originale con cui essere confrontato. La verifica del nucleo, inoltre, segnala i file modificati o in più tra quelli del nucleo, ma lascia fuori per scelta tutta la cartella wp-content.

Questo approccio ha due grandi pregi: è veloce e produce pochi falsi allarmi. Se un file corrisponde a una firma di una webshell nota, è quasi certamente una webshell. Il difetto è speculare: una firma riconosce solo ciò che qualcuno ha già visto, e solo nella forma in cui l’ha visto.

Firme ed euristica: due approcci, due limiti opposti

Per coprire le varianti nuove, gli scanner più evoluti affiancano alle firme regole euristiche: invece di cercare un codice preciso, cercano caratteristiche sospette. Una funzione di decodifica il cui risultato finisce in eval, righe lunghe migliaia di caratteri, stringhe ad alta entropia, un file PHP dentro wp-content/uploads, un file con data di modifica diversa da tutti i vicini. Ogni caratteristica aggiunge un punteggio e oltre una soglia il file viene segnalato.

L’euristica trova cose che nessuna firma conosce, ma paga un prezzo: anche il codice legittimo usa base64_decode, alcuni plugin commerciali sono distribuiti codificati con ionCube o SourceGuardian, alcuni temi comprimono le proprie risorse in stringhe lunghissime. Abbassare la soglia vuol dire sommergere l’utente di segnalazioni; alzarla vuol dire lasciar passare il malware scritto con un minimo di cura. Nessuno scanner può permettersi troppi falsi allarmi, perché un utente che ne riceve venti a settimana smette di leggerli.

Confronto tra due approcci di scansione: in alto il riconoscimento a firme, in cui un file viene confrontato con un archivio di hash, stringhe ed espressioni regolari di malware noto e il verdetto è sì o no, con pochi falsi positivi ma cieco alle varianti nuove; in basso l’analisi euristica, in cui caratteristiche come decodifica passata a eval, entropia alta, righe molto lunghe e posizione in uploads sommano un punteggio confrontato con una soglia, con più varianti trovate ma più falsi positivi
Le firme sono precise ma vedono solo il già noto; l’euristica generalizza ma deve scegliere una soglia tra falsi negativi e falsi positivi.

C’è poi il tempo. Tra la comparsa di una nuova variante e la pubblicazione della firma corrispondente passano ore o giorni, e non tutti ricevono le firme nello stesso momento: Wordfence, per esempio, dichiara che la versione gratuita riceve le nuove regole del firewall e le nuove firme di malware 30 giorni dopo la versione a pagamento. È una scelta commerciale legittima, ma va tenuta presente quando si legge un risultato «pulito».

Lo scanner gira dentro l’applicazione compromessa

Il limite più sottovalutato non riguarda le firme, ma la posizione. Un plugin di sicurezza è codice PHP eseguito da WordPress, con lo stesso utente di sistema e gli stessi permessi del resto del sito. Se l’attacco ha ottenuto la possibilità di eseguire codice o di scrivere file, ha esattamente gli stessi poteri dello scanner, e li ha avuti per primo.

In pratica abbiamo visto malware che:

  • disattiva il plugin di sicurezza modificando l’opzione active_plugins nel database, o lo rende inerte rinominandone la cartella;
  • aggiunge i propri file all’elenco delle esclusioni, o segna come «ignorati» gli avvisi già emessi;
  • intercetta le richieste HTTP di WordPress per bloccare il download delle firme aggiornate;
  • si carica da un mu-plugin o da un drop-in, prima dei plugin normali, e filtra ciò che questi possono vedere;
  • si riscrive subito dopo essere stato rimosso, perché un’attività pianificata lo ripristina da una copia nascosta.

Non è un difetto di un prodotto specifico: è una conseguenza strutturale. Per lo stesso motivo nessun antivirus serio si fida di un sistema operativo già compromesso, e l’analisi forense si fa su una copia, da un ambiente pulito. Quando la domanda è «questo sito è compromesso?», la risposta più affidabile arriva da un controllo eseguito fuori dal sito.

Schema di un processo PHP eseguito con l’utente del sito che contiene insieme il nucleo di WordPress, il plugin di sicurezza e il malware: dal malware partono frecce rosse verso il plugin con le azioni disattiva il plugin, aggiunge esclusioni, blocca l’aggiornamento delle firme e filtra i risultati; a destra, separata, una scansione esterna eseguita su una copia dei file con un utente diverso, che il malware non può influenzare
Plugin di sicurezza e malware condividono processo, utente e permessi: chi arriva prima può manomettere l’altro. Una scansione su una copia, da fuori, non ha questo problema.

Codice offuscato, codificato e polimorfico

Chi scrive malware per WordPress conosce le firme degli scanner più diffusi, perché sono installabili gratuitamente da chiunque. Il modo più semplice per aggirarle è non scrivere mai, nel file, le stringhe che le firme cercano. Un esempio minimo del principio:

// Forma classica: qualunque firma la riconosce
eval(base64_decode($_POST['x']));

// Stessa intenzione, nessuna delle stringhe cercate da una firma letterale
$f = str_rot13('onfr64_qrpbqr');   // diventa "base64_decode"
$p = $_POST[chr(120)];             // equivale a $_POST['x']
$d = $f($p);                       // il codice decodificato viene poi eseguito altrove

Le varianti reali sono molto più elaborate: catene di gzinflate, str_rot13 e base64_decode ripetute decine di volte, nomi di variabili generati casualmente a ogni infezione, stringhe spezzate e ricomposte, codice nascosto nei metadati di un’immagine o in un’opzione del database e ricostruito al volo. Il malware polimorfico genera una versione diversa per ogni sito, così l’hash di un file infetto non serve a riconoscere quello del sito accanto.

Un caso a parte sono i file codificati con encoder commerciali come ionCube, Zend Guard o SourceGuardian. Uno scanner basato su PHP non può leggerne il contenuto: può solo prendere atto che il file è codificato. Dato che molti plugin legittimi sono distribuiti così, lo scanner di solito tace. Come spieghiamo nell’articolo sui file offuscati e codificati, la verifica passa dal confronto con il pacchetto originale del produttore, non dalla lettura del file.

Quello che un plugin non vede

Anche lo scanner migliore guarda solo ciò che il suo punto di osservazione gli permette di raggiungere. Un plugin di WordPress vede con buona precisione i file dell’installazione e, in parte, il contenuto del database, come articoli e opzioni. Oltre quel perimetro la visibilità cala rapidamente:

  • file fuori dall’installazione: altri siti dello stesso account, cartelle superiori alla document root, file .user.ini con auto_prepend_file. Alcuni scanner, come Wordfence, possono estendere la scansione oltre la cartella di WordPress, ma l’opzione è disattivata di default e resta limitata ai permessi dell’utente del sito;
  • oggetti del database diversi dalle tabelle: trigger, procedure ed eventi SQL che reinseriscono codice o utenti a ogni salvataggio;
  • attività pianificate del sistema: il crontab dell’utente e le cartelle di cron, dove si nascondono le backdoor che reinfettano il sito;
  • processi in memoria: un processo PHP che ha cancellato il proprio file dal disco non lascia nulla da scansionare, come raccontiamo nell’articolo sui processi «deleted»;
  • configurazione del server: regole di Apache, NGINX o LiteSpeed modificate, moduli caricati, configurazioni di PHP-FPM.

Gli scanner remoti, come Sucuri SiteCheck, hanno un campo visivo ancora diverso: vedono le pagine così come le restituisce il server a un visitatore, e quindi colgono redirect, script iniettati e blacklist, ma non possono vedere i file. Se il malware mostra il contenuto malevolo solo a certi visitatori, per esempio da mobile o provenienti da Google, lo scanner remoto potrebbe non ricevere mai la versione infetta.

Diagramma a livelli della copertura di uno scanner installato come plugin WordPress: livello applicazione con file di WordPress visibili e tabelle del database parzialmente visibili; livello account con altri siti, file fuori dalla document root e .user.ini visibili solo in parte o su opzione; livello database server con trigger, procedure ed eventi non coperti; livello sistema con crontab, processi in memoria e configurazione del server web non coperti
Più ci si allontana dai file di WordPress, meno un plugin riesce a vedere. La persistenza delle infezioni complesse vive soprattutto nei livelli bassi.

Chi ha accesso alla riga di comando può controllare direttamente questi livelli. Alcuni punti di partenza:

# Trigger ed eventi pianificati nel database del sito
mysql -e "SELECT TRIGGER_NAME, EVENT_OBJECT_TABLE FROM information_schema.TRIGGERS
          WHERE TRIGGER_SCHEMA = 'nome_db';
          SELECT EVENT_NAME, STATUS FROM information_schema.EVENTS
          WHERE EVENT_SCHEMA = 'nome_db';"

# Attività pianificate dell'utente del sito
crontab -l

# Processi il cui eseguibile non esiste più su disco
ls -l /proc/*/exe 2>/dev/null | grep '(deleted)'

# Direttive PHP che caricano codice prima di ogni pagina
grep -rn 'auto_prepend_file\|auto_append_file' ~ --include='.user.ini' --include='php.ini' --include='.htaccess'

Falsi negativi e falsi positivi

Un falso negativo, cioè un file infetto che lo scanner non segnala, è il rischio più evidente: produce una falsa sensazione di sicurezza e rimanda la pulizia vera. Ma anche i falsi positivi hanno un costo concreto. Un file legittimo segnalato e cancellato può rompere il sito; un plugin commerciale codificato scambiato per malware e rimosso può bloccare un e-commerce. E un utente abituato ai falsi allarmi impara a premere «ignora» senza leggere, che è esattamente ciò di cui ha bisogno chi attacca.

Per questo il risultato di una scansione va letto come un indizio, non come un verdetto. «Nessun problema trovato» significa «nessuna delle cose che questo strumento sa riconoscere, nei posti in cui può guardare». Una segnalazione, a sua volta, significa «questo file merita un’occhiata», non «questo file va cancellato». La differenza la fa chi interpreta il risultato, con il contesto: da quando esiste il file, chi l’ha creato, se corrisponde all’originale, se compare nei log.

Un esempio tipico dei casi che ci arrivano: lo scanner segnala un file nella cartella della cache, il gestore lo cancella, la scansione successiva risulta pulita e il problema sembra risolto. Il giorno dopo il file è di nuovo lì, con un nome diverso. Lo scanner ha fatto il suo lavoro, riconoscendo il carico; ciò che non poteva vedere era il meccanismo che lo ricreava, in quel caso un evento pianificato nel database. Il risultato «pulito» della seconda scansione era vero e, allo stesso tempo, fuorviante.

Una scansione pulita dice cosa lo scanner non ha trovato, non cosa il sito non contiene.

Come usare bene gli scanner

Nulla di quanto detto è un motivo per disinstallare il plugin di sicurezza. Firewall applicativo, limitazione dei tentativi di accesso, autenticazione a due fattori, avvisi sulle modifiche ai file e sui plugin vulnerabili riducono in modo concreto il rischio di un’infezione, e sono la parte in cui questi strumenti danno il meglio. Il punto è non chiedere loro qualcosa che non possono fare, cioè certificare che un sito già compromesso sia tornato pulito.

Qualche accorgimento aiuta a ottenere il massimo:

  • usare uno scanner interno e uno esterno, perché guardano cose diverse;
  • affiancare alle scansioni la verifica di integrità con WP-CLI e, per i plugin commerciali, il confronto con il pacchetto scaricato dall’area clienti del produttore;
  • quando si sospetta un’infezione, analizzare una copia dei file da un ambiente separato, con strumenti che non dipendono da WordPress, come ClamAV, regole YARA o semplici ricerche con grep e find;
  • controllare periodicamente database, crontab e processi, che nessun plugin copre fino in fondo;
  • tenere i log del server abbastanza a lungo da poter ricostruire da dove è entrato un attacco.

Il nostro approccio

Quando analizziamo un sito lavoriamo da fuori: su una copia di file e database, con accesso al sistema per esaminare crontab, processi, configurazioni e log. Alle firme affianchiamo controlli di integrità, misure di entropia e di struttura dei file, riconoscimento degli encoder commerciali e un confronto con i pacchetti originali. I casi che non corrispondono a nulla di noto, comprese le possibili vulnerabilità non ancora pubbliche, li smistiamo con modelli linguistici aperti eseguiti sui nostri server, e ogni ipotesi viene poi verificata da una persona.

Se il tuo plugin di sicurezza dice che è tutto a posto ma i sintomi restano, è il momento di guardare nei livelli che non vede. La pulizia di un’installazione WordPress è garantita entro 6, 12 o 24 ore a seconda dell’urgenza; puoi descriverci cosa succede e ti diciamo da dove partiremmo.

IL PROSSIMO PASSO

Il tuo sito
è infetto?

Ogni ora conta: il malware continua a colpire visitatori e clienti, e Google, l’hosting e le blacklist non aspettano. Scegli il piano, paga online e condividi gli accessi: la bonifica parte subito, a prezzo fisso e con tempi garantiti.

Richiedi la bonifica

Ti porta ai piani: bonifica entro 6, 12 o 24 ore dalla ricezione degli accessi.

MANAGED SERVER S.R.L.info@rimozionemalware.com +39 02 5656 9681

Lunedì – venerdì · 09:30 – 19:30

Preferisci un modulo online?
Contattaci su managedserver.it ↗