如果你愿意
允许我从 SECURITY_MANDATORY_HIGH_RID 开始的示例代码
SECURITY_MANDATORY_MEDIUM_RID。
您需要使用TOKEN_ADJUST_DEFAULT(用于更改完整性级别-这是强制性的)和WRITE_OWNER(用于更改您的令牌安全描述符中的强制性标签-否则您将无法打开自己的进程令牌以写入访问权限)更多 - 但这是可选的)
调用SetTokenInformation 和TokenIntegrityLevel 让当前的完整性级别降级。在此之后它已经无法提高。
当我们将完整性级别设置为低于SECURITY_MANDATORY_HIGH_RID 时,系统也会在内部禁用令牌中的某些权限。我怀疑这是否已记录在案,但从我的测试来看,下一个权限已被禁用并且无法再启用:
SeTakeOwnershipPrivilege
SeLoadDriverPrivilege
SeBackupPrivilege
SeRestorePrivilege
SeDebugPrivilege
SeImpersonatePrivilege
SeDelegateSessionUserImpersonatePrivilege
但您仍将是管理员组的成员(S-1-5-32-544 管理员),并且此组不能被 AdjustTokenGroups 禁用,因为函数无法使用 @ 禁用组987654330@ 属性 - 但 S-1-5-32-544 具有此属性。并且更改主进程令牌也是不可能的(如果我们有SeAssignPrimaryTokenPrivilege,只有在进程创建之后(处于挂起状态)和它开始执行(恢复)之前才有可能)
所以在将完整性级别降级到 medium 后,您的应用程序实际上将处于中间状态 - 从一方面您失去了最重要的特权,但对对象(文件、注册表项)的访问主要不是基于特权但组成员身份和强制性标签 - 与完整性级别。因为 Administrators 组仍将在您的令牌中启用,并且大多数对象没有明确的强制标签(默认为中等)-您的应用程序仍然能够打开/创建限制应用程序的文件/键(uac 下的管理员) 不能。但是,如果您将完整性级别降级为SECURITY_MANDATORY_LOW_RID - 您的应用程序确实有限,但大多数遗留代码在低级完整性下工作不正确
降级完整性级别的最少代码:
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();
}
但这里存在薄弱点 - 令牌本身具有带有显式标签的安全描述符。和高完整性进程具有High Mandatory Label 和SYSTEM_MANDATORY_LABEL_NO_WRITE_UP 访问策略。这意味着我们不能再以写访问权限(TOKEN_ADJUST_*)(读访问权限可以)打开我们的进程令牌。如果应用程序在某个地方尝试使用此访问权限打开自我进程令牌,这可能会产生问题(一些糟糕的设计代码可以在需要查询自己的进程令牌属性而不是 TOKEN_QUERY 访问时询问 TOKEN_ALL_ACCESS 并在这一点上失败)。为了防止这个潜在问题,我们可以在降级之前更改令牌安全描述符的强制标签完整性:
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();
}