Le profondità della virtualizzazione Windows (parte 2) — Memoria che nemmeno il kernel può vedere: come funzionano VBS, HVCI e Credential Guard
· Go Komura · Windows, Virtualizzazione, Sicurezza, VBS, HVCI, Credential Guard
C’è stato un tempo in cui i privilegi di amministratore erano l’«obiettivo» per un attaccante su Windows. Caricare un driver kernel come amministratore, fare il dump della memoria del processo LSASS, e si hanno hash delle password e ticket Kerberos. Da lì è solo questione di camminare verso un’altra macchina con gli hash rubati.
Sul Windows 11 attuale con Credential Guard in esecuzione — lo stato predefinito da 22H2 in poi sui dispositivi che soddisfano i requisiti di licenza come Enterprise ed Education, più i requisiti hardware — quel playbook non funziona. Un attaccante che ha preso per intero il kernel può cercare nella memoria quanto vuole, e gli hash effettivi delle credenziali di dominio protette non si trovano «dentro quel sistema operativo». Se non è in esecuzione, il vecchio pericolo resta, quindi leggere questo insieme ai metodi di conferma più avanti nell’articolo.
Allora dove sono? La risposta è «un altro mondo, creato nello stesso PC». Come abbiamo visto nella parte 1, il Windows host gira nella partizione root sopra l’hypervisor («Dove gira davvero il vostro Windows?»). Questo articolo continua da lì e segue un’altra linea di confine che l’hypervisor traccia dentro la stessa partizione.
La domanda a cui risponde la parte 2 è una sola.
Dove mette Windows i segreti che né un amministratore né il kernel possono leggere?
I destinatari sono sviluppatori e operatori che hanno visto parole come Isolamento del core, Integrità della memoria e Credential Guard su una schermata di impostazioni o in un caso di risoluzione dei problemi, e vogliono capire la cosa reale dal meccanismo in su. I prerequisiti sono Windows 10/11 x64 o un Windows Server attuale (come nella parte 1, la discussione di ring e SLAT presuppone x64; Arm64 usa un meccanismo diverso come i livelli di eccezione). Lo sfondo richiesto sono i concetti di partizioni e SLAT trattati nella parte 1. La difficoltà è intermedia. L’obiettivo è una spiegazione della struttura, non un how-to per configurare le funzioni di sicurezza.
1. Prima di tutto, la conclusione
Windows ha aggiunto un asse di privilegio chiamato VTL (Virtual Trust Level) e ha messo i segreti in VTL1. La memoria in VTL1 non si può leggere dal kernel ordinario che gira in VTL0. Ciò che custodisce il confine non è il kernel stesso, ma l’hypervisor che detiene le tabelle di traduzione SLAT.
Quello è lo scheletro della sicurezza basata sulla virtualizzazione (VBS). VBS usa l’hypervisor per creare un ambiente isolato e vi ospita le funzioni di sicurezza. È progettata nell’ipotesi che l’ambiente isolato resti protetto anche se il kernel è compromesso.1
flowchart TB
accTitle: I due mondi che VBS crea
accDescr: VTL0 e VTL1 stanno dentro la stessa partizione; VTL0 detiene il kernel ordinario e le app, VTL1 detiene il Secure Kernel e le funzioni di sicurezza isolate, e l'hypervisor custodisce il confine
subgraph vtl0 ["VTL0(il mondo ordinario)"]
apps["App(ring 3)"]
ntk["Kernel NT e driver(ring 0)"]
end
subgraph vtl1 ["VTL1(il mondo isolato)"]
ium["Funzioni di sicurezza isolate"]
sk["Secure Kernel"]
end
hv["Hypervisor(impone il confine via SLAT)"] --- vtl0
hv --- vtl1
ntk -.->|Non può leggere| ium
Figura 1: Ci sono due mondi dentro un solo Windows, e il kernel VTL0 non può accedere alla memoria VTL1.
Il punto importante è che questo non è «alzare un’altra VM». VTL0 e VTL1 sono dentro la stessa partizione, dentro lo stesso Windows. Vedremo a turno come si realizza questa scissione.
2. I limiti del modello a ring — Il guardiano e il custodito stanno alla stessa altezza
La sicurezza tradizionale di Windows era costruita sulla scala dei ring (livelli di privilegio). La modalità utente (ring 3) è custodita dalla modalità kernel (ring 0). Allora chi custodisce ring 0 — nessuno può. Ring 0 è il privilegio più alto.
Questa struttura ha due debolezze strutturali.
- Il kernel non è un monolite. A ring 0, non solo Windows stesso ma un gran numero di driver di terze parti girano. Se uno qualsiasi di essi ha una vulnerabilità, un attaccante ottiene l’esecuzione di codice a ring 0.
- Da ring 0, tutto è visibile. Per quanto un processo in modalità utente come LSASS si difenda, la sua memoria è libera da leggere per un attaccante che ha preso il kernel. Attributi di protezione e page table sono gestiti dal kernel stesso.
flowchart TB
accTitle: Il percorso di furto delle credenziali nel modello a ring tradizionale
accDescr: Un attaccante che prende ring 0 attraverso un driver vulnerabile può leggere la memoria del processo LSASS con la piena autorità del kernel e ottenere gli hash delle password
mal["Codice dell'attaccante"] -->|Sfrutta un driver vulnerabile| r0["Prende il controllo di ring 0"]
r0 --> readall["Può leggere tutta la memoria fisica"]
readall --> lsass["Ottiene gli hash dalla memoria di LSASS"]
lsass --> lateral["Abusati per il movimento laterale verso altre macchine"]
Figura 2: Poiché il guardiano (il kernel) e il custodito (i segreti) stanno alla stessa altezza, la debolezza fondamentale è che se cade ring 0, cade tutto.
Ciò che serve, allora, è «un posto più alto di ring 0». Quel posto è già comparso nella parte 1. L’hypervisor gira a un privilegio più alto del kernel e monopolizza presto il controllo dei permessi di accesso alla memoria della CPU (SLAT). Una regione isolata che l’hypervisor custodisce è protetta anche contro l’accesso dal software del sistema operativo a ring 0 (modalità supervisor).2
3. VSM e VTL — Aggiungere un altro asse di privilegio
3.1. Virtual Trust Level (VTL)
La famiglia di funzioni dell’hypervisor che fornisce questo isolamento si chiama VSM (Virtual Secure Mode). VSM è il fondamento per Device Guard, Credential Guard, un TPM virtuale e simili.2
Il concetto centrale di VSM è il VTL (Virtual Trust Level). I punti chiave sono i seguenti.2
- I VTL sono gerarchici, e più alto è il numero, più alto è il privilegio. VTL0 è il più basso; VTL1 è più privilegiato di VTL0.
- Architetturalmente sono definiti fino a 16 livelli, ma ciò che è attualmente implementato sono due: VTL0 e VTL1.
- Ogni VTL ha protezioni di accesso alla memoria indipendenti. Queste protezioni sono gestite dall’hypervisor rispetto allo spazio di indirizzi fisici della partizione, quindi il software di sistema dentro la partizione non può cambiarle.
- Un processore virtuale ha uno stato dei registri e un apparato di interruzioni separati per VTL, e un VTL inferiore non può spiare lo stato di un VTL superiore.
flowchart TB
accTitle: Tre indipendenze che compongono l'isolamento VTL
accDescr: Protezioni di accesso alla memoria, stato dei registri del processore virtuale e apparato di interruzioni sono indipendenti per VTL, e un VTL inferiore non può toccare nessuno di essi in un VTL superiore
vtl["Cosa è indipendente per VTL"] --> m1["Protezioni di accesso alla memoria"]
vtl --> m2["Stato dei registri del VP"]
vtl --> m3["Apparato di interruzioni"]
m1 -.-> rule["Un VTL inferiore non tocca un VTL superiore"]
m2 -.-> rule
m3 -.-> rule
Figura 3: Fare non solo della memoria ma anche dello stato della CPU e delle interruzioni un mondo separato è il tris che non lascia spioncino.
Se i ring (0 e 3) sono l’asse che separa «sistema operativo e app», i VTL sono un secondo asse che separa «il mondo ordinario e il mondo isolato». I due assi sono ortogonali, e dentro VTL1 ci sono modalità kernel e modalità utente anche lì.
flowchart TB
accTitle: Quattro regioni create dai due assi di ring e VTL
accDescr: L'asse dei ring separa modalità kernel e modalità utente, l'asse VTL separa il mondo ordinario e il mondo isolato, e la combinazione produce quattro regioni: app ordinarie, kernel NT, trustlet IUM e Secure Kernel
subgraph ax0 ["VTL0(mondo ordinario)"]
a0["Ring 3: app ordinarie"]
k0["Ring 0: kernel NT e driver"]
end
subgraph ax1 ["VTL1(mondo isolato)"]
a1["Ring 3: IUM(trustlet)"]
k1["Ring 0: Secure Kernel"]
end
a0 --- k0
a1 --- k1
k0 ~~~ a1
Figura 4: Ora ci sono due assi di privilegio, e «è il kernel?» e «è il mondo isolato?» sono diventate domande distinte.
3.2. La sostanza del confine è SLAT
Nella parte 1 abbiamo detto che le tabelle di traduzione di secondo livello che mappano un indirizzo fisico guest (GPA) sulla RAM reale (SPA) — SLAT — sono detenute dall’hypervisor. VSM usa esattamente questa proprietà. L’isolamento VTL è creato usando l’hypervisor Hyper-V e SLAT.3
Quando VTL1 dichiara «questa memoria non va mostrata a VTL0», l’hypervisor toglie il permesso di accesso a quella pagina dalle tabelle di traduzione di VTL0. Da allora in poi, anche se il kernel VTL0 prova a toccare quell’indirizzo, viene negato nella fase di traduzione degli indirizzi della CPU. È inutile che il kernel riscriva le proprie page table come vuole. Le page table (GVA→GPA) possono appartenere al kernel, ma la traduzione oltre quello (GPA→SPA) e il permesso di accesso finale appartengono all’hypervisor.
flowchart TB
accTitle: Il flusso con cui l'accesso da VTL0 alla memoria VTL1 viene negato
accDescr: Quando il kernel VTL0 prova a leggere la memoria VTL1, può passare la propria page table ma viene negato dalla protezione di accesso SLAT, e il controllo passa all'hypervisor
try["Il kernel VTL0 prova a leggere una pagina VTL1"] --> pt["Passa la page table del kernel"]
pt --> slat{"La protezione SLAT lo consente?"}
slat -->|Non consentito| deny["L'hypervisor interviene e nega l'accesso"]
slat -->|Consentito| ok["Accesso ordinario alla memoria"]
deny -.-> point["Protetto a uno strato che il kernel non può cambiare"]
Figura 5: La barriera sta fuori dal kernel, e le protezioni SLAT non possono essere cambiate dal software dentro la partizione.
Nella parte 1 della serie sulla memoria abbiamo scritto che «VAD, PTE e attributi di protezione decidono se l’accesso è consentito». In un ambiente VBS lo si può organizzare così: dopo che tutti quelli sono stati superati, aspetta ancora un checkpoint SLAT.
3.3. Il Secure Kernel e IUM
Ciò che gira dentro VTL1 non è il kernel NT ordinario ma un kernel piccolo chiamato Secure Kernel. La modalità utente in VTL1 si chiama IUM (Isolated User Mode), e i programmi che vi girano si chiamano trustlet (processi fidati).3
Un trustlet non può fare tutto come un processo ordinario. La maggior parte delle system call viene marshalled verso il kernel NT sul lato VTL0 e il lavoro viene richiesto lì.3 VTL1 non è un «mondo superiore che può fare qualsiasi cosa»; è costruito di proposito piccolo, come una cassaforte che detiene i segreti. Meno codice si può portare nella cassaforte, più piccola è la superficie di attacco.
flowchart TB
accTitle: Il flusso delle system call di un trustlet
accDescr: Un trustlet in VTL1 non gestisce da sé la maggior parte delle system call; le marshalla verso il kernel NT VTL0 e riceve solo il risultato, il che tiene VTL1 piccolo
tl["Trustlet(IUM in VTL1)"] --> sc{"Serve una system call"}
sc -->|Nella maggior parte dei casi| mar["La richiesta è marshalled al kernel NT VTL0"]
mar --> res["Torna solo il risultato"]
res -.-> small["VTL1 resta piccolo, riducendo la superficie di attacco"]
Figura 6: La cassaforte non ha strutture proprie; appalta le faccende e continua a custodire solo i segreti.
4. HVCI — Verificare l’integrità del codice kernel nella cassaforte
4.1. Cosa viene verificato
La prima funzione rappresentativa che sta su VBS è Integrità della memoria — HVCI (hypervisor-protected code integrity). Windows ha un meccanismo di integrità del codice che ispeziona driver e binari in modalità kernel prima che partano e non carica quelli non firmati o non fidati. HVCI esegue questa verifica dentro l’ambiente isolato di VBS.1
La ragione per spostare la logica di verifica stessa in VTL1 è esattamente la debolezza della sezione 2. Se il codice di verifica sta dentro il kernel VTL0, un attaccante che ha preso il kernel può sostituire la verifica. Se sta in VTL1, la mano che sostituisce non ci arriva.
flowchart TB
accTitle: La differenza data da dove vive il codice di verifica
accDescr: Se il codice di verifica sta dentro il kernel VTL0 può essere disabilitato prendendo il kernel, ma se sta in VTL1 anche un attaccante che ha preso il kernel non ci arriva e la verifica è protetta
atk["Attaccante che ha preso il kernel"] --> q{"Dove vive la verifica di integrità del codice?"}
q -->|"Dentro il kernel VTL0(classico)"| bad["La logica di verifica può essere sostituita"]
q -->|"Ambiente isolato in VTL1(HVCI)"| good["La sostituzione è fuori portata"]
bad --> res1["Codice non firmato può girare nel kernel"]
good --> res2["La verifica continua a funzionare dopo la compromissione del kernel"]
Figura 7: Non mettere il checkpoint dentro il lato che potrebbe essere violato — quello spostamento della logica di verifica è l’essenza di HVCI.
4.2. Le regole per le pagine eseguibili
L’effetto di HVCI non si limita all’«ispezione all’avvio». Vincola anche l’allocazione della memoria kernel.4
- Una pagina del kernel diventa eseguibile solo dopo aver superato la verifica di integrità del codice.
- Una pagina eseguibile non diventa scrivibile (il cosiddetto W^X).
Quando queste due sono in vigore, anche se una vulnerabilità come un buffer overflow permette di riscrivere la memoria kernel, non si possono mettere in esecuzione i contenuti riscritti. Una pagina eseguibile non si può riscrivere, e una pagina che si può riscrivere non si può eseguire.4 Il sostegno finale del permesso di esecuzione è il diritto di esecuzione sul lato SLAT, che il kernel VTL0 non può manipolare.
flowchart TB
accTitle: Finché una pagina del kernel diventa eseguibile in un ambiente HVCI
accDescr: Una richiesta di caricamento di un driver riceve la verifica di integrità del codice nell'ambiente isolato di VBS; se passa viene consentita come pagina eseguibile e non scrivibile, e se fallisce viene bloccata e registrata nel registro CodeIntegrity
load["Richiesta di caricare ed eseguire codice kernel"] --> verify{"Verifica di integrità del codice nell'ambiente isolato"}
verify -->|Passa| exec["Eseguibile(scritture vietate)"]
verify -->|Fallisce| block["Il caricamento è bloccato"]
block --> log["Registro CodeIntegrity(3087)"]
exec -.-> wx["Le pagine scrivibili restano non eseguibili"]
Figura 8: La verifica della regola che non lascia coesistere esecuzione e scrittura è fatta sul lato VTL1, e il kernel VTL0 non può ribaltarla.
Tracciare questo dal punto di vista di un attaccante rende chiaro come la regola prende effetto.
flowchart TB
accTitle: Il flusso con cui l'iniezione di codice fallisce in un ambiente HVCI
accDescr: Anche se una vulnerabilità permette di riscrivere la memoria kernel, una pagina che si è potuta scrivere non è eseguibile, e una pagina eseguibile non si può riscrivere in partenza, quindi il codice iniettato non può essere messo in esecuzione
inj["Prova a manomettere la memoria kernel via una vulnerabilità"] --> which{"Quale pagina è l'obiettivo?"}
which -->|Una pagina scrivibile| wok["La scrittura riesce"]
which -->|Una pagina eseguibile| xfail["La scrittura stessa è impossibile"]
wok --> nx["Ma quella pagina non è eseguibile"]
nx --> dead["Il codice iniettato non può essere eseguito"]
xfail --> dead
Figura 9: Il significato di non far incrociare pagine scrivibili e pagine eseguibili è che, qualunque ingresso si prenda, si finisce in un vicolo cieco.
4.3. Il prezzo in compatibilità dei driver
Questa regola collide con i driver di progettazione più vecchia. Quelli che riscrivono il proprio codice a runtime, non hanno firma, o pretendono memoria insieme eseguibile e scrivibile — tali driver non possono essere caricati in un ambiente HVCI. Il fatto del blocco si può confermare in Visualizzatore eventi sotto Applications and Services Logs\Microsoft\Windows\CodeIntegrity\Operational (l’event ID 3087 è rappresentativo).5
«Dopo aver abilitato Integrità della memoria, una periferica ha smesso di funzionare» — in molti casi, quella è la vera identità del problema. La risposta corretta è aggiornare a un driver compatibile con HVCI; disabilitare Integrità della memoria va pensato come ultima risorsa che rinuncia alla protezione in blocco. Se si è coinvolti in questa verifica dal punto di vista dello sviluppo di driver, si veda anche l’articolo sui filter driver («I minifilter driver di Windows»).
flowchart TB
accTitle: Isolare il caso in cui una periferica smette di funzionare sotto Integrità della memoria
accDescr: Identificare il driver bloccato nel registro CodeIntegrity Operational; la risposta corretta è aggiornare a una versione compatibile con HVCI, chiedere al fornitore se non esiste, e trattare la disabilitazione come ultima risorsa che non si rende permanente
sym["Un dispositivo smette di funzionare dopo l'abilitazione di Integrità della memoria"] --> log2["Identifica il driver bloccato nel registro CodeIntegrity"]
log2 --> upd{"C'è un driver compatibile HVCI?"}
upd -->|Sì| fix2["Aggiorna e risolvi lasciando HVCI attivo"]
upd -->|No| ask2["Chiedi al fornitore una versione compatibile"]
ask2 -.-> temp["Disabilitare è un'ultima risorsa, non un'impostazione permanente"]
Figura 10: La prima cosa da guardare non è la schermata delle impostazioni ma il registro, e l’event ID 3087 sa chi ha bloccato il caricamento.
5. Credential Guard — Gli hash sono dentro LSAIso
5.1. LSASS e LSAIso
La seconda funzione rappresentativa che sta su VBS è la risposta al mistero di apertura: Credential Guard.
Il Windows tradizionale teneva gli hash NTLM e i ticket Kerberos nella memoria del processo LSA (lsass.exe). Quando Credential Guard è abilitato, l’archiviazione dei segreti protetti tra questi — gli hash NTLM delle credenziali di dominio e i TGT Kerberos (Ticket Granting Ticket) — si sposta su LSAIso.exe, un trustlet che gira in IUM in VTL1.6
- lsass.exe (VTL0) continua a girare come sportello per l’elaborazione dell’autenticazione, come prima.
- I segreti effettivi sono detenuti da LSAIso.exe (VTL1) e non sono accessibili da VTL0.
- I due comunicano via RPC (Remote Procedure Call).
- LSAIso non ospita affatto driver di dispositivo, e ospita solo il minimo di binari firmati. Le firme sono verificate con un certificato di cui VBS si fida.6
flowchart TB
accTitle: Dove stanno le credenziali quando Credential Guard è abilitato
accDescr: lsass in VTL0 comunica con LSAIso in VTL1 via RPC come sportello di autenticazione; gli hash e i TGT effettivi delle credenziali di dominio protette sono detenuti da LSAIso, quindi un attaccante che ottiene privilegi di amministratore in VTL0 e fa il dump di lsass non ottiene comunque la sostanza protetta
subgraph v0 ["VTL0"]
lsassP["lsass.exe(sportello di autenticazione)"]
att["Attaccante(privilegi di amministratore)"]
end
subgraph v1 ["VTL1"]
iso["LSAIso.exe(cassaforte dei segreti)"]
end
lsassP <-->|RPC| iso
att -->|Dump della memoria| lsassP
att -.->|Non ci arriva| iso
Figura 11: Poiché lo sportello e la cassaforte sono stati separati, fare il dump di lsass non produce più gli hash effettivi delle credenziali di dominio protette.
Da Windows 11 versione 22H2 in poi, sui dispositivi che soddisfano i requisiti di licenza (Enterprise E3/E5, Education A3/A5) e i requisiti hardware, VBS e Credential Guard sono abilitati per default. Sulle edizioni come Pro, Credential Guard non viene abilitato automaticamente (ci sono eccezioni, come quando una macchina che era abilitata sotto una licenza idonea viene poi declassata).7 «Il playbook non funziona più» in apertura non è una storia su un prodotto aggiuntivo speciale; è lo stato standard del Windows attuale sulle edizioni di destinazione.
flowchart TB
accTitle: Il flusso delle credenziali dall'accesso all'autenticazione
accDescr: Dopo l'accesso i segreti effettivi sono archiviati in LSAIso in VTL1; ogni volta che serve l'autenticazione, lsass in VTL0 richiede il calcolo via RPC, e a VTL0 torna solo il risultato dell'elaborazione di autenticazione senza che i segreti di lungo termine protetti stessi vengano restituiti
signin["L'utente accede"] --> front["lsass lo gestisce come sportello"]
front --> store["I segreti effettivi sono archiviati in LSAIso"]
auth["Richieste di autenticazione successive"] --> front
front -->|"Richiede il calcolo via RPC"| store
store -->|"Restituisce il risultato(non il segreto)"| front
Figura 12: I segreti di lungo termine protetti stessi non lasciano mai la cassaforte; ciò che torna a VTL0 è il risultato dell’elaborazione di autenticazione, come un ticket.
5.2. Sapere con precisione cosa non è protetto
Credential Guard non è uno scudo per tutti gli usi. Ciò che è protetto sono gli hash NTLM delle credenziali di dominio, i TGT Kerberos (Ticket Granting Ticket) e ciò che è stato memorizzato come credenziali di dominio. I seguenti sono fuori ambito.8
- I service ticket Kerberos (i TGT sono protetti)
- Le credenziali degli account locali e degli account Microsoft
- Il furto dell’input da parte di un keylogger, e gli attacchi fisici
- Le credenziali su percorsi che usano NTLMv1, MS-CHAPv2, Digest o CredSSP
- Gli interni di software di terze parti che gestisce le credenziali in proprio
Inoltre, quando Credential Guard è abilitato, NTLMv1, la delega Kerberos non vincolata e simili diventano inutilizzabili, quindi i sistemi aziendali che dipendono dall’autenticazione legacy necessitano di un controllo di compatibilità.8 Non «abilitalo e hai finito», ma capire cosa sta dentro e fuori il raggio di difesa e riempire il resto con altri controlli: è il modo corretto di usarlo in pratica.
flowchart TB
accTitle: Il raggio di difesa di Credential Guard
accDescr: Hash NTLM di dominio e TGT, e credenziali di dominio memorizzate, sono protetti, mentre service ticket, account locali, keylogger, attacchi fisici e credenziali archiviate in privato da un'app sono fuori ambito
scope{"Da che lato del confine di protezione sta questo segreto?"} --> inA["Hash NTLM di dominio e TGT"]
scope --> outA["Service ticket e account locali"]
inA --> prot["Protetti in LSAIso"]
outA --> unprot["Non protetti(servono altri controlli)"]
unprot -.-> outB["Tastiera, attacchi fisici e archivi privati delle app sono fuori ambito"]
Figura 13: Il raggio di difesa è tracciato con una linea chiara, e l’esterno della linea si riempie con autenticazione a più fattori e progetto lato app.
6. Verificatelo voi stessi
Si può confermare lo stato di esecuzione di VBS e di ciascuna funzione sulla propria macchina.
Get-CimInstance -Namespace root/Microsoft/Windows/DeviceGuard `
-ClassName Win32_DeviceGuard |
Select-Object VirtualizationBasedSecurityStatus,
SecurityServicesConfigured,
SecurityServicesRunning
Come leggerlo è il seguente.9
- Se
VirtualizationBasedSecurityStatusè 2, VBS è abilitata e in esecuzione. - Se
SecurityServicesRunningcontiene 1, Credential Guard è in esecuzione; se contiene 2, Integrità della memoria (HVCI) è in esecuzione.
Per confermare lo stato di esecuzione nella GUI, guardare il campo «Sicurezza basata sulla virtualizzazione» in msinfo32 (sono elencati i servizi in esecuzione, come «Hypervisor enforced Code Integrity»). L’interruttore «Integrità della memoria» sotto «Sicurezza del dispositivo > Isolamento del core» nell’app Sicurezza di Windows è una schermata che riflette le impostazioni; può apparire acceso anche mentre HVCI non è effettivamente in esecuzione — in attesa di un riavvio subito dopo l’abilitazione, o un problema di compatibilità all’avvio — quindi giudicare se è in esecuzione da msinfo32 o da SecurityServicesRunning di Win32_DeviceGuard.5
C’è anche una traccia nella scheda Dettagli di Gestione attività. Su una macchina in cui VBS è in esecuzione si vedrà un processo chiamato «Secure System». LsaIso.exe è il processo che compare quando il servizio Isolated LSA è ospitato in VTL1, e di norma non compare in una configurazione in cui è abilitato solo HVCI. La presenza o l’assenza di un processo è però solo una traccia, quindi giudicare se Credential Guard è in esecuzione da SecurityServicesRunning (se contiene 1), come sopra. Entrambi sono finestre visibili da VTL0 che corrispondono al mondo lato VTL1.
flowchart TB
accTitle: Come verificare che le funzioni legate a VBS siano in esecuzione
accDescr: Confermare che VBS è in esecuzione interrogando Win32_DeviceGuard, giudicare Credential Guard e HVCI dai valori di SecurityServicesRunning, e guardare il registro CodeIntegrity per i problemi dei driver
q0["Win32_DeviceGuard"] --> q1{"Stato VBS 2?"}
q1 -->|No| off["VBS non è in esecuzione"]
q1 -->|Sì| q2{"Contiene 1 o 2?"}
q2 -->|1| cg["Credential Guard attivo"]
q2 -->|2| hvciR["HVCI attivo"]
hvciR -.-> ev["CodeIntegrity 3087"]
Figura 14: La conferma dello stato procede in tre stadi: VBS stesso, ciascun servizio sopra di esso, e il registro quando si verifica un problema.
7. Tre equivoci da evitare nella pratica
7.1. «Proteggere i privilegi di amministratore basta. VBS è una storia lato server»
Ciò che Credential Guard impedisce è il danno che si propaga dopo che i privilegi di amministratore sono stati presi (esfiltrazione degli hash e movimento laterale). In altre parole VBS è uno strato di difesa in profondità che presuppone la compromissione, ed è sui PC client che è efficace. Su Windows 11 che soddisfa i requisiti, abilitata-per-default è lo standard, quindi l’atteggiamento giusto non è «questo non c’entra con noi» ma «gestire la compatibilità nell’ipotesi che sia già in esecuzione».
flowchart TB
accTitle: Stadi della compromissione e dove VBS ha effetto
accDescr: L'accesso iniziale è coperto da altri controlli come autenticazione a più fattori e formazione; HVCI blocca l'iniezione di codice nel kernel dopo l'escalation di privilegi; Credential Guard blocca il furto dei segreti di dominio protetti e il movimento laterale, ma non raggiunge i segreti fuori dal suo ambito
s1["Accesso iniziale(phishing e simili)"] --> s2["Escalation di privilegi"]
s2 --> s3["Iniezione di codice nel kernel"]
s3 --> s4["Furto di segreti di dominio protetti e movimento laterale"]
s1 -.-> d1["MFA, formazione ed EDR coprono questo"]
s3 -.-> d2["HVCI blocca questo passo"]
s4 -.-> d3["Credential Guard blocca questo(solo i segreti protetti)"]
Figura 15: VBS non è una tecnologia del «non farli entrare»; è una tecnologia del «non farli vincere dopo che sono dentro», e lo stadio che custodisce è diverso.
7.2. «Se Integrità della memoria causa un problema, basta spegnerla»
Spegnendola le cose funzioneranno per il momento, ma si abbatte in blocco la barriera contro l’iniezione di codice nel kernel. La risposta corretta è prima identificare il driver bloccato nel registro CodeIntegrity e applicare la versione aggiornata del fornitore. Anche se la si disabilita temporaneamente per la convalida, raccomandiamo un’operazione che non renda quella un’impostazione permanente.
7.3. «Con Credential Guard le password non si possono rubare»
Quella è una fiducia eccessiva nata dal mescolare il raggio di difesa. Service ticket, account locali, i tasti stessi e le credenziali archiviate in privato da un’app sono fuori ambito.8 Phishing e keylogger richiedono altri controlli (autenticazione a più fattori, Windows Hello e una revisione della gestione delle credenziali lato app).
8. Riepilogo
- VBS usa l’hypervisor per creare un ambiente isolato e protegge le funzioni di sicurezza nell’ipotesi che il kernel possa essere compromesso.1
- L’unità di isolamento è il VTL; attualmente sono implementati due livelli, VTL0 (il mondo ordinario) e VTL1 (il Secure Kernel e IUM).2
- La sostanza del confine è la protezione di accesso alla memoria SLAT, che il software dentro la partizione — compreso il kernel — non può cambiare.2
- HVCI esegue la verifica di integrità del codice nell’ambiente isolato e impone «non eseguibile finché la verifica non passa» e «una pagina eseguibile non è scrivibile».4 Il prezzo è che occorre gestire la compatibilità dei driver.5
- Credential Guard isola gli hash NTLM delle credenziali di dominio e i TGT in LSAIso in VTL1. Da Windows 11 22H2 in poi è abilitato per default sui dispositivi che soddisfano i requisiti di licenza (Enterprise, Education) e i requisiti hardware (usare questo insieme a un controllo dello stato di esecuzione).67
- Si può confermare lo stato di esecuzione da SecurityServicesRunning di
Win32_DeviceGuard(1 = Credential Guard, 2 = HVCI).9
Continua nella parte 3, «Macchine virtuali che si avviano in pochi secondi — WSL2, Windows Sandbox e container».
Fin qui abbiamo guardato la virtualizzazione dal lato della «forza dell’isolamento». L’ultima puntata guarda dal lato opposto, della «leggerezza», e segue dove le VM leggere che hanno messo da parte il peso di una VM completa stanno tagliando gli angoli.
Articoli correlati
- Le profondità della virtualizzazione Windows (parte 1) — Dove gira davvero il vostro Windows? L’hypervisor e le partizioni
- Le profondità della memoria Windows (parte 1) — Il momento in cui un indirizzo virtuale diventa RAM fisica: un page fault dall’inizio alla fine
- Le profondità dell’I/O di Windows (parte 6, finale) — Filter driver e minifilter: perché Procmon e gli scanner antivirus possono intercettare l’I/O
- Decodificare i codici di errore di Windows — La struttura a tre strati di errori Win32, HRESULT e NTSTATUS
Aree di consulenza correlate
KomuraSoft LLC si occupa di indagini di compatibilità tra applicazioni Windows e funzioni di sicurezza, di analisi di guasti causati da driver e di convalida tecnica degli ambienti PC aziendali.
- Sviluppo di app Windows
- Indagine sui difetti e analisi delle cause
- Riutilizzo di asset esistenti e supporto alla migrazione
- Contattaci
Riferimenti
-
Microsoft Learn, Virtualization-based Security (VBS). Sul fatto che VBS usi la virtualizzazione hardware e l’hypervisor Windows per creare un ambiente isolato e lo tratti come radice di fiducia del sistema operativo nell’ipotesi che il kernel possa essere compromesso; che Integrità della memoria esegua la verifica di integrità del codice in modalità kernel dentro quell’ambiente isolato; e che SLAT sia un requisito vincolante per VBS. ↩ ↩2 ↩3
-
Microsoft Learn, Virtual Secure Mode. Sul fatto che VSM sia il fondamento per Device Guard, Credential Guard, un TPM virtuale e simili; che l’accesso alle regioni isolate sia controllato solo attraverso l’hypervisor e protetto anche dal software del sistema operativo a ring 0; che i VTL siano gerarchici con 2 di un massimo di 16 livelli implementati; e che le protezioni di accesso alla memoria per VTL siano immutabili dal software di sistema dentro la partizione. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Isolated User Mode (IUM) Processes. Sul fatto che VSM crei i VTL usando l’hypervisor Hyper-V e SLAT; che Secure Kernel e IUM girino in VTL1; che i trustlet marshallino le system call verso il kernel VTL0; e che LSAIso giri in VTL1 e comunichi con lsass via RPC. ↩ ↩2 ↩3
-
Microsoft Learn, Memory integrity and virtualization-based security. Sul fatto che Integrità della memoria (HVCI) esegua la verifica di integrità del codice in un ambiente isolato, e sul fatto che le pagine di memoria kernel diventino eseguibili solo dopo aver superato la verifica e che le pagine eseguibili non diventino scrivibili. ↩ ↩2 ↩3
-
Microsoft Learn, Memory integrity and VBS enablement. Sul fatto che Integrità della memoria sia abilitata per default su un’installazione pulita di Windows 11 se l’hardware è compatibile; sulla conferma dello stato in msinfo32 e nell’app Sicurezza di Windows; e sulla conferma di un driver bloccato tramite l’event ID 3087 nel registro CodeIntegrity Operational. ↩ ↩2 ↩3
-
Microsoft Learn, How Credential Guard works. Sul fatto che LSA comunichi con un processo Isolated LSA (LSAIso.exe) per archiviare i segreti quando Credential Guard è abilitato; che i dati archiviati siano protetti da VBS e inaccessibili dal resto del sistema operativo; e che il processo Isolated LSA non ospiti driver di dispositivo e ospiti solo un minimo di binari verificati per firma. ↩ ↩2 ↩3
-
Microsoft Learn, Credential Guard overview. Sul fatto che Credential Guard sia abilitato per default da Windows 11 versione 22H2 in poi sui dispositivi che soddisfano i requisiti di licenza, hardware e software e non siano stati esplicitamente disabilitati; che le edizioni/licenze idonee siano Enterprise (E3/E5) ed Education (A3/A5), con Pro fuori ambito; e che una macchina Pro che era stata abilitata in precedenza sotto una licenza idonea resti un obiettivo abilitato per default dopo un declassamento. ↩ ↩2
-
Microsoft Learn, Credential Guard protection limits. Sul fatto che service ticket, account locali, keylogger, attacchi fisici e simili siano fuori dall’ambito di protezione di Credential Guard; che i TGT siano protetti mentre i service ticket no; e che NTLMv1 e la delega non vincolata diventino inutilizzabili quando è abilitato. ↩ ↩2 ↩3
-
Microsoft Learn, Enable virtualization-based protection of code integrity. Su come confermare lo stato di VBS e Integrità della memoria tramite la classe Win32_DeviceGuard, e sul significato dei valori di SecurityServicesRunning (1 è Credential Guard, 2 è Integrità della memoria). ↩ ↩2
Articoli correlati
Articoli recenti con gli stessi tag per approfondire argomenti vicini.
Le profondità della virtualizzazione Windows (parte 3) — Macchine virtuali che si avviano in pochi secondi: perché WSL2, Windows Sandbox e i container sono così leggeri
Perché WSL2 e Windows Sandbox partono in pochi secondi e sembrano così leggeri? Questo articolo spiega i meccanismi, dalle immagini di ba...
Le profondità della virtualizzazione Windows (parte 1) — Dove gira davvero il vostro Windows? L'hypervisor e le partizioni
Quando si abilita Hyper-V, il Windows host stesso gira sopra l'hypervisor come partizione root. Questo articolo spiega i fondamenti della...
Named pipe in pratica — L'IPC standard di Windows, dalla progettazione alla sicurezza
Guida pratica alle named pipe, il meccanismo standard di comunicazione tra processi su Windows. L'articolo organizza, a partire dalle fon...
L'API thread pool Win32 — Concorrenza senza creare thread, tramite CreateThreadpoolWork
State spargendo chiamate CreateThread per tutto il codice nativo? Questo articolo spiega l'API thread pool Win32 ridisegnata in Vista — i...
Come comprendere l'isolamento delle sessioni di Windows — Session 0, RDP ed esecuzione simultanea di più utenti
Questo articolo chiarisce il concetto di «sessione» di Windows, un argomento che genera costante confusione tra gli sviluppatori di appli...
Argomenti correlati
Queste pagine collocano l’argomento in un contesto più ampio di servizi e decisioni.
Argomenti tecnici Windows
Portale su sviluppo Windows, analisi dei problemi e valorizzazione delle risorse esistenti.
Servizi collegati all’argomento
L’articolo è direttamente collegato ai servizi seguenti.
Sviluppo di applicazioni Windows
Applicazioni aziendali, integrazione di dispositivi e strumenti di comunicazione, dai requisiti allo sviluppo.
Domande frequenti
Domande che ricorrono nelle consulenze sull’argomento dell’articolo.
- VBS (sicurezza basata sulla virtualizzazione) e Isolamento del core sono la stessa cosa?
- In senso stretto, sono diversi. VBS è la tecnologia di fondamento che crea un ambiente isolato con l'hypervisor, e «Isolamento del core» nell'app Sicurezza di Windows è il nome di una schermata che raggruppa diverse protezioni costruite su VBS. Quella rappresentativa è «Integrità della memoria», che si riferisce a HVCI (hypervisor-protected code integrity). Confermare lo stato di esecuzione di ciascun servizio interrogando Win32_DeviceGuard, non dalla visualizzazione della schermata.
- La memoria VTL1 non si può davvero leggere, nemmeno con privilegi di amministratore o da un driver kernel?
- Non si può. Le protezioni di accesso alla memoria per VTL sono gestite dall'hypervisor rispetto allo spazio di indirizzi fisici della partizione, e il software che gira dentro la partizione non può cambiarle. Anche il codice che gira nel kernel (ring 0) non è autorizzato ad accedere alla memoria VTL1 da VTL0.
- Perché abilitare Integrità della memoria (HVCI) può far smettere di funzionare un driver?
- In un ambiente HVCI, una pagina del kernel diventa eseguibile solo dopo aver superato la verifica di integrità, e le scritture su pagine eseguibili non sono consentite. Un driver non firmato, o un driver di progettazione più vecchia che riscrive memoria eseguibile, non può soddisfare questo vincolo e il suo caricamento viene bloccato. Si può confermare il blocco nel registro CodeIntegrity Operational (event ID 3087 e simili).
- Cosa protegge Credential Guard, e cosa non protegge?
- Protegge gli hash delle password NTLM delle credenziali di dominio, i TGT Kerberos e ciò che un'app ha memorizzato come credenziali di dominio, in un ambiente isolato. I service ticket Kerberos, le credenziali degli account locali e degli account Microsoft, il furto dell'input da parte di un keylogger e gli attacchi fisici sono fuori ambito.
- Dove si può controllare se VBS è in esecuzione?
- Guardare il campo «Sicurezza basata sulla virtualizzazione» in msinfo32, oppure interrogare la classe Win32_DeviceGuard nello spazio dei nomi root/Microsoft/Windows/DeviceGuard da PowerShell. Se SecurityServicesRunning contiene 1, Credential Guard è in esecuzione; se contiene 2, Integrità della memoria (HVCI) è in esecuzione.
Profilo dell’autore
Pagina di presentazione dell’autore dell’articolo.
Go Komura
Rappresentante di KomuraSoft LLC
Specializzato nello sviluppo di software Windows, nella consulenza tecnica e nell’analisi dei malfunzionamenti, soprattutto nei progetti con sistemi esistenti e guasti difficili da riprodurre.