I have an application that needs to register controls when it is Run As Administrator and I would like the application to drop the elevated privileges when they are no longer needed. I have read that this can be done with AdjustTokenPrivileges, (Dropping privileges in C++ on Windows) but I have not found any sample code that will allow me to go from SECURITY_MANDATORY_HIGH_RID to SECURITY_MANDATORY_MEDIUM_RID. My code is written C++ using Visual Studio.
if you want
sample code that will allow me to go from SECURITY_MANDATORY_HIGH_RID to SECURITY_MANDATORY_MEDIUM_RID.
you need open own process token with TOKEN_ADJUST_DEFAULT (for change integrity level - this is mandatory) and WRITE_OWNER (for change mandatory label in your token security descriptor - otherwise you not be able more open own token with write access more - but this is optional)
call SetTokenInformation with TokenIntegrityLevel let downgrade current integrity level. after this it already can not be raised.
also internally system disable some privileges in token, when we set integrity level below SECURITY_MANDATORY_HIGH_RID. i doubt that this is documented, but from my test, next privileges is disabled and can not be more enabled:
SeTakeOwnershipPrivilege
SeLoadDriverPrivilege
SeBackupPrivilege
SeRestorePrivilege
SeDebugPrivilege
SeImpersonatePrivilege
SeDelegateSessionUserImpersonatePrivilege
but you still will be member of admin group (S-1-5-32-544 Administrators) and this group can not be disabled by AdjustTokenGroups because function cannot disable groups with the SE_GROUP_MANDATORY attribute - but S-1-5-32-544 have this attribute. and change primary process token also not possible already (it possible only after process created (in suspended state) and before it begin executed (resumed) if we have SeAssignPrimaryTokenPrivilege )
so really your application will be in intermediate state after downgrade integrity level to medium - from one side you lost most significant privileges, but access to objects (files, registry keys) primary based not on privileges but group membership and mandatory label - vs integrity level. because Administrators group still will be enabled in your token and most objects not have explicit mandatory label (so medium by default) - your app still be able open/create files/keys which limited applications (admin under uac) can not. however if you downgrade you integrity level to SECURITY_MANDATORY_LOW_RID - you really got limited application, but most legacy code incorrect worked under LowLevel integrity
minimal code for downgrade integrity level:
ULONG SetMediumLevel()
{
HANDLE hToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_DEFAULT, &hToken))
{
ULONG cbSid = GetSidLengthRequired(1);
TOKEN_MANDATORY_LABEL tml = { { alloca(cbSid)} };
ULONG dwError = NOERROR;
if (!CreateWellKnownSid(WinMediumLabelSid, 0, tml.Label.Sid, &cbSid) ||
!SetTokenInformation(hToken, TokenIntegrityLevel, &tml, sizeof(tml)))
{
dwError = GetLastError();
}
CloseHandle(hToken);
return dwError;
}
return GetLastError();
}
but here exist thin point - token itself have security descriptor with explicit label. and high integrity process have High Mandatory Label with SYSTEM_MANDATORY_LABEL_NO_WRITE_UP access policy. this mean that we no more can open our process token with write access (TOKEN_ADJUST_* ) (with read access can). this can create problems if app in some place try open self process token with this access (some bad design code can when need query own process token properties instead TOKEN_QUERY access ask TOKEN_ALL_ACCESS and fail in this point). for prevent this potential issue we can change mandatory label of our token security descriptor before downgrade it integrity:
ULONG SetMediumLevel()
{
HANDLE hToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_DEFAULT|WRITE_OWNER, &hToken))
{
ULONG cbSid = GetSidLengthRequired(1);
TOKEN_MANDATORY_LABEL tml = { { alloca(cbSid)} };
ULONG dwError = NOERROR;
if (CreateWellKnownSid(WinMediumLabelSid, 0, tml.Label.Sid, &cbSid))
{
SECURITY_DESCRIPTOR sd;
ULONG cbAcl = sizeof(ACL) + FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + cbSid;
PACL Sacl = (PACL)alloca(cbAcl);
if (!InitializeAcl(Sacl, cbAcl, ACL_REVISION) ||
!AddMandatoryAce(Sacl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, tml.Label.Sid) ||
!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) ||
!SetSecurityDescriptorSacl(&sd, TRUE, Sacl, FALSE) ||
!SetKernelObjectSecurity(hToken, LABEL_SECURITY_INFORMATION, &sd) ||
!SetTokenInformation(hToken, TokenIntegrityLevel, &tml, sizeof(tml)))
{
dwError = GetLastError();
}
}
CloseHandle(hToken);
return dwError;
}
return GetLastError();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With