I'm running the following snippet of code in my user-mode process that starts up when a Windows user account logs in to the workstation. Or, in other words, its path is placed in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
registry key.
The code is supposed to determine the mandatory integrity level of my user process. It goes as such:
DWORD getMIL()
{
//Try to get integrity level
//-1 Unknown
//SECURITY_MANDATORY_UNTRUSTED_RID 0x00000000 Untrusted.
//SECURITY_MANDATORY_LOW_RID 0x00001000 Low integrity.
//SECURITY_MANDATORY_MEDIUM_RID 0x00002000 Medium integrity.
//SECURITY_MANDATORY_MEDIUM_PLUS_RID SECURITY_MANDATORY_MEDIUM_RID + 0x100 Medium high integrity.
//SECURITY_MANDATORY_HIGH_RID 0X00003000 High integrity.
//SECURITY_MANDATORY_SYSTEM_RID 0x00004000 System integrity.
//SECURITY_MANDATORY_PROTECTED_PROCESS_RID 0x00005000 Protected process.
DWORD dwIntgtyLvl = -1;
HANDLE hToken;
if(OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
DWORD dwSizeIntgtyLvl = 0;
if(!GetTokenInformation(hToken, TokenIntegrityLevel, NULL, dwSizeIntgtyLvl, &dwSizeIntgtyLvl) &&
::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
BYTE* pbIntgtyLvl = new BYTE[dwSizeIntgtyLvl];
if(pbIntgtyLvl)
{
TOKEN_MANDATORY_LABEL* pTML = (TOKEN_MANDATORY_LABEL*)pbIntgtyLvl;
DWORD dwSizeIntgtyLvl2;
if(GetTokenInformation(hToken, TokenIntegrityLevel, pTML, dwSizeIntgtyLvl, &dwSizeIntgtyLvl2) &&
dwSizeIntgtyLvl2 <= dwSizeIntgtyLvl)
{
dwIntgtyLvl = *GetSidSubAuthority(pTML->Label.Sid,
(DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTML->Label.Sid)-1));
}
//Free mem
delete[] pbIntgtyLvl;
pbIntgtyLvl = NULL;
}
}
::CloseHandle(hToken);
}
return dwIntgtyLvl;
}
In a normal flow of events I'd expect to get the value of 0x2000
for SECURITY_MANDATORY_MEDIUM_RID
, or 0x3000
for SECURITY_MANDATORY_HIGH_RID
, but if I have one Windows user account already logged in, and if I then switch users, and log in with another user account, the method above will get me the value of 0x2010
for the mandatory integrity level.
Does anyone know what that value stands for?
You are not taking into account that integrity levels use value ranges, where a token/process can be assigned a value within a range of values for its integrity level. You are looking for specific values only.
Untrusted integrity can be any value between SECURITY_MANDATORY_UNTRUSTED_RID
(inclusive) and SECURITY_MANDATORY_LOW_RID
(non-inclusive).
Low integrity can be any value between SECURITY_MANDATORY_LOW_RID
(inclusive) and SECURITY_MANDATORY_MEDIUM_RID
(non-inclusive).
Medium integrity can be any value between SECURITY_MANDATORY_MEDIUM_RID
(inclusive) and SECURITY_MANDATORY_HIGH_RID
(non-inclusive). Which is what you are seeing in your example.
High integrity can be any value between SECURITY_MANDATORY_HIGH_RID
(inclusive) and SECURITY_MANDATORY_SYSTEM_RID
(non-inclusive).
Any value at or above SECURITY_MANDATORY_SYSTEM_RID
is reserved for the system.
There is a table in the documentation showing this:
Windows Integrity Mechanism Design
Table 2 Defined integrity levels and corresponding values Value Description Symbol 0x0000 Untrusted level SECURITY_MANDATORY_UNTRUSTED_RID 0x1000 Low integrity level SECURITY_MANDATORY_LOW_RID 0x2000 Medium integrity level SECURITY_MANDATORY_MEDIUM_RID 0x3000 High integrity level SECURITY_MANDATORY_HIGH_RID 0x4000 System integrity level SECURITY_MANDATORY_SYSTEM_RID