File PHP offuscati: malware o plugin cifrato con ionCube e SourceGuardian?

Catene base64, gzinflate ed eval e file cifrati con ionCube, SourceGuardian o Zend Guard: come distinguere un plugin in licenza da un malware offuscato.

Due file PHP affiancati: uno con uno scudo verde e un lucchetto, l’altro pieno di codice illeggibile che inizia con eval e gzinflate, esaminato con una lente

Aprire un file PHP e trovare una lunga stringa illeggibile è un’esperienza che mette in allarme chiunque. A volte è esattamente ciò che sembra: una backdoor offuscata per non farsi riconoscere. Altre volte è un plugin commerciale protetto con uno strumento di cifratura come ionCube o SourceGuardian, perfettamente legittimo e regolarmente pagato. Cancellare il secondo rompe il sito; lasciare il primo lo lascia infetto.

In questo articolo vediamo le tecniche di offuscamento più comuni nel malware PHP, come si presentano i file cifrati legittimamente e quali criteri usare per distinguerli. E perché molti scanner, proprio su questi file, non riescono a dare una risposta affidabile.

Perché il malware si offusca

L’offuscamento ha due obiettivi: impedire a un essere umano di capire a colpo d’occhio cosa fa il codice, e impedire a uno scanner di riconoscerlo confrontandolo con un elenco di firme note. Il codice non cambia comportamento; cambia solo il modo in cui è scritto. E siccome lo stesso malware può essere offuscato in infiniti modi diversi, ogni variante ha una forma nuova, che nessuna firma esistente descrive.

Le catene di decodifica

La tecnica più diffusa è racchiudere il codice vero in una stringa codificata e decodificarla al momento dell’esecuzione, spesso con più passaggi in cascata:

<?php
eval(gzinflate(base64_decode('7b1pc9tItjD8eSb/Q9mtHssXq5r...')));

// Varianti con passaggi aggiuntivi
eval(str_rot13(gzinflate(str_rot13(base64_decode('...')))));
eval(gzuncompress(strrev(base64_decode('...'))));

base64_decode trasforma testo in dati binari, gzinflate e gzuncompress li decomprimono, str_rot13 e strrev aggiungono una trasformazione in più, e alla fine eval esegue il risultato come codice PHP. Spesso il risultato della prima decodifica è a sua volta una catena simile, per decine di livelli.

Funzioni variabili e costruzione dinamica

Siccome molti scanner cercano parole come eval o base64_decode, le varianti più curate evitano di scriverle. PHP permette di chiamare una funzione il cui nome è contenuto in una variabile, e di costruire quel nome un pezzo alla volta:

<?php
$a = 'bas' . 'e64_' . 'decode';
$b = "\x67\x7a\x69\x6e\x66\x6c\x61\x74\x65"; // "gzinflate" in esadecimale
$c = $b($a($_POST['d']));
@array_map('assert', array($c)); // assert come eval, solo su PHP 7 e precedenti

// Esecuzione tramite callback, senza la parola eval
call_user_func($GLOBALS['f'], $_COOKIE['k']);

Si trovano anche preg_replace con il modificatore /e (rimosso da PHP 7), create_function (rimossa da PHP 8), file inclusi con estensioni innocue come .ico o .png, e codice che riceve le istruzioni direttamente dalla richiesta, attraverso un parametro POST o un cookie, così che il file sul disco contenga solo l’«esecutore», senza alcun carico riconoscibile.

Come decodificare senza eseguire

La regola principale è non eseguire mai un file sospetto per vedere cosa fa, e nemmeno sostituire eval con echo in un ambiente di produzione: basta un passaggio sfuggito per far girare il codice. La decodifica si fa su una copia del file, in un ambiente isolato e senza rete, applicando un passaggio alla volta con uno script separato che si limita a trasformare stringhe. A ogni livello si guarda il risultato e si decide il passaggio successivo. Il codice finale in chiaro è quello che conta: dice cosa fa la backdoor, a quali indirizzi si collega e, spesso, quali altri file ha creato.

I file cifrati legittimi: ionCube, SourceGuardian, Zend Guard

Alcuni sviluppatori di software commerciale proteggono il proprio codice con strumenti che lo compilano in un formato che solo un’estensione del server, il cosiddetto loader, sa eseguire. Il file resta un file PHP, ma il suo contenuto è in gran parte dati binari codificati, preceduti da un’intestazione riconoscibile:

  • ionCube: il file inizia con un commento e un controllo della presenza dell’estensione, del tipo if(!extension_loaded('ionCube Loader')), con un messaggio che spiega come installare il loader; per funzionare richiede l’estensione ionCube Loader attiva;
  • SourceGuardian: il file contiene un richiamo alla funzione sg_load() con i dati cifrati e un controllo analogo sulla presenza del loader;
  • Zend Guard (Zend Encoder nelle versioni più vecchie): il file inizia con un’intestazione @Zend;, ma Zend Guard non è più sviluppato e il suo loader esiste solo fino a PHP 5.6. Su un server con PHP 7 o 8 un file di questo tipo non può essere eseguito: se è lì, o è un residuo di un vecchio software, o è qualcosa che imita quell’intestazione.
# Quali loader sono installati sul server
php -m | grep -iE 'ioncube|sourceguardian|zend guard'

# File che richiedono un loader
grep -rlE "ionCube Loader|sg_load\(|^<\?php @Zend;" wp-content/

Nell’ecosistema WordPress questi file si trovano soprattutto in plugin e temi commerciali venduti fuori dalla directory ufficiale. Le linee guida della directory di WordPress.org non ammettono codice offuscato: un plugin scaricato da WordPress.org che contiene file cifrati è quindi già di per sé un’anomalia.

Distinguere un plugin in licenza da un malware

Nessun criterio da solo è decisivo, ma insieme danno una risposta affidabile:

  1. Provenienza: il file appartiene a un plugin o tema commerciale che il cliente ha effettivamente acquistato? Il pacchetto originale scaricato dall’area riservata del produttore contiene lo stesso file, con lo stesso contenuto? Un confronto dei checksum risolve la maggior parte dei dubbi.
  2. Posizione e nome: un file cifrato con ionCube dentro la cartella di un plugin che lo dichiara è normale; lo stesso file in wp-content/uploads/2024/03/ o con il nome di un file del core non lo è.
  3. Coerenza con il server: un file che richiede un loader non installato non viene eseguito. Se il sito funziona e il loader non c’è, quel file non fa parte del funzionamento del sito.
  4. Intestazione e struttura: il malware a volte imita l’intestazione di un encoder commerciale e poi, poche righe sotto, contiene una normale catena eval(base64_decode(…)). Un file cifrato vero non ha codice PHP in chiaro dopo l’intestazione.
  5. Integrità del resto: per il core e per i plugin di WordPress.org, wp core verify-checksums e wp plugin verify-checksums --all segnalano ogni file modificato o aggiunto rispetto alla versione ufficiale.

Perché gli scanner basati su firme li mancano

Uno scanner basato su firme confronta i file con un elenco di schemi di malware già noti. Funziona bene contro le infezioni diffuse e ripetitive, ma ha due limiti strutturali. Il primo è che ogni nuova variante offuscata è diversa da tutte quelle precedenti, e finché qualcuno non la analizza e ne aggiunge la firma, lo scanner non la riconosce. Il secondo riguarda proprio i file cifrati: il loro contenuto è binario e non si può leggere senza il loader, quindi non ci sono stringhe su cui applicare le firme. Segnalare ogni file cifrato come sospetto produrrebbe un’enorme quantità di falsi positivi sui plugin commerciali, e molti scanner scelgono quindi di ignorarli. È un compromesso ragionevole per uno strumento automatico, ma lascia un punto cieco di cui un attacco può approfittare.

Il nostro sistema di analisi affronta il problema da più direzioni: oltre alle firme misura l’entropia e la struttura dei file per individuare contenuti codificati, riconosce le intestazioni degli encoder e le verifica rispetto ai loader presenti e ai pacchetti originali, e segnala i file la cui posizione, data o proprietario non sono coerenti con il resto dell’installazione. I casi dubbi li guarda una persona. Se hai trovato file illeggibili sul tuo sito e non sai se fidarti, scrivici: è una domanda a cui si può rispondere con certezza, senza cancellare niente alla cieca.

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 ↗