Parte 1: http://blogs.ugidotnet.org/raffaele/archive/2009/01/27/windows-vista-integrity-levels-parte-1.aspx
Parte 2: http://blogs.ugidotnet.org/raffaele/archive/2009/01/29/windows-vista-integrity-levels-parte-2.aspx
La parte divertente è quella di scrivere codice, vediamo quindi le API per usare gli Integrity Levels.
Creazione di un processo via API con integrity level impostato a low
- Prendere l'handle del token del processo corrente (che di default è "medium")
- Duplicare l'handle (API DuplicateHandle)
- Impostare l'Integrity Level a "Low" grazie a SetTokenInformation
- Creare il processo con CreateProcessAsUser usando il nuovo token modificato
1: #include <windows.h>
2: #include <Sddl.h>
3:
4: #include <string>
5: using namespace std;
6:
7:
8: // restituisce zero se tutto è ok, oppure l'errore win32
9: DWORD CreateLowProcess(wstring PathName, wstring CommandLine)
10: {
11: // Low integrity SID
12: WCHAR IntegritySid[20] = L"S-1-16-4096";
13: DWORD LastError = 0;
14:
15: HANDLE hToken = NULL;
16: // Legge il token del processo attuale
17: if(OpenProcessToken(GetCurrentProcess(),
18: TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT |
19: TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY,
20: &hToken))
21: {
22: HANDLE hNewToken = NULL;
23: // duplica il token per poterlo modificare
24: if(DuplicateTokenEx(hToken,
25: MAXIMUM_ALLOWED,
26: NULL,
27: SecurityImpersonation,
28: TokenPrimary,
29: &hNewToken))
30: {
31: PSID pIntegritySid = NULL;
32: // converte la stringa del sid in struttura binaria
33: if(ConvertStringSidToSid(IntegritySid, &pIntegritySid))
34: {
35: TOKEN_MANDATORY_LABEL TIL = {0};
36: TIL.Label.Attributes = SE_GROUP_INTEGRITY;
37: TIL.Label.Sid = pIntegritySid;
38:
39: // Modifica l'integrity level del nuovo token
40: if(SetTokenInformation(hNewToken, TokenIntegrityLevel, &TIL,
41: sizeof(TOKEN_MANDATORY_LABEL)))
42: {
43: PROCESS_INFORMATION ProcInformation = {0};
44: STARTUPINFO StartupInfo = {0};
45: StartupInfo.cb = sizeof(StartupInfo);
46:
47: // crea il processo con il nuovo token
48: if(CreateProcessAsUser(hNewToken,
49: PathName.c_str(),
50: const_cast<wchar_t*>(CommandLine.c_str()),
51: NULL,
52: NULL,
53: FALSE,
54: 0,
55: NULL,
56: NULL,
57: &StartupInfo,
58: &ProcInformation))
59: {
60: if (ProcInformation.hProcess != NULL)
61: CloseHandle(ProcInformation.hProcess);
62:
63: if (ProcInformation.hThread != NULL)
64: CloseHandle(ProcInformation.hThread);
65: }
66: else
67: LastError = ::GetLastError();
68: }
69: else
70: LastError = ::GetLastError();
71: LocalFree(pIntegritySid);
72: }
73: else
74: LastError = ::GetLastError();
75: CloseHandle(hNewToken);
76: }
77: else
78: LastError = ::GetLastError();
79: CloseHandle(hToken);
80: }
81: else
82: LastError = ::GetLastError();
83:
84: return LastError;
85: }
Il listato è in C++ perché non ci sono chiamate pronte nel Framework.NET. Ovviamente le stesse cose si possono fare creando le corrispondenti chiamate PInvoke.
In alternativa è sufficiente impostare il file dell'exe con un Integrity Level "low" e di conseguenza al suo avvio il token sarà automaticamente a quello stesso livello.
Impostare a low un file
Per fare le prove consiglio di copiare il file notepad.exe in una cartella temporanea.
Si può cambiare l'integrity level di un file con l'utility ICACLS:
icacls notepad.exe /setintegritylevel L
Per leggere l'integrity level non è necessario il prompt elevato e il risultato è:
C:\Temp>icacls notepad.exe
notepad.exe XYZ\Raf:(I)(F)
BUILTIN\Administrators:(I)(F)
NT AUTHORITY\SYSTEM:(I)(F)
BUILTIN\Users:(I)(RX)
Mandatory Label\Low Mandatory Level:(NW)
Successfully processed 1 files; Failed processing 0 files
Io mi sono costruitio una mia utility per modificare i token e posso impostare l'integrity level ad un numero arbitrario, non solo ai livelli prefissati nell'sdk.
Se un file viene impostato ad un valore non predeterminato nell'SDK, ICACLS non mostra il numero esatto.
Per esempio uso la mia utility RafToken per impostare il livello 4095 (Low è 4096), ma poi ICACLS mi dice che non è riuscito a mappare il numero 4095 in uno degli Integrity Level noti.
C:\Temp>debug\raftoken -i 4095 notepad.exe
C:\Temp>icacls notepad.exe
notepad.exe XYZ\Raf:(I)(F)
BUILTIN\Administrators:(I)(F)
NT AUTHORITY\SYSTEM:(I)(F)
BUILTIN\Users:(I)(RX)
No mapping between account names and security IDs was done.
(NW,NR,NX)
Successfully processed 1 files; Failed processing 0 files
Questa operazione non è affatto illegale. È solo l'utility ICACLS che non mostra il valore numerico. L'integrity Level alla fine dei conti è solo un numero a 16 bit e quindi qualsiasi valore è valido. Ovviamente il sistema operativo ha dei valori noti a cui fa riferimento.
Impostare a low un oggetto kernel (come un file) via API
- Creare una stringa SDDL con le opzioni desiderate
Per esempio "S:(ML;;NWNRNX;;;S-1-16-4096)" imposta
- no-write-up (NW), no-read-up (NR), no-execute-up (NX) e level 4096 cioè medium
(ML è l'acronimo di Mandatory Label, usato in MSDN per indicare la struttura che contiene le informazioni relative agli Integriry Level e Policy)
- Aprire il file per ottenerne l'handle (GENERIC_READ | GENERIC_WRITE | WRITE_DAC | WRITE_OWNER)
- Chiamare ConvertStringSecurityDescriptorToSecurityDescriptor per creare un security descriptor binario a partire dalla stringa SDDL
- Chiamare GetSecurityDescriptorSacl per ottenere la SACL a partire dal security descriptor appena ottenuto
- Chiamare SetSecurityInfo specificando come object type "SE_KERNEL_OBJECT", come security information "LABEL_SECURITY_INFORMATION" e infine la SACL nell'ultimo parametro.
Le SACL sono nate per ospitare le informazioni sull'auditing degli oggetti e sono accessibili solo dagli administrators.
Il mio target era invece quello di poter modificare gli integrity level / policy senza richiedere l'elevazione con UAC.
Il "trucco" sta nell'API SetSecurityInfo con parametro "LABEL_SECURITY_INFORMATION". Impostando le SACL con altre API l'operazione fallirebbe con un accesso negato e sarebbe perciò necessario elevare il processo ad administrator.
Il listato per questa sequenza di chiamate è più lungo e il blog non mi sembra il posto più indicato dove farlo. Ad ogni modo le chiamate sopra citate fanno parte della mia utility (scritta in C++) e quindi sono assolutamente collaudate. Basta un minimo di pazienza e il gioco è fatto.
La lettura degli integrity level è del tutto analoga e consiste nel chiamare GetSecurityInfo con "LABEL_SECURITY_INFORMATION" ottenendo le Sacl da cui estrarre le ACE di tipo "SYSTEM_MANDATORY_LABEL_ACE_TYPE" che contengono le informazioni su Integrity Level e Policy.
Tool: AccessChk
AccessChk di Mark Russinovich permette di verificare l'accesso ad un oggetto e mostrare la relativa security. Per esempio nel caso del file di notepad a cui abbiamo modificato l'Integrity Level a Low, ecco il risultato:
C:\Temp>c:\util\SysinternalsSuite\accesschk -e notepad.exe
Accesschk v4.20 - Reports effective permissions for securable objects
Copyright (C) 2006-2008 Mark Russinovich
Sysinternals - www.sysinternals.com
C:\Temp\notepad.exe
Low Mandatory Level [No-Write-Up, No-Read-Up, No-Execute-Up]
RW XYZ\Raf
RW BUILTIN\Administrators
RW NT AUTHORITY\SYSTEM
R BUILTIN\Users
Tool: Process Explorer
Process Explorer è il famoso tool sempre della suite SysInternals, che forinisce centinaia di informazioni interessanti. Tra queste possiamo vedere l'Integrity Level nel token del processo di Notepad che abbiamo lanciato grazie al primo listato del post.
Lo stesso "Low Mandatory Label" sarebbe visibile nel processo di Internet Explorer in Protected Mode.
Gli Integrity Levels sono il mattoncino per un'altra novità fondamentale in Vista che è UIPI.
[more to come ...]
Parte 4: http://blogs.ugidotnet.org/raffaele/archive/2009/02/09/windows-vista-uipi-parte-4.aspx
Era il 1989 e il grande Doc, non conoscendo ancora la nuova generazione di utenti, diceva: "È meglio che mi dedichi a studiare l'altro grande mistero dell'universo... le donne.".
Da allora i geek sono stati sopraffatti da una nuova specie: gli utenti.
Utente è colui che quando vede una mail con scritto "hai vinto" ... clicca; compra dozzine di pillole di tutti i colori; è il rarissimo vincitore ... di una partecipazione a giocare d'azzardo (?); sente la necessità di "allargarsi"; ...
Ma spazia anche oltre perché l'Utente ha sempre detto di detestare il PC e tutto ciò che è tecnologico ma (c'è sempre un ma) non appena ha capito che esisteva il P2P e poteva scroccare film e musica ha imparato ad usare, installare, etc. etc. Ma siccome non è tutto oro quello che luccica, anche a incriccarsi il PC e chiamare il cugino del cugino per sistemarlo.
L'Utente ha fiducia cieca nell'antivirus, e mentre gira gli sembra di vedere il Dr Welby che fa uno dei suoi miracoli.
Così scarica il mondo di applicazioni incriccate, le avvia e gli tocca rivolgersi al Dr Quincy perché gli antivirus sono arrivati al capolinea e molto presto non serviranno più a nulla. A quelli che non ci credono mi possono portare il PC così gli creo "ad hoc" un virus su misura e sconosciuto agli antivirus: nella richiesta si prega di specificare se è per Windows 9x, XP, Linux (specificare la distro), FreeBsd o la variante Mac.
A questo Utente è stata offerta la UAC che ricorda all'utente che l'operazione che sta facendo può modificare in qualche modo la stabilità del sistema operativo. UAC è un modo per rendere consapevole l'utente che esiste un rischio diretto o indiretto nell'operazione che ha chiesto di eseguire. UAC permette tutto questo senza richiedere la password come invece accade nei sistemi *nix con Sudo.
Ma l'Utente aveva ancora memoria dell'istinto primordiale di quando odiava la tecnologia, di quando non voleva neppure capire come funzionasse, e anche se l'era pre-P2P era già passata da un pezzo, Vista evidenziò il lato schizzinoso dell'Utente.
E l'Utente dapprima rigettò Vista ma per avere, come accadeva a Camogli, il 'diritto al mugugno' cambiò idea, prese Vista e rigettò UAC.
E così Microsoft decise di ascoltare l'Utente e di introdurre in Windows 7 una diabolica slider che diminuisce il numero di volte in cui la UAC avverte l'utente. Le applicazioni parte del sistema operativo avrebbero taciuto.
Ma non si erano bevuti il cervello all'epoca di Vista, non era sbagliato chiedere all'Utente *sempre* il permesso. E infatti puntualmente le conseguenze: http://www.istartedsomething.com/20090130/uac-security-flaw-windows-7-beta-proof/
A quanto sembra Microsoft dice che è "by design". Mai avrei potuto essere più daccordo.
Microsoft ascolta gli "Utenti"? Per favore prima facciamo un distinguo su quali U/utenti andrebbero ascoltati.
I misteri di Doc oltre che misteriosi sono affascinanti, chiedo scusa alle donne per aver mischiato il fascino con il profano.