SYSADMIN JOURNAL / Linux · Networking · Security · HostingProcedure, appunti e soluzioni tecniche
badiis

BadIIS su Windows IIS: analisi dell’infezione e bonifica offline con WinRE

Pubblicato il 12/11/2026

12 novembre 2026 — Caso reale, procedura di incident response anonimizzata. Un gruppo di frontend Windows Server con Microsoft IIS ha manifestato indicatori compatibili con una compromissione della pipeline HTTP e con le campagne di SEO poisoning associate a BadIIS. Questo resoconto descrive gli artefatti osservati e, soprattutto, come sono stati isolati, conservati e rimossi senza interrompere il servizio. Per riservatezza non vengono pubblicati hostname, indirizzi IP, nomi dei sistemi o domini dell’infrastruttura coinvolta.

1. Il problema: risposte differenti per crawler e utenti

L’anomalia che ha fatto partire l’analisi riguardava contenuti e reindirizzamenti estranei al sito legittimo, inclusi riferimenti a pagine promozionali di giochi d’azzardo in lingua asiatica. Un comportamento particolarmente indicativo era la potenziale differenza tra le risposte ottenute da browser ordinari e quelle con User-Agent di crawler, in particolare Googlebot. Quando un server modifica contenuti o collegamenti soltanto per determinati bot, il problema può passare inosservato ai normali controlli di disponibilità.

BadIIS è una famiglia di malware che agisce a livello IIS, anche tramite moduli e componenti caricati nel processo di gestione delle richieste. Elastic Security Labs ha descritto una campagna in cui la persistenza coinvolge il servizio WalletServiceInfo e i file CbsMsgApi.exe e CbsMsgApi.dll nella directory ProgramData. La presenza di nomi coincidenti è un indicatore significativo, ma non basta da sola per attribuire con certezza ogni campione allo stesso attore o alla stessa variante.

2. Indicatori trovati sui sistemi

Durante la ricognizione abbiamo individuato e trattato le seguenti tracce:

  • Servizi di persistenza: NovaGuard e WalletServiceInfo, registrati nei ControlSet del registro di sistema.
  • Driver sospetto: C:WindowsSystem32driversNovaGuard.sys.
  • Loader e libreria: C:ProgramDataMicrosoftWindowsRingtonesCbsMsgApi.exe e CbsMsgApi.dll.
  • Artefatto da acquisire: C:Windowstamper.auth, copiato per analisi senza eliminare automaticamente l’originale.
  • DLL sospette in C:WindowsTemp: file senza firma digitale, con nomi numerici nel formato ##########.#######.dll. Alcuni hash SHA-256 coincidevano su sistemi differenti, segnale di una distribuzione comune degli artefatti.
  • Altri eseguibili da valutare singolarmente: file temporanei con estensioni inattese e un tool di tunneling trovato su un sistema. Nessuno di questi file deve essere cancellato indiscriminatamente senza verificarne contesto, hash e utilizzo.

È essenziale distinguere gli indicatori osservati dalle ipotesi di funzionamento: il percorso Ringtones e il servizio WalletServiceInfo sono coerenti con un meccanismo già documentato pubblicamente; l’esatto vettore iniziale di accesso non è stato determinato da questa bonifica.

3. Prima di toccare Windows: isolamento controllato dal bilanciatore

La strategia scelta è stata una manutenzione a rotazione. Un frontend alla volta è stato escluso dai gruppi BalancerMember configurati sui reverse proxy Apache. Gli altri frontend sono rimasti attivi per gestire il traffico.

  1. Inventariare tutti i vhost in /etc/apache2/sites-enabled e identificare ogni riferimento al backend da isolare, comprese le configurazioni SSL, i redirect e i pool secondari.
  2. Effettuare un backup di ciascun file Apache interessato e commentare esclusivamente le righe del backend in manutenzione.
  3. Eseguire apachectl -t e, soltanto se restituisce Syntax OK, effettuare un systemctl reload apache2 o il comando equivalente disponibile.
  4. Controllare attraverso tutti i proxy le risposte HTTP dei siti principali, delle sottosezioni e dei domini di redirect; verificare che non rimangano membri attivi diretti al backend escluso.
  5. Salvare le impostazioni originali dei servizi IIS, quindi fermare e disabilitare W3SVC e WAS prima del riavvio, così il server non riparte con IIS attivo durante gli aggiornamenti.

Questa fase non è facoltativa su un cluster di produzione: le operazioni successive prevedono un ambiente di ripristino e interruzioni del servizio sul nodo oggetto della bonifica.

4. Perché abbiamo usato Windows Recovery Environment

Provare a cancellare un driver o una ServiceDLL durante il normale funzionamento di Windows può fallire perché il file è caricato, bloccato oppure protetto da una persistenza attiva. Per questo abbiamo avviato il sistema in WinRE, dove l’installazione Windows rimane offline. Da qui è possibile acquisire il file SYSTEM, aprirne la hive con reg load, disabilitare i servizi sospetti nei ControlSet esistenti e spostare in quarantena i binari conosciuti.

In Windows, prima del riavvio, sono stati controllati i servizi IIS e il supporto WinRE:

sc.exe config W3SVC start= disabled
sc.exe stop W3SVC
sc.exe config WAS start= disabled
sc.exe stop WAS
reagentc.exe /info
reagentc.exe /boottore
shutdown.exe /r /t 10 /f

Attenzione: questi comandi richiedono privilegi amministrativi, escludono temporaneamente il servizio web e vanno impiegati soltanto dopo avere messo in sicurezza la continuità applicativa. Il comando reagentc /boottore programma WinRE per il successivo avvio: il batch non viene eseguito automaticamente.

5. Il batch di bonifica da eseguire in WinRE

Il seguente batch è una versione anonimizzata e generalizzata della procedura utilizzata. È costruito per intervenire soltanto sui nomi di servizi e sui percorsi indicati, e si interrompe se non riesce a identificare univocamente il volume Windows/IIS. Conserva le prove nella directory IIS-RECOVERY-EVIDENCE del volume offline, senza cancellare file generici di Windows. Prima dell’utilizzo va esaminato e adattato al proprio incidente.

Salvare il testo in un file denominato IIS-RECOVERY-REMEDIATE.cmd sul volume di Windows, prima del riavvio. Nel prompt di WinRE, verificare prima dove è montato il volume:

diskpart
list volume
exit

Se il file si trova, per esempio, sul volume D:, avviarlo così:

D:IIS-RECOVERY-REMEDIATE.cmd

Non utilizzare il batch su un sistema sano: il file modifica il registro offline e sposta componenti specifici. È consigliabile avere anche uno snapshot o un backup ripristinabile. La copia e il confronto delle dimensioni verificano soltanto una condizione minima: non costituiscono una verifica crittografica dell’identità dei file.

@echo off
setlocal EnableExtensions EnableDelayedExpansion
echo === BONIFICA OFFLINE IIS - WINRE ===
if /I not "%SystemDrive%"=="X:" (
 echo STOP: eseguire ESCLUSIVAMENTE in Windows Recovery Environment.
 exit /b 2
)
set "VOL="
set "COUNT=0"
for %%D in (C D E F G H I J K L M N O P Q R S T U V W Y Z) do (
 if exist "%%D:WindowsSystem32configSYSTEM" if exist "%%D:WindowsSystem32inetsrvconfigapplicationHost.config" (
  set /a COUNT+=1
  set "VOL=%%D:"
 )
)
if not "!COUNT!"=="1" (
 echo STOP: attesi 1 disco Windows IIS, trovati !COUNT!
 exit /b 3
)
set "BK=!VOL!IIS-RECOVERY-EVIDENCEIR-%RANDOM%-%RANDOM%"
md "!BK!" >nul 2>&1
if not exist "!BK!" (echo STOP: impossibile salvare evidenze & exit /b 4)
set "LOG=!BK!remediation.log"
echo DATE=%DATE% TIME=%TIME% OS=!VOL! > "!LOG!"
echo EVIDENCE=!BK! >> "!LOG!"
echo [1/5] BACKUP hive SYSTEM e applicationHost.config
copy /b /y "!VOL!WindowsSystem32configSYSTEM" "!BK!SYSTEM.before" >> "!LOG!" 2>&1
if errorlevel 1 (echo STOP: backup SYSTEM fallito & exit /b 5)
for %%A in ("!VOL!WindowsSystem32configSYSTEM") do set "ORIG_SIZE=%%~zA"
for %%A in ("!BK!SYSTEM.before") do set "COPY_SIZE=%%~zA"
if not defined COPY_SIZE (echo STOP: copia SYSTEM assente & exit /b 6)
if "!COPY_SIZE!"=="0" (echo STOP: copia SYSTEM vuota & exit /b 6)
if not "!ORIG_SIZE!"=="!COPY_SIZE!" (echo STOP: dimensioni SYSTEM differenti & exit /b 6)
echo SYSTEM size verified: !COPY_SIZE! >> "!LOG!"
copy /b /y "!VOL!WindowsSystem32inetsrvconfigapplicationHost.config" "!BK!applicationHost.config.before" >> "!LOG!" 2>&1
if errorlevel 1 (echo STOP: backup IIS fallito & exit /b 7)
echo [2/5] DISABILITA persistenze confermate (NovaGuard e WalletServiceInfo)
set "HIVE=HKLMTC_RECOVERY_SECURITY"
reg load "!HIVE!" "!VOL!WindowsSystem32configSYSTEM" >> "!LOG!" 2>&1
if errorlevel 1 (echo STOP: caricamento hive fallito & exit /b 8)
set "FAILED=0"
for %%N in (001 002 003 004 005 006 007 008 009 010) do (
 for %%S in (NovaGuard WalletServiceInfo) do (
  reg query "!HIVE!ControlSet%%NServices%%S" >nul 2>&1
  if not errorlevel 1 (
   reg export "!HIVE!ControlSet%%NServices%%S" "!BK!%%S-CS%%N.reg" /y >> "!LOG!" 2>&1
   if errorlevel 1 (
    set /a FAILED+=1
   ) else (
    reg add "!HIVE!ControlSet%%NServices%%S" /v Start /t REG_DWORD /d 4 /f >> "!LOG!" 2>&1
    if errorlevel 1 (set /a FAILED+=1) else (echo DISABLED %%S ControlSet%%N >> "!LOG!")
   )
  )
 )
)
reg unload "!HIVE!" >> "!LOG!" 2>&1
if errorlevel 1 (echo STOP: unload hive fallito, non sposto file & exit /b 9)
if not "!FAILED!"=="0" (echo STOP: disabilitazione incompleta: !FAILED! errori & exit /b 10)
echo [3/5] QUARANTENA driver NovaGuard.sys
set "DRIVER=!VOL!WindowsSystem32driversNovaGuard.sys"
if exist "!DRIVER!" (
 copy /b /y "!DRIVER!" "!BK!NovaGuard.sys.evidence" >> "!LOG!" 2>&1
 if errorlevel 1 (echo STOP: backup NovaGuard fallito & exit /b 11)
 for %%A in ("!DRIVER!") do set "ORIG_SIZE=%%~zA"
 for %%A in ("!BK!NovaGuard.sys.evidence") do set "COPY_SIZE=%%~zA"
 if not defined COPY_SIZE (echo STOP: copia NovaGuard assente & exit /b 12)
 if "!COPY_SIZE!"=="0" (echo STOP: copia NovaGuard vuota & exit /b 12)
 if not "!ORIG_SIZE!"=="!COPY_SIZE!" (echo STOP: dimensioni NovaGuard differenti & exit /b 12)
 echo NovaGuard size verified: !COPY_SIZE! >> "!LOG!"
 move /y "!DRIVER!" "!BK!NovaGuard.sys.quarantined" >> "!LOG!" 2>&1
 if errorlevel 1 (echo STOP: isolamento NovaGuard fallito & exit /b 13)
) else (
 echo NovaGuard.sys not present >> "!LOG!"
)
echo [4/5] QUARANTENA directory Ringtones se presenta artefatti del malware
set "RING=!VOL!ProgramDataMicrosoftWindowsRingtones"
if exist "!RING!CbsMsgApi.dll" (
 move "!RING!" "!BK!Ringtones.quarantined" >> "!LOG!" 2>&1
 if errorlevel 1 (echo WARNING: Ringtones non isolata >> "!LOG!")
) else (
 if exist "!RING!CbsMsgApi.exe" (
  move "!RING!" "!BK!Ringtones.quarantined" >> "!LOG!" 2>&1
  if errorlevel 1 (echo WARNING: Ringtones non isolata >> "!LOG!")
 ) else (
  echo No known Ringtones malware components found >> "!LOG!"
 )
)
echo [5/5] QUARANTENA TEMP DLL identificate nell'indagine, solo se presenti
for %%F in (1593525016.067717.dll 1734111945.0605412.dll 1678500782.4131799.dll 1696682910.7105846.dll) do (
 if exist "!VOL!WindowsTemp%%F" (
  copy /b /y "!VOL!WindowsTemp%%F" "!BK!%%F.evidence" >> "!LOG!" 2>&1
  if not errorlevel 1 (
   move /y "!VOL!WindowsTemp%%F" "!BK!%%F.quarantined" >> "!LOG!" 2>&1
  ) else (
   echo WARNING: backup fallito per %%F >> "!LOG!"
  )
 )
)
if exist "!VOL!Windowstamper.auth" (
 copy /b /y "!VOL!Windowstamper.auth" "!BK!tamper.auth.evidence" >> "!LOG!" 2>&1
 echo tamper.auth copied for review; NOT REMOVED >> "!LOG!"
)
echo FINISHED %DATE% %TIME% >> "!LOG!"
echo.
echo === FINITO: VERIFICARE !LOG! ===
echo Le azioni mirano solo a persistenze/file noti. Non certificano la rimozione di ogni malware.
echo NON reinserire il nodo nel pool senza scansione AV offline, controllo IIS e verifica.
exit /b 0

Come funziona il batch

  1. Controllo di sicurezza: richiede di essere eseguito da WinRE, con drive di sistema X:, e cerca una sola installazione Windows con configurazione IIS.
  2. Acquisizione evidenze: crea una cartella univoca di quarantena, copia la hive SYSTEM e la configurazione applicationHost.config e apre un log.
  3. Disabilitazione della persistenza: carica la hive offline, esamina i ControlSet da 001 a 010, esporta le chiavi dei servizi presenti e imposta Start=4 soltanto per NovaGuard e WalletServiceInfo. Infine scarica la hive.
  4. Quarantena del driver: copia NovaGuard.sys, verifica la dimensione e sposta l’originale nella cartella delle prove.
  5. Quarantena del loader: sposta la directory Ringtones solo se contiene CbsMsgApi.dll o CbsMsgApi.exe.
  6. File aggiuntivi: controlla esclusivamente un elenco esplicito di DLL temporanee e copia tamper.auth senza rimuoverlo.

Non abbiamo usato fc /b nel batch definitivo: in quell’ambiente di recupero il comando non era disponibile. Il controllo delle copie è quindi implementato con comandi nativi di cmd.exe e confronti di dimensione; una volta rientrati in Windows gli hash SHA-256 possono essere verificati con PowerShell.

6. Riavvio e quarantena mirata di Windows Temp

Dopo aver controllato remediation.log e gli esiti di reg unload, da WinRE si può riavviare con:

wpeutil reboot

Il server resta ancora escluso dai bilanciatori. Una volta rientrati in Windows, abbiamo verificato il mancato ritorno dei file e dei servizi sospetti, quindi esaminato C:WindowsTemp alla ricerca delle DLL numeriche senza firma digitale. La procedura prudente applicata a ogni file è stata: controllo della firma, calcolo SHA-256, verifica dei moduli in uso nei processi accessibili, copia in una directory di quarantena con manifest.csv, verifica che la copia abbia lo stesso SHA-256 e solo allora eliminazione dell’originale.

Comandi utili di sola ricognizione da PowerShell amministrativo:

Get-ChildItem 'C:WindowsTemp' -File -Force |
  Where-Object { $_.Name -match '^d{9,12}.d+.dll$' } |
  Select-Object Name,Length,LastWriteTime,FullName

Get-FileHash -Algorithm SHA256 -LiteralPath 'C:WindowsTempNOME_FILE.dll'
Get-AuthenticodeSignature -LiteralPath 'C:WindowsTempNOME_FILE.dll'

Get-CimInstance Win32_Service |
  Where-Object { $_.Name -in @('NovaGuard','WalletServiceInfo') } |
  Select-Object Name,State,StartMode

Non è consigliabile eseguire una cancellazione globale di WindowsTemp: nella cartella convivono log, file temporanei legittimi e possibili prove forensi. Anche gli eseguibili rinominati con estensioni non convenzionali richiedono verifica manuale o automatica basata su firme e intestazioni.

7. Antivirus, Windows Update e riavvio controllato di IIS

Su ciascun nodo trattato è stata eseguita la scansione con Microsoft Safety Scanner (MSERT), consultando il log C:Windowsdebugmsert.log. In alcuni casi la scansione non ha rilevato nuove infezioni dopo la bonifica offline; in altri ha individuato ulteriori artefatti o strumenti non desiderati. Questo non prova, di per sé, che il sistema sia completamente affidabile.

Abbiamo poi installato gli aggiornamenti Windows disponibili, controllato gli indicatori di riavvio pendente, e ripristinato i tipi di avvio originali di IIS: WAS manuale e W3SVC automatico. Dopo il riavvio di un vecchio frontend IIS è stato necessario attendere il warm-up delle applicazioni: inizialmente alcune richieste rimanevano nello stadio ExecuteRequestHandler del modulo AspNetCoreModuleV2 e superavano i timeout del test. Non abbiamo interpretato automaticamente l’avvio lento come una nuova compromissione.

Solo quando sono scomparsi i timeout e le richieste bloccate abbiamo verificato ripetutamente i codici HTTP attesi (200 per le pagine pubbliche, 301/302 per i redirect e 403 sugli endpoint che rifiutano normalmente l’accesso anonimo), con confronto tra User-Agent ordinario e Googlebot.

8. Ritorno in servizio e rimozione dei workaround temporanei

Il ritorno in produzione è avvenuto per gradi, reinserendo i BalancerMember precedentemente commentati, verificando apachectl -t, ricaricando Apache senza interrompere i frontend sani e controllando i tempi di risposta dal lato proxy.

Durante l’emergenza era stata introdotta una regola temporanea RequestHeader set User-Agent che trasformava le richieste di Googlebot in quelle di un normale browser Chrome. Era una mitigazione diagnostica, non una soluzione: una volta completata la bonifica, l’abbiamo rimossa da tutti i vhost interessati per ripristinare il comportamento naturale verso i crawler.

L’audit dei file Apache ha anche identificato una pagina /balancer-manager accessibile senza credenziali a causa di una direttiva permissiva. È stata corretta mantenendo l’autenticazione Basic: la verifica anonima è passata da HTTP 200 a HTTP 401. Infine sono state allineate, dopo backup, le copie dei vhost in sites-available e sites-enabled, eliminando le sole divergenze lasciate dai commenti di manutenzione.

9. Cosa è stato verificato e cosa resta da fare

  • Verificato: assenza dei componenti identificati nei percorsi originali, servizi sospetti disabilitati, quarantena delle DLL numeriche, scansioni MSERT, IIS avviato, bilanciatori funzionanti e risposte HTTP regolari.
  • Non dimostrato: assenza di ogni possibile backdoor, vettore iniziale di accesso, eventuale esfiltrazione o attribuzione definitiva a una singola campagna.
  • Passi raccomandati: revisione dei moduli IIS e di applicationHost.config, controllo degli account locali e delle membership amministrative, attività pianificate, autorun, webshell e log; rotazione delle credenziali potenzialmente esposte; confronto con backup integri e valutazione di reinstallazione/ripristino completo dei nodi, specialmente perché Windows Server 2012 R2 è un sistema legacy.

Conclusione. Il punto chiave è stato separare la bonifica offline dal ripristino applicativo: prima le prove e le persistenze, poi gli aggiornamenti e la scansione, infine il collaudo IIS a caldo e il ritorno progressivo nel bilanciatore. La disponibilità del sito è stata preservata, ma un incidente di questo tipo merita comunque un’indagine forense successiva e, dove possibile, la migrazione verso sistemi supportati.

Approfondimenti

Riferimento tecnico: Elastic Security Labs, “BADIIS to the Bone: New Insights to a Global SEO Poisoning Campaign” (11 febbraio 2026). Il report descrive il ruolo di WalletServiceInfo, CbsMsgApi.dll, dei moduli IIS e delle tecniche di SEO poisoning. I dettagli operativi dell’intervento descritti sopra sono invece derivati dai controlli eseguiti durante questo caso.

Approfondimenti correlati