Il contesto
Un piccolo negozio online di articoli per la casa, con qualche centinaio di prodotti su WooCommerce e un buon volume di ordini nei fine settimana. Anni prima un fornitore, abituato a lavorare con ambienti Microsoft, aveva installato tutto su un server virtuale Windows: IIS come server web, PHP tramite FastCGI, MySQL e WordPress nella cartella del sito. Per gestirlo da remoto aveva lasciato aperto il Desktop remoto (RDP) verso Internet, con un account amministratore dalla password corta. Poi il rapporto si era interrotto, e da allora nessuno aveva più aggiornato né il sistema né i plugin. Per riservatezza, nome del negozio, prodotti e dettagli che permetterebbero di identificarlo sono stati omessi o modificati.
I sintomi
A inizio agosto la banca che gestiva i pagamenti aveva segnalato al negozio alcune frodi su carte usate di recente sul sito. Nello stesso periodo il server era diventato lentissimo: il pannello del fornitore mostrava la CPU costantemente al massimo, anche di notte, quando il sito non aveva visite. Il titolare aveva provato a eseguire una scansione con l’antivirus di Windows, che non aveva trovato nulla. Ci ha contattato scegliendo il servizio con intervento entro 12 ore.
Cosa abbiamo trovato a livello applicativo
Le frodi avevano una spiegazione precisa: uno skimmer nella pagina di pagamento, del tipo descritto nell’articolo sugli skimmer nel checkout di WooCommerce. Uno script offuscato, caricato solo nel checkout, copiava i dati inseriti nel modulo della carta e li inviava a un dominio che imitava quello di una libreria JavaScript. Era aggiunto al sito da poche righe infilate in un file del plugin di pagamento.
Non era l’unica presenza. Negli upload c’erano tre file PHP con estensioni doppie e un contenuto codificato più volte, come quelli descritti nell’articolo sui file offuscati, e altre due backdoor erano nascoste in plugin disattivati, che nessuno controllava perché «tanto sono spenti». I log di IIS riconducevano il primo caricamento a un plugin per l’importazione dei prodotti, fermo da due anni, con una vulnerabilità nota di caricamento di file. Avrebbe dovuto trovare un ostacolo nei permessi: e invece il vecchio fornitore, per risolvere un problema con il caricamento delle immagini, aveva dato al pool applicativo di IIS il controllo completo sull’intera cartella del sito. Con quei permessi, una webshell negli upload poteva modificare qualunque file di WordPress.
Cosa abbiamo trovato a livello di sistema
Il carico sulla CPU non veniva dal sito. Il registro di sicurezza di Windows era pieno di accessi falliti via RDP (evento 4625) da decine di indirizzi diversi e, tra questi, alcuni accessi riusciti di tipo RemoteInteractive (evento 4624, tipo 10) con l’account amministratore, da indirizzi esteri, in orari in cui nessuno del negozio era al computer. La password era stata indovinata per forza bruta. Chi era entrato aveva i pieni poteri sul sistema, e li aveva usati:
- un nuovo utente locale, con un nome da account di servizio, aggiunto al gruppo degli amministratori;
- un servizio di Windows con avvio automatico e una descrizione copiata da un componente di sistema, che lanciava un miner di criptovaluta nascosto in
C:\ProgramData; - due attività pianificate che ogni ora controllavano che il miner fosse attivo e, in caso contrario, lo riscaricavano con PowerShell;
- un valore in una delle chiavi di registro Run, che avviava all’accesso un programma per il controllo remoto;
- soprattutto, alcune esclusioni aggiunte a Microsoft Defender per le cartelle del miner e dello strumento remoto. È il motivo per cui la scansione del titolare non trovava nulla: le esclusioni dicono all’antivirus di non guardare proprio lì, e si aggiungono con un solo comando,
Add-MpPreference, a chiunque sia amministratore.
# PowerShell da amministratore: esclusioni configurate in Defender
Get-MpPreference | Select-Object -ExpandProperty ExclusionPath
Get-MpPreference | Select-Object -ExpandProperty ExclusionProcess
# Attività pianificate non di Microsoft, con il comando che eseguono
Get-ScheduledTask | Where-Object TaskPath -notlike '\Microsoft\*' |
Select-Object TaskName, TaskPath, @{n='Azione';e={$_.Actions.Execute + ' ' + $_.Actions.Arguments}}
# Servizi con avvio automatico e percorso dell'eseguibile
Get-CimInstance Win32_Service | Where-Object StartMode -eq 'Auto' |
Select-Object Name, DisplayName, PathName
# Programmi avviati dalle chiavi Run e membri del gruppo Administrators
Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Run'
Get-LocalGroupMember -Group 'Administrators'
Le date raccontavano due storie parallele. Gli accessi via RDP erano cominciati a maggio, lo sfruttamento del plugin a giugno: con buona probabilità due attaccanti diversi, uno interessato alla potenza di calcolo del server, l’altro alle carte dei clienti, che si erano trovati per caso nella stessa casa lasciata aperta. Ricostruire tutto non è stato semplice. Il registro di sicurezza, lasciato alla dimensione predefinita e riempito dai tentativi di accesso, copriva solo gli ultimi giorni: la data del primo ingresso l’abbiamo ricavata dal registro di sistema, che conservava l’installazione del servizio malevolo (evento 7045), e dalle date di creazione dei file. E sul server mancavano gli strumenti che su Linux diamo per scontati. Abbiamo lavorato su una copia dei log e dei file, con l’aiuto di modelli di intelligenza artificiale open-weight eseguiti in locale per ordinare e correlare decine di migliaia di righe.
Come l’abbiamo rimosso
La prima cosa è stata fermare lo skimmer: il checkout è stato messo in manutenzione e il negozio ha avvisato la banca, come previsto quando i dati delle carte possono essere stati sottratti. Poi abbiamo chiuso la porta RDP a livello del firewall del fornitore, lasciandola raggiungibile solo dal nostro indirizzo, e salvato le prove: log di IIS, registri eventi esportati, attività pianificate, servizi, chiavi di registro, gli eseguibili malevoli e i file PHP sospetti.
Sul sistema operativo non c’era una scelta ragionevole diversa dalla ricostruzione. Un attaccante che è stato amministratore di Windows per tre mesi può aver lasciato persistenze ovunque: in WMI, nei driver, in altri account, in configurazioni di Defender che non abbiamo visto. Pulire quel server e dichiararlo affidabile non sarebbe stato onesto. Abbiamo quindi separato, come sempre, due attività:
- la bonifica di WordPress, coperta dal servizio entro 12 ore: core ricostruito dai pacchetti ufficiali, WooCommerce e gli altri plugin reinstallati dal repository ufficiale, plugin disattivati eliminati, plugin vulnerabile sostituito, tema confrontato con l’originale, upload ripuliti da ogni file eseguibile, database controllato in utenti, opzioni e contenuti. Il risultato è stato verificato su un nuovo server Linux, in un indirizzo di prova;
- la migrazione da Windows a Linux, concordata con il titolare come attività separata e fuori dalla garanzia: un nuovo server con una distribuzione Debian stabile e uno stack LEMP (Nginx, MariaDB, PHP-FPM), le regole di riscrittura del
web.configdi IIS tradotte nella configurazione di Nginx, il cambio dei DNS.
La migrazione ha avuto una sorpresa tipica: il file system di Windows non distingue maiuscole e minuscole, quello di Linux sì. Una quarantina di immagini, richiamate nel database con un nome scritto in modo leggermente diverso dal file, sul nuovo server risultavano mancanti. Le abbiamo individuate confrontando i riferimenti nel database con i file presenti e corrette prima del cambio dei DNS.
Infine le credenziali: password degli amministratori e dei clienti con ruolo di gestione, chiavi e salt di WordPress, password del database, chiavi API del servizio di pagamento, accessi al pannello del fornitore. Il vecchio server è stato spento e conservato come prova per trenta giorni, poi eliminato.
Perché WordPress su Linux
Va detto con onestà: WordPress su Windows funziona. Il core contiene perfino una funzione, iis7_supports_permalinks(), che verifica se IIS può gestire gli indirizzi «parlanti», e WP-CLI ha istruzioni di installazione anche per Windows. Il problema non è la compatibilità, ma tutto ciò che sta intorno:
- l’ecosistema: la gran parte delle installazioni di WordPress gira su server Linux, e documentazione, guide, plugin di sicurezza e strumenti di analisi sono pensati e provati lì. Su Windows, molte istruzioni vanno tradotte, e alcune non hanno un equivalente diretto;
- i permessi: il modello di Linux, con proprietario, gruppo e utente dedicato per PHP-FPM, è semplice da impostare e da verificare. Le ACL di NTFS sono potenti, ma ereditate e stratificate, e nella pratica finiscono spesso come in questo caso, con un «controllo completo» concesso per risolvere un problema e mai più tolto;
- l’amministrazione remota: un server Linux si gestisce con SSH e chiavi, che si possono limitare facilmente. Su Windows la strada più comoda è il Desktop remoto, e la stessa documentazione di Microsoft avverte che aprirlo verso Internet non è raccomandato e che è preferibile una VPN;
- le competenze: chi fa hosting di WordPress, noi compresi, lavora su Linux da anni. Un server Windows con IIS e PHP è una configurazione rara, e ciò che è raro è più facile da configurare male e più difficile da far controllare a qualcuno che lo conosca bene.
L’hardening
Sul nuovo server PHP-FPM gira con un utente dedicato che può scrivere solo negli upload e nella cache, e negli upload l’esecuzione di PHP è bloccata, come spiegato nell’articolo sulle webshell negli upload. SSH accetta solo chiavi e solo dagli indirizzi autorizzati, non esiste nessun accesso amministrativo esposto a tutta Internet e gli aggiornamenti di sicurezza del sistema si installano da soli. WordPress, WooCommerce e i plugin si aggiornano con una procedura concordata con il titolare, preceduta da un backup. È attivo il monitoraggio dell’integrità dei file, con un controllo dedicato ai file del checkout, e una Content Security Policy limita i domini da cui la pagina di pagamento può caricare script e verso cui può inviare dati.
Il risultato
WordPress ripulito era pronto e verificato entro le 12 ore previste dal servizio. La migrazione su Linux, con i test degli ordini e dei pagamenti in modalità di prova, si è chiusa in due giorni, e il checkout è tornato attivo solo dopo il via libera della banca. Nelle settimane successive non sono state segnalate nuove frodi, la CPU del nuovo server segue l’andamento delle visite e il monitoraggio non ha registrato modifiche non autorizzate. Il titolare ha ricevuto un rapporto con le due cronologie, gli indicatori di compromissione e gli elementi per valutare, con il proprio consulente, gli adempimenti verso i clienti coinvolti.
Cosa insegna questo caso
Quando un’infezione tocca il sistema operativo, pulire WordPress non basta, e questo vale per Linux quanto per Windows. Ma la scelta della piattaforma pesa su tutto il resto: su quanto è facile impostare bene i permessi, su quanti strumenti e quante persone sanno analizzare il sistema, su quanto è naturale evitare di esporre un accesso amministrativo a tutta Internet. Un Desktop remoto aperto con una password debole è una porta che prima o poi qualcuno prova, e in questo caso l’hanno provata in due.
Rimozionemalware.com è il servizio di bonifica dei siti WordPress di Managed Server S.r.l., che gestisce server e hosting dal 2005. Interveniamo sull’applicazione e sul sistema, con tempi garantiti di 6, 12 o 24 ore per ogni installazione di WordPress, calcolati dalla ricezione degli accessi; attività come la migrazione di un server vengono proposte e concordate a parte. Per un sito che gira su un server Windows, o su qualunque server di cui non sei più sicuro, puoi contattarci.