Nota
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare ad accedere o a cambiare directory.
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare a cambiare directory.
Il modello di sicurezza di Windows si basa su oggetti a protezione diretta. Ogni componente del sistema operativo deve garantire la sicurezza degli oggetti per cui è responsabile. I driver, pertanto, devono salvaguardare la sicurezza dei dispositivi e degli oggetti dispositivo.
Questo argomento riepiloga il modo in cui il modello di sicurezza di Windows si applica ai driver in modalità kernel.
Modello di sicurezza di Windows
Il modello di sicurezza di Windows si basa principalmente sui diritti per oggetto, con un numero ridotto di privilegi a livello di sistema. Gli oggetti che possono essere protetti includono, ad esempio processi, thread, eventi e altri oggetti di sincronizzazione, nonché file, directory e dispositivi.
Per ogni tipo di oggetto, i diritti di lettura, scrittura ed esecuzione generici si trasformano in diritti dettagliati specifici dell'oggetto. Ad esempio, per file e directory, i diritti possibili includono il diritto di leggere o scrivere il file o la directory, il diritto di leggere o scrivere attributi di file estesi, il diritto di attraversare una directory e il diritto di scrivere il descrittore di sicurezza di un oggetto.
Il modello di sicurezza prevede i concetti seguenti:
- Identificatori di sicurezza (SID)
- Token di accesso
- Descrittori di sicurezza
- Elenchi di controllo di accesso (ACL)
- Privilegi
Identificatori di sicurezza (SID)
Un identificatore di sicurezza (SID, detto anche principale) identifica un utente, un gruppo o una sessione di accesso. Ogni utente ha un SID univoco, recuperato dal sistema operativo all'accesso.
I SID vengono emessi da un'autorità, ad esempio il sistema operativo o un server di dominio. Alcuni SID sono noti e hanno nomi e identificatori. Ad esempio, il SID S-1-1-0 identifica Everyone (o World).
Token di accesso
Ogni processo ha un token di accesso. Il token di accesso descrive il contesto di sicurezza completo del processo. Contiene il SID dell'utente, il SID dei gruppi a cui appartiene l'utente e il SID della sessione di accesso, nonché un elenco dei privilegi a livello di sistema concessi all'utente.
Per impostazione predefinita, il sistema usa il token di accesso primario per un processo ogni volta che un thread del processo interagisce con un oggetto a protezione diretta. Tuttavia, un thread può impersonare un account client. Quando un thread impersona, ha un token di impersonificazione oltre al proprio token primario. Il token di rappresentazione descrive il contesto di sicurezza dell'account utente che il thread sta impersonando. L'impersonificazione è particolarmente comune nella gestione RPC (Remote Procedure Call).
Un token di accesso che descrive un contesto di sicurezza limitato per un thread o un processo è denominato token con restrizioni. I SID in un token con restrizioni possono essere impostati solo per negare l'accesso, non per consentire l'accesso, agli oggetti proteggibili. Inoltre, il token può descrivere un set limitato di privilegi a livello di sistema. Il SID e l'identità dell'utente rimangono invariati, ma i diritti di accesso dell'utente sono limitati mentre il processo usa il token con restrizioni. La funzione CreateRestrictedToken crea un token con restrizioni.
Descrittori di sicurezza
Ogni oggetto Windows denominato ha un descrittore di sicurezza; anche alcuni oggetti senza nome. Il descrittore di sicurezza descrive i SID del proprietario e del gruppo per l'oggetto insieme ai relativi ACL.
Il descrittore di sicurezza di un oggetto viene in genere creato dalla funzione che crea l'oggetto. Quando un driver chiama la routine IoCreateDevice o IoCreateDeviceSecure per creare un oggetto dispositivo, il sistema applica un descrittore di sicurezza all'oggetto dispositivo creato e imposta gli ACL per l'oggetto. Per la maggior parte dei dispositivi, gli elenchi di controllo di accesso vengono specificati nel file INF (Device Information).
Per altre informazioni sui descrittori di sicurezza nella documentazione del driver del kernel.
Elenchi di controllo di accesso
Gli elenchi di controllo di accesso (ACL) consentono un controllo granulare sull'accesso agli oggetti. Un elenco di controllo di accesso fa parte del descrittore di sicurezza per ogni oggetto.
Ogni ACL contiene zero o più voci di controllo di accesso (ACE). Ogni ACE, a sua volta, contiene un singolo SID che identifica un utente, un gruppo o un computer e un elenco di diritti negati o consentiti per tale SID.
ACL per gli oggetti di dispositivo
L'ACL per un oggetto dispositivo può essere impostato in uno dei tre modi seguenti:
- Impostato nel descrittore di sicurezza predefinito per il tipo di dispositivo.
- Creato a livello di codice dalla funzione RtlCreateSecurityDescriptor e impostato dalla funzione RtlSetDaclSecurityDescriptor .
- Specificato in Security Descriptor Definition Language (SDDL) nel file INF del dispositivo o in una chiamata alla routine IoCreateDeviceSecure .
Tutti i driver devono usare SDDL nel file INF per specificare gli elenchi di controllo di accesso per gli oggetti dispositivo.
SDDL è un linguaggio di descrizione estendibile che consente ai componenti di creare elenchi di controllo di accesso in un formato stringa. SDDL viene usato sia dal codice in modalità utente che dal codice in modalità kernel. La figura seguente illustra il formato delle stringhe SDDL per gli oggetti dispositivo.
Il valore access specifica il tipo di accesso consentito. Il valore SID specifica un identificatore di sicurezza che determina a chi si applica il valore di Access, ad esempio un utente o un gruppo.
Ad esempio, la stringa SDDL seguente consente al sistema (SY) di accedere a tutti gli elementi e consente a tutti gli altri (WD) solo l'accesso in lettura:
“D:P(A;;GA;;;SY)(A;;GR;;;WD)”
Il file di intestazione wdmsec.h include anche un set di stringhe SDDL predefinite adatte agli oggetti dispositivo. Ad esempio, il file di intestazione definisce SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX come indicato di seguito:
"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGWGX;;;WD)(A;;GRGWGX;;;RC)"
Il primo segmento di questa stringa consente il controllo completo del kernel e del sistema operativo (SY) sul dispositivo. Il secondo segmento consente a chiunque nel gruppo Administrators predefinito (BA) di accedere all'intero dispositivo, ma non di modificare l'ACL. Il terzo segmento consente a tutti (WD) di leggere o scrivere nel dispositivo e il quarto segmento concede gli stessi diritti al codice non attendibile (RC). I driver possono usare le stringhe predefinite così come sono o come modelli per stringhe specifiche dell'oggetto dispositivo.
Tutti gli oggetti dispositivo in uno stack devono avere gli stessi elenchi di controllo di accesso. La modifica degli elenchi di controllo di accesso in un oggetto dispositivo nello stack modifica gli elenchi di controllo di accesso nell'intero stack di dispositivi.
Tuttavia, l'aggiunta di un nuovo oggetto dispositivo allo stack non modifica gli ACL, quelli del nuovo oggetto dispositivo (se contiene ACL) o quelli di qualsiasi oggetto dispositivo esistente nello stack. Quando un driver crea un nuovo oggetto dispositivo e lo collega all'inizio dello stack, il driver deve copiare gli elenchi di controllo di accesso per lo stack nel nuovo oggetto dispositivo copiando il campo DeviceObject.Characteristics dal driver inferiore successivo.
La routine IoCreateDeviceSecure supporta un subset di stringhe SDDL che usano SID predefiniti, ad esempio WD e SY. Le API in modalità utente e i file INF supportano la sintassi SDDL completa.
Controlli di sicurezza tramite ACL (elenchi di controllo di accesso)
Quando un processo richiede l'accesso a un oggetto, i controlli di sicurezza confrontano gli ACL per l'oggetto con i SID nel token di accesso del chiamante.
Il sistema confronta le ACE in un ordine rigorosamente dall'alto verso il basso e si ferma sulla prima corrispondenza pertinente. Pertanto, quando si crea un ACL, è consigliabile inserire sempre gli ACL negati sopra gli ACL di concessione corrispondenti. Negli esempi seguenti viene illustrato come procede il confronto.
Esempio 1: Confronto di un ACL con un token di accesso
Nell'esempio 1 viene illustrato come il sistema confronta un ACL con il token di accesso per il processo di un chiamante. Si supponga che il chiamante voglia aprire un file con l'elenco di controllo di accesso illustrato nella tabella seguente.
ACL di file di esempio
| Autorizzazione | SID | Accesso |
|---|---|---|
| Consentire | Contabilità | Scrivere, eliminare |
| Consentire | Vendite | Aggiungi |
| Negare | Legale | Accodamento, scrittura, eliminazione |
| Consentire | Tutti | Leggi |
Questo ACL ha quattro ACE, che si applicano in modo specifico ai gruppi Contabilità, Vendite, Legale e Everyone.
Si supponga quindi che il token di accesso per il processo di richiesta contenga i SID per un utente e tre gruppi, nell'ordine seguente:
Utente Jim (S-1-5-21...)
Contabilità gruppo (S-1-5-22...)
Legale gruppo (S-1-5-23...)
Raggruppa tutti (S-1-1-0)
Quando si confronta un ACL di file con un token di accesso, il sistema cerca prima un ace per l'utente Jim nell'ACL del file. Non compare nulla, quindi successivamente cerca un ACE per il gruppo di contabilità. Come illustrato nella tabella precedente, un'ACE per il gruppo di Contabilità appare come prima voce nell'ACL del file, quindi al processo di Jim viene assegnato il diritto di scrivere o eliminare il file e il confronto si arresta. Se l'ACE per il gruppo Legale precede l'ACE per il gruppo Accounting nell'ACL, il processo non avrà i permessi di scrittura, accodamento ed eliminazione sul file.
Esempio 2: Confronto di un ACL con un token con restrizioni
Il sistema confronta un ACL con un token con restrizioni nello stesso modo in cui confronta quelli in un token che non è limitato. Tuttavia, un SID denial in un token con restrizioni può corrispondere solo a Deny ACE in un ACL.
Nell'esempio 2 viene illustrato come il sistema confronta l'ACL di un file con un token con restrizioni. Si supponga che il file abbia lo stesso ACL illustrato nella tabella precedente. In questo esempio, tuttavia, il processo ha un token con restrizioni che contiene i SID seguenti:
Utente Jim (S-1-5-21...) Negare
Contabilità gruppo (S-1-5-22...) Negare
Legale gruppo (S-1-5-23...) Negare
Raggruppa tutti (S-1-1-0)
L'ACL del file non elenca il SID di Jim, quindi il sistema procede al SID del gruppo Accounting. Anche se l'ACL del file ha un ACE per il gruppo Accounting, questa ACE consente l'accesso; pertanto, non corrisponde al SID nel token con restrizioni del processo, che nega l'accesso. Di conseguenza, il sistema procede al SID del gruppo legale. L'ACL per il file contiene un ace per il gruppo Legale che nega l'accesso, pertanto il processo non può scrivere, aggiungere o eliminare il file.
Privilegi
Un privilegio è il diritto per un utente di eseguire un'operazione correlata al sistema nel computer locale, ad esempio il caricamento di un driver, la modifica dell'ora o l'arresto del sistema.
I privilegi sono diversi dai diritti di accesso perché si applicano alle attività e alle risorse correlate al sistema anziché agli oggetti e perché vengono assegnati a un utente o a un gruppo da un amministratore di sistema, anziché dal sistema operativo.
Il token di accesso per ogni processo contiene un elenco dei privilegi concessi al processo. I privilegi devono essere abilitati in modo specifico prima dell'uso. Per altre informazioni sui privilegi, vedere Privilegi nella documentazione del driver del kernel.
Comandi del debugger correlati alla sicurezza
L'estensione !acl formatta e visualizza il contenuto di un elenco di controllo di accesso (ACL). Per altre informazioni, vedere Determinazione dell'ACL di un oggetto e !acl.
L'estensione !token visualizza una visualizzazione formattata di un oggetto token di sicurezza. Per altre informazioni, vedere !token.
L'estensione !tokenfields visualizza i nomi e gli offset dei campi all'interno dell'oggetto token di accesso (la struttura TOKEN). Per altre informazioni, vedere !tokenfields.
L'estensione !sid visualizza l'identificatore di sicurezza (SID) nell'indirizzo specificato. Per altre informazioni, vedere !sid.
L'estensione !sd visualizza il descrittore di sicurezza in corrispondenza dell'indirizzo specificato. Per altre informazioni, vedere !sd.
Scenario del modello di sicurezza di Windows: Creazione di un file
Il sistema usa i costrutti di sicurezza descritti nel modello di sicurezza di Windows ogni volta che un processo crea un handle per un file o un oggetto.
Il diagramma seguente illustra le azioni correlate alla sicurezza attivate quando un processo in modalità utente tenta di creare un file.
Il diagramma precedente mostra come il sistema risponde quando un'applicazione in modalità utente chiama la funzione CreateFile . Le note seguenti fanno riferimento ai numeri cerchiati nella figura:
- Un'applicazione in modalità utente chiama la funzione CreateFile , passando un nome di file Microsoft Win32 valido.
- La modalità utente Kernel32.dll passa la richiesta a Ntdll.dll, che converte il nome Win32 in un nome file di Microsoft Windows NT.
- Ntdll.dll chiama la funzione NtCreateFile con il nome file di Windows. All'interno di Ntoskrnl.exe, il gestore di I/O gestisce NtCreateFile.
- Il gestore I/O riconfeziona la richiesta in una chiamata al gestore degli oggetti.
- Gestione oggetti risolve i collegamenti simbolici e garantisce che l'utente disponga dei diritti di attraversamento per il percorso in cui verrà creato il file. Per altre informazioni, vedere Controlli di sicurezza in Gestione oggetti.
- Gestione oggetti chiama il componente di sistema proprietario del tipo di oggetto sottostante associato alla richiesta. Per una richiesta di creazione di file, questo componente è l'I/O Manager, proprietario di oggetti dispositivo.
- Il gestore I/O verifica il descrittore di sicurezza dell'oggetto dispositivo rispetto al token di accesso del processo dell'utente per garantire che l'utente abbia l'accesso necessario al dispositivo. Per altre informazioni, vedere Controlli di sicurezza in Gestione I/O.
- Se il processo utente ha l'accesso necessario, il gestore I/O crea un handle e invia una richiesta IRP_MJ_CREATE al driver per il dispositivo o il file system.
- Il driver esegue controlli di sicurezza aggiuntivi in base alle esigenze. Ad esempio, se la richiesta specifica un oggetto nello spazio dei nomi del dispositivo, il driver deve assicurarsi che il chiamante disponga dei diritti di accesso necessari. Per altre informazioni, vedere Controlli di sicurezza nel driver.
Controlli di sicurezza in Gestione oggetti
La responsabilità di controllare i diritti di accesso appartiene al componente di livello più alto in grado di eseguire tali controlli. Se Gestione oggetti può verificare i diritti di accesso del chiamante, lo fa. In caso contrario, Gestione oggetti passa la richiesta al componente responsabile del tipo di oggetto sottostante. Tale componente, a sua volta, verifica l'accesso, se possibile; se non riesce, passa la richiesta a un componente ancora inferiore, ad esempio un driver.
Il Gestore degli Oggetti controlla gli elenchi di controllo di accesso per tipi di oggetto semplici, ad esempio eventi e lock mutex. Per gli oggetti con uno spazio dei nomi, il proprietario del tipo esegue i controlli di sicurezza. Ad esempio, Gestione I/O viene considerato il proprietario del tipo per oggetti dispositivo e oggetti file. Se Gestione oggetti trova il nome di un oggetto dispositivo o di un oggetto file durante l'analisi di un nome, passa il nome a Gestione I/O, come nello scenario di creazione di file presentato in precedenza. Gestione I/O controlla quindi i diritti di accesso, se possibile. Se il nome specifica un oggetto all'interno di un namespace del dispositivo, il Gestore I/O passa il nome al driver del dispositivo (o del file system), e tale driver è responsabile della convalida dell'accesso richiesto.
Controlli di sicurezza in Gestione I/O
Quando gestione I/O crea un handle, controlla i diritti dell'oggetto rispetto al token di accesso del processo e quindi archivia i diritti concessi all'utente insieme all'handle. Quando arrivano richieste di I/O successive, Gestione I/O controlla i diritti associati all'handle per assicurarsi che il processo abbia il diritto di eseguire l'operazione di I/O richiesta. Ad esempio, se il processo richiede in seguito un'operazione di scrittura, Gestione I/O controlla i diritti associati all'handle per assicurarsi che il chiamante disponga dell'accesso in scrittura all'oggetto.
Se l'handle è duplicato, i diritti possono essere rimossi dalla copia, ma non possono essere aggiunti.
Quando gestione I/O crea un oggetto, converte le modalità di accesso Win32 generiche in diritti specifici dell'oggetto. Ad esempio, i diritti seguenti si applicano a file e directory:
| Modalità di accesso Win32 | Diritti specifici dell'oggetto |
|---|---|
| GENERIC_READ | LeggiDati |
| SCRITTURA_GENERICA | WriteData |
| ESECUZIONE_GENERICA | ReadAttributes |
| GENERIC_ALL | Tutti |
Per creare un file, un processo deve avere permessi di navigazione per le directory padre nel percorso di destinazione. Ad esempio, per creare \Device\CDROM0\Directory\File.txt, un processo deve avere il diritto di attraversare \Device, \Device\CDROM0 e \Device\CDROM0\Directory. Il gestore I/O controlla solo i diritti di attraversamento per queste directory.
Il gestore I/O controlla i diritti di accesso quando analizza il nome del file. Se il nome del file è un collegamento simbolico, Gestione I/O lo risolve in un percorso completo e quindi controlla i diritti di attraversamento, a partire dalla radice. Si supponga, ad esempio, che il collegamento simbolico \DosDevices\D sia mappato al nome del dispositivo Windows NT \Device\CDROM0. Il processo deve avere diritti di attraversamento per la directory \Device.
Per altre informazioni, vedere Handle di oggetti e sicurezza degli oggetti.
Controlli di sicurezza nel driver
Il kernel del sistema operativo considera ogni driver, in effetti, come un file system con il proprio spazio dei nomi. Di conseguenza, quando un chiamante tenta di creare un oggetto nello spazio dei nomi del dispositivo, l'I/O Manager verifica che il processo abbia permessi di passaggio per le directory nel percorso.
Con i driver WDM, il gestore I/O non esegue controlli di sicurezza sullo spazio dei nomi, a meno che l'oggetto dispositivo non sia stato creato specificando l'opzione FILE_DEVICE_SECURE_OPEN. Quando FILE_DEVICE_SECURE_OPEN non è impostato, il driver è responsabile di garantire la sicurezza del proprio namespace. Per ulteriori informazioni, vedere Controllo dell'accesso allo spazio dei nomi del dispositivo e Protezione degli oggetti dispositivo.
Per i driver WDF, il flag di FILE_DEVICE_SECURE_OPEN viene sempre impostato, in modo che sia presente un controllo del descrittore di sicurezza del dispositivo prima di consentire a un'applicazione di accedere a qualsiasi nome all'interno dello spazio dei nomi del dispositivo. Per altre informazioni, vedere Controllo dell'accesso ai dispositivi nei driver KMDF.
Limiti di sicurezza di Windows
I driver che comunicano tra loro e con i chiamanti in modalità utente di diversi livelli di privilegio possono essere considerati attraversare un limite di attendibilità. Un limite di attendibilità è qualsiasi percorso di esecuzione del codice che attraversa un processo con privilegi inferiore in un processo con privilegi più elevati.
Maggiore è la disparità nei livelli di privilegio, più interessante è il limite per gli attaccanti che vogliono eseguire attacchi come un attacco di elevazione dei privilegi contro il driver o il processo preso di mira.
Parte del processo di creazione di un modello di minaccia consiste nell'esaminare i limiti di sicurezza e cercare percorsi imprevisti. Per altre informazioni, vedere Modellazione delle minacce per i driver.
Tutti i dati che superano un limite di attendibilità non sono attendibili e devono essere convalidati.
Questo diagramma mostra tre driver del kernel e due app, una in un contenitore di app e un'app eseguita con diritti di amministratore. Le linee rosse indicano limiti di attendibilità di esempio.
Poiché il contenitore dell'app può fornire vincoli aggiuntivi e non è in esecuzione a livello di amministratore, il percorso (1) è un percorso di rischio più elevato per un attacco di escalation perché il limite di attendibilità è tra un contenitore di app (un processo con privilegi molto limitati) e un driver kernel.
Il percorso (2) è un percorso di rischio inferiore, perché l'app viene eseguita con diritti di amministratore e chiama direttamente nel driver del kernel. L'amministratore è già un privilegio piuttosto elevato nel sistema, quindi la superficie di attacco dall'amministratore al kernel è meno di un obiettivo interessante per gli utenti malintenzionati, ma ancora un limite di attendibilità notevole.
Path (3) è un esempio di percorso di esecuzione del codice che supera più limiti di attendibilità che potrebbero non essere superati se non viene creato un modello di minaccia. In questo esempio esiste un limite di attendibilità tra il driver 1 e il driver 3, perché il driver 1 accetta l'input dall'app in modalità utente e lo passa direttamente al driver 3.
Tutti gli input provenienti dal driver dalla modalità utente non sono attendibili e devono essere convalidati. Gli input provenienti da altri driver potrebbero anche non essere attendibili a seconda che il driver precedente sia stato solo un semplice passaggio (ad esempio, i dati ricevuti dal driver 1 dall'app 1, il driver 1 non ha eseguito alcuna convalida sui dati e li ha semplicemente passati al driver 3). Assicurarsi di identificare tutte le superfici di attacco e i limiti di attendibilità e convalidare tutti i dati che li attraversano, creando un modello di minaccia completo.
Consigli sul modello di sicurezza di Windows
- Impostare elenchi di controllo di accesso predefiniti sicuri nelle chiamate alla routine IoCreateDeviceSecure .
- Specificare gli elenchi di controllo di accesso nel file INF per ogni dispositivo. Questi ACL possono allentare gli ACL predefiniti stretti, se necessario.
- Impostare la caratteristica FILE_DEVICE_SECURE_OPEN per applicare le impostazioni di sicurezza degli oggetti dispositivo allo spazio dei nomi del dispositivo.
- Non definire IOCTLs che consentono FILE_ANY_ACCESS a meno che tale accesso non possa essere sfruttato in modo dannoso.
- Usare la routine IoValidateDeviceIoControlAccess per rafforzare la sicurezza su IOCTLS esistenti che consentono FILE_ANY_ACCESS.
- Creare un modello di minaccia per esaminare i limiti di sicurezza e cercare percorsi imprevisti. Per altre informazioni, vedere Modellazione delle minacce per i driver.
- Per altre raccomandazioni sulla sicurezza dei driver, vedere Elenco di controllo per la sicurezza dei driver.