Malware WordPress auto-riparante si nasconde nel database e nella RAM
Gli analisti di sicurezza di Sucuri hanno documentato una famiglia di malware WordPress che chiamano SC, una rete auto-riparante che sopravvive alla rimozione memorizzando copie di sé stessa in almeno otto posti contemporaneamente e ricostruendo qualsiasi componente eliminato nel giro di pochi secondi. La ricerca, pubblicata il 30 settembre 2026 dall'analista di sicurezza di Sucuri Gabriel Barbosa, nasce da una pulizia reale in cui la stessa backdoor continuava a tornare, indipendentemente da quanto attentamente venissero eliminati i file visibili. Il nome SC deriva dai marcatori 'SC_' trovati nel contenuto iniettato.
Secondo Sucuri, ogni file SC recuperato condivide lo stesso schema di offuscamento: non c'è eval, nessun marcatore sui pezzi più recenti e nessun nome di funzione leggibile. Invece, ogni file porta con sé una tabella di stringhe mescolate e un piccolo decodificatore che risolve un indice numerico in un nome di funzione reale attraverso un cifrario di sostituzione posizionale.
L'infezione ha otto componenti fondamentali. Il primo è un trigger .user.ini con una singola riga che imposta auto_prepend_file, una direttiva di configurazione PHP che esegue un file specificato prima di ogni richiesta in quell'albero di directory, anche richieste che non raggiungono mai WordPress. PHP memorizza nella cache questo valore, motivo per cui eliminare il target del prepend mentre la cache è ancora calda fa fallire ogni richiesta PHP sull'account fino alla scadenza della cache.
Il secondo componente è un file shim PHP visibile. Nel caso documentato si chiamava c1b12371.php, ma il nome varia da sito a sito. Il .user.ini punta a questo shim, e lo shim fa una sola cosa: se accanto esiste un file nascosto con prefisso punto, include quel file nascosto. Se un difensore rimuove solo il file nascosto, lo shim non fa nulla in silenzio e il sito resta attivo, dando tempo all'attaccante mentre un altro componente ricrea il file nascosto.
Il terzo componente è il file nascosto con prefisso punto, il primo vero loader. Individua il plugin falso e lo ricostruisce nella directory mu-plugins da tre fonti provate in ordine: una copia esistente nella cartella plugins, uno stub codificato nella directory cache e un bundle di ripristino ZIP con un nome esadecimale casuale. Scrive attraverso un file temporaneo, imposta i permessi del file a 0644 e chiama opcache_invalidate in modo che il file appena scritto venga eseguito immediatamente. Definisce anche una costante chiamata SC_AUTO_PREPEND, collegandola al lato auto_prepend della famiglia.
Il quarto componente è il drop-in wp-content/db.php, un file speciale di WordPress caricato molto presto durante l'avvio. Questa copia porta con sé l'intero payload della backdoor al suo interno come blob gzip più base64, due comuni formati di compressione e codifica. Su qualsiasi richiesta in cui il plugin falso è mancante o troppo piccolo, decodifica il blob e riscrive il plugin direttamente su disco.
Il quinto componente è il drop-in wp-content/advanced-cache.php, la posizione più precoce e pericolosa di tutte. Quando la cache è abilitata, WordPress carica advanced-cache.php prima dei plugin ordinari. A differenza di db.php, non porta il payload in linea. È un finder che può ricostruire il plugin da cinque fonti indipendenti in ordine: un mu-plugin esistente, una copia plugin esistente, un segmento di memoria condivisa System V contenente codice PHP, un bundle ZIP cercato in diverse cartelle e infine il database stesso. Per il percorso del database, apre una connessione diretta utilizzando le costanti di credenziali del sito e legge il payload da una riga di opzione specifica, decodificando lo stesso formato gzip. Una volta ottenuta una copia, aggancia plugins_loaded e la include.
Il sesto componente è un'iniezione nel tema. L'attaccante ha aggiunto un blocco delimitato in fondo al functions.php del tema attivo, recintato da marcatori di inizio e fine. Quel blocco è il gemello residente nel tema di db.php: riscrive il plugin ogni volta che scompare.
Il settimo e l'ottavo componente sono due copie identiche del payload effettivo della backdoor, installate sia come plugin must-use (che si carica automaticamente e invisibilmente) sia come plugin normale. La cartella del plugin include persino una convincente pagina di impostazioni falsa, uno shortcode e un hook di attivazione in bella vista, così un'occhiata rapida suggerisce un vero plugin di caching. Le due copie sono deliberatamente ridondanti e il payload aggiorna competitivamente una dall'altra in modo che entrambe rimangano sulla stessa versione.
Il payload è il motivo per cui esiste il resto della rete. Una volta in esecuzione, svolge diversi compiti distinti. Si nasconde filtrando l'elenco dei plugin, il transiente di aggiornamento e le viste dei plugin del sito e della rete per rimuovere la propria voce, così non appare nella schermata dei plugin dell'amministrazione né nei controlli di aggiornamento. Emette anche JavaScript amministrativo per ripulirsi dalla tabella dei plugin come ripiego.
Per il comando e controllo, il payload comunica tramite infrastruttura blockchain. Porta con sé un elenco di circa venti gateway RPC Ethereum pubblici e un insieme di selettori di metodo di smart contract. Invece di un singolo server cablato, invia richieste a quei gateway di terze parti legittimi per leggere istruzioni da uno smart contract. Poiché questi gateway sono legittimi, bloccare solo quello visto nel traffico lascia gli altri come ripiego, quindi l'intero insieme deve essere bloccato insieme.
Il payload rileva le impronte del sito e recupera un payload. Raccoglie URL e host del sito, versioni di WordPress e dei plugin, hash dei percorsi, temi attivi, elenco dei mu-plugin e token di sessione amministratore correnti, crittografa quel bundle e lo invia all'endpoint risolto. La risposta può contenere JavaScript front-end da iniettare, che su un negozio online abilita lo skimming del checkout, più nuovo PHP da installare ed elenchi di plugin di sicurezza da disattivare ed eliminare. Quando gli viene detto di rimuovere un plugin di sicurezza, può disattivarlo, cancellare la sua directory e persino riassegnare o elevare prima un altro account.
Il payload crea anche un amministratore nascosto. Adotta un amministratore nascosto esistente o ne genera uno nuovo, scrivendo l'account direttamente nelle tabelle users e usermeta quando l'API normale di WordPress non è disponibile. Memorizza le capacità sotto la chiave meta delle capacità predefinite, quindi nasconde l'account dall'elenco utenti, dai conteggi utenti e dalle viste dei ruoli tramite filtri di query e conteggio. Forgia anche cookie di autenticazione validi per quell'account, così l'operatore può accedere senza password.
Il payload espone un beacon attivo. Un parametro di richiesta magico, nella forma di un breve prefisso seguito da un valore fisso, viene gestito prima che WordPress finisca di caricarsi. Mentre la rete è presente, quella richiesta restituisce una risposta normale con contenuto e poi esce.
Infine, il payload ricostruisce l'intera rete. Aggancia un ampio insieme di azioni e filtri di WordPress il cui unico scopo è riscrivere ogni altro componente. Rigenera i drop-in db.php e advanced-cache.php, l'iniezione nel tema, il loader nascosto e le sue direttive prepend .htaccess e .user.ini, il bundle di ripristino ZIP, il segmento di memoria condivisa e la copia del payload nel database. Apre persino una connessione raw al database per inserire direttamente la sua opzione payload, bypassando WordPress.
La lezione più importante di questo caso è che la persistenza non è limitata ai file. Sucuri ha recuperato copie vive del payload in tre posizioni non file, ognuna delle quali ricostruirà l'intero insieme alla richiesta successiva. Il database memorizza il payload completo in una riga di opzioni con un nome casuale, nello stesso formato gzip e base64. Il drop-in advanced-cache.php lo rilegge attraverso una connessione diretta al database. Questo è il motivo per cui una pulizia dei file completa e corretta fallisce: il successivo caricamento della pagina ripristina tutto dalla riga. Sui server che supportano la memoria condivisa System V, un metodo per far condividere dati in RAM a processi diversi, il payload viene scritto in un segmento identificato da una chiave numerica fissa. Quel segmento vive in RAM, quindi sopravvive sia all'eliminazione dei file sia alla pulizia del database, e sull'hosting condiviso può persino essere di proprietà di un account diverso. L'infezione registra anche hook cron, inclusi nomi casuali accanto a un hook di fetch noto. Il cron di sistema esegue il file cron di WordPress, non il traffico dei visitatori, quindi attiva la ridistribuzione secondo il programma. Accanto a questi, Sucuri ha visto trigger di database usati da varianti SC correlate che ricreano un amministratore all'inserimento. Un trigger viene eseguito all'interno del database, quindi sopravvive a un ripristino completo dei file e persino all'eliminazione dell'account che continua a ricreare.
Gli indicatori di compromissione elencati da Sucuri includono blocchi PHP inattesi all'interno di wp-content/db.php o wp-content/advanced-cache.php che si aprono con un marcatore di inizio in stile SC_ e una costante di guardia; un blocco delimitato in fondo al functions.php del tema attivo recintato da marcatori di inizio e fine, a volte con il marcatore di inizio duplicato; un .user.ini, php.ini o .htaccess che porta una direttiva auto_prepend_file che punta a un file PHP nascosto con prefisso punto; un plugin falso presente sia in wp-content/mu-plugins sia in wp-content/plugins con contenuti corrispondenti e una pagina di impostazioni plausibile; un bundle di ripristino ZIP con un nome esadecimale casuale in wp-content, wp-content/uploads o una cartella del tema; una riga di opzioni con un nome casuale che contiene un grande blob gzip e base64 più opzioni di controllo e transienti che usano un prefisso in stile sc_; un segmento di memoria condivisa che contiene PHP leggibile che inizia con un tag di apertura; un amministratore con pieni privilegi che potrebbe non apparire nell'elenco utenti con capacità memorizzate sotto la chiave meta delle capacità predefinite, e a volte un'opzione orfana che punta all'ID di quell'account lasciata dopo una pulizia parziale; e richieste in uscita verso gateway RPC Ethereum pubblici dal server web.
Le indicazioni di pulizia di Sucuri insistono sul fatto che l'ordine delle operazioni conta più delle singole eliminazioni. Rimuovere prima i file, nell'ordine sbagliato, innesca semplicemente una riscrittura. L'approccio che funziona è interrompere l'esecuzione, pulire le copie fuori disco prima di quelle su disco e solo allora rimuovere i file in un unico passaggio. Per prima cosa, neutralizzare il prepend prima di eliminare il suo target. Poiché auto_prepend_file è memorizzato nella cache da PHP per un massimo di 300 secondi, svuotare prima il target del prepend in uno stub inerte, quindi rimuovere la direttiva da .user.ini, php.ini e .htaccess. Eliminare il target mentre la cache è ancora calda fa cadere ogni richiesta PHP sull'account. In secondo luogo, pulire le copie del payload fuori disco. Rimuovere la riga del payload dalla tabella delle opzioni, eliminare il segmento di memoria condivisa ed eliminare le opzioni di controllo e i transienti. Se qualcuno di questi rimane, la richiesta successiva attraverso advanced-cache.php riscriverà l'intero insieme su disco. Sull'hosting condiviso, un segmento di memoria condivisa può essere di proprietà di un altro account, nel qual caso solo quell'account o l'host può rimuoverlo, e diventa innocuo una volta che i drop-in che lo leggono sono spariti. In terzo luogo, rimuovere le attività pianificate e qualsiasi trigger di database. Pulire gli hook cron dannosi in modo che il cron di sistema non possa ridistribuire secondo il programma, e controllare information_schema.TRIGGERS per qualsiasi trigger che ricrea un amministratore all'inserimento. Un trigger sopravvissuto ricostruirà l'accesso anche dopo un ripristino completo dei file. In quarto luogo, rimuovere l'amministratore nascosto. Eliminare l'account le cui capacità sono memorizzate sotto la chiave meta delle capacità predefinite e pulire l'opzione orfana che punta al suo ID. In quinto luogo, pulire i file in un unico passaggio. Rimuovere i loader autonomi e lo shim, eliminare entrambe le copie del plugin falso dalle cartelle mu-plugins e plugins, eliminare il bundle di ripristino ZIP ovunque fosse nascosto e rimuovere i drop-in iniettati. Per db.php e advanced-cache.php, questo significa eliminare i file dannosi. Per il functions.php del tema, significa tagliare solo il blocco delimitato tra i marcatori di inizio e fine in modo che il codice legittimo del tema resti intatto. In sesto luogo, scansionare di nuovo e controllare la ricomparsa dei file. Eseguire una scansione completa, quindi monitorare i percorsi interessati. Un componente che ritorna significa che un punto di persistenza è sopravvissuto o che il percorso di ingresso originale è ancora aperto.
I consigli di prevenzione di Sucuri iniziano con il mantenere tutto aggiornato. La maggior parte delle compromissioni che gestiscono sfrutta vulnerabilità note e già corrette in componenti obsoleti, e gli aggiornamenti tempestivi accorciano la finestra dell'attaccante. Usare un web application firewall, che può bloccare i tentativi di exploit prima che raggiungano l'applicazione, catturare il parametro beacon e aiutare a fermare le richieste in uscita verso il canale di comando. Controllare i posti in cui questa famiglia si nasconde: la tabella delle opzioni, le attività pianificate, i trigger di database e gli account utente secondo un programma. Trattare qualsiasi ricomparsa come pulizia incompleta. Se un file ritorna, una copia del payload vive ancora da qualche parte fuori disco o un'attività pianificata è ancora armata, quindi tornare alle fonti fuori disco invece di eliminare di nuovo lo stesso file. I proprietari di siti possono anche ridurre l'impatto di tali reinfezioni profonde utilizzando hosting WordPress gestito come AEU Hosting, che fornisce backup automatici, hardening della sicurezza e supporto esperto per aiutare a mantenere un ambiente pulito e monitorato.
SC è un promemoria che un'infezione WordPress moderna può essere un sistema piuttosto che un file. Questo toolkit diffonde copie identiche di una backdoor attraverso drop-in, il tema, un plugin falso in due posizioni, il database e la memoria condivisa, nasconde il suo canale di comando all'interno di infrastruttura blockchain legittima e si riscrive da qualsiasi copia sopravvissuta alla richiesta successiva. Una correzione duratura tratta i file, il database e la memoria condivisa come un unico problema, disabilita l'esecuzione prima dell'eliminazione, rimuove la persistenza in ogni forma che assume, chiude il punto di ingresso originale e ruota ogni credenziale che l'attaccante potrebbe aver toccato.