高完整性令牌是否*必须*启用管理员组?
Do high-integrity tokens *have* to have the Administrators group enabled?
启用 UAC 并使用管理帐户登录后,您将获得两个令牌:
提升令牌;这已启用管理员组,具有高完整性(即强制性完整性标签 SID 为 S-1-16-12288)并且具有提升类型 TokenElevationTypeFull。
限量代币;这已禁用管理员组,中等完整性 (S-1-16-8192) 并且具有提升类型 TokenElevationTypeLimited。
这三个因素总是这样匹配吗?即内核是否要求只有启用了Administrators组的token才能具有高完整性and/orTokenElevationTypeFull?
是否存在进程不具有管理员权限但 运行 高度完整性 and/or TokenElevationTypeFull 的情况?
(问题的基本原理:答案会影响程序员安全测试提升权限的方式。例如,it came up here。)
不,内核不要求令牌的完整性级别和提升类型与管理员组的状态匹配。这意味着具有高完整性级别或 TokenElevationTypeFull
的进程不一定具有管理员访问权限。
特别是,请注意,在管理命令提示符下使用 runas /trustlevel:0x20000
将导致进程没有管理员权限,但仍然 运行s具有高完整性并且(如果启用 UAC)将具有 TokenElevationTypeFull
。 (As discovered here.) 我认为这是 runas
.
中的错误
此示例代码演示了该行为;如果 运行 具有管理员权限,它会启动一个禁用管理员组(以及除 SeChangeNotifyPrivilege
之外的所有权限)的子进程,但它仍然是 运行 高完整性和 TokenElevationTypeFull
.
#include <Windows.h>
#include <Sddl.h>
#include <stdio.h>
PSID admins_sid;
void get_membership(HANDLE token)
{
BOOL is_enabled;
HANDLE itoken;
if (!DuplicateToken(token, SecurityIdentification, &itoken))
{
printf("DuplicateToken: %u\n", GetLastError());
return;
}
if (!CheckTokenMembership(itoken, admins_sid, &is_enabled))
{
printf("CheckTokenMembership: %u\n", GetLastError());
CloseHandle(itoken);
return;
}
CloseHandle(itoken);
printf("Administrators group enabled: %u\n", is_enabled);
return;
}
void get_integrity(HANDLE token)
{
char buffer[4096];
char * stringsid;
TOKEN_MANDATORY_LABEL *token_mandatory_label = (TOKEN_MANDATORY_LABEL *)buffer;
DWORD dw;
if (!GetTokenInformation(token, TokenIntegrityLevel, buffer, sizeof(buffer), &dw))
{
printf("GetTokenInformation: %u\n", GetLastError());
return;
}
if (!ConvertSidToStringSidA(token_mandatory_label->Label.Sid, &stringsid))
{
printf("ConvertSidToStringSid: %u\n", GetLastError());
return;
}
printf("SID: %s\n", stringsid);
}
void get_elevation(HANDLE token)
{
TOKEN_ELEVATION_TYPE elevation;
DWORD dw;
if (!GetTokenInformation(token,
TokenElevationType, &elevation, sizeof(elevation), &dw))
{
printf("GetTokenInformation: %u\n", GetLastError());
return;
}
printf("Elevation type : %u\n", (DWORD)elevation);
}
void test(void)
{
HANDLE token1, token2;
SID_AND_ATTRIBUTES sids_to_disable;
STARTUPINFOA si = {sizeof(STARTUPINFOA)};
PROCESS_INFORMATION pi;
if (!OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token1))
{
printf("OpenProcessToken: %u\n", GetLastError());
return;
}
printf("token1:\n");
get_membership(token1);
get_integrity(token1);
get_elevation(token1);
sids_to_disable.Attributes = 0;
sids_to_disable.Sid = admins_sid;
if (!CreateRestrictedToken(token1,
DISABLE_MAX_PRIVILEGE, 1, &sids_to_disable, 0, NULL, 0, NULL, &token2))
{
printf("CreateRestrictedToken: %u\n", GetLastError());
return;
}
printf("token2:\n");
get_membership(token2);
get_integrity(token2);
get_elevation(token2);
if (!CreateProcessAsUserA(token2,
NULL, "cmd", NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
printf("CreateProcessAsUser: %u\n", GetLastError());
return;
}
}
int main(int argc, char ** argv)
{
{
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
if(! AllocateAndInitializeSid( &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&admins_sid) )
{
printf( "AllocateAndInitializeSid: %u\n", GetLastError());
return 1;
}
}
test();
return 0;
}
从提升的命令提示符 运行 时输出:
token1:
Administrators group enabled: 1
SID: S-1-16-12288
Elevation type : 2
token2:
Administrators group enabled: 0
SID: S-1-16-12288
Elevation type : 2
如果您从子进程中再次运行示例代码,您可以确认子进程确实保留了这些属性:
token1:
Administrators group enabled: 0
SID: S-1-16-12288
Elevation type : 2
如果禁用 UAC,则提升类型为 TokenElevationTypeDefault,否则结果相同:
token1:
Administrators group enabled: 1
SID: S-1-16-12288
Elevation type : 1
token2:
Administrators group enabled: 0
SID: S-1-16-12288
Elevation type : 1
正如预期的那样,受限令牌如下所示:
token1:
Administrators group enabled: 0
SID: S-1-16-8192
Elevation type : 3
或者如果您以非管理员用户身份登录,无论 UAC 是否启用:
token1:
Administrators group enabled: 0
SID: S-1-16-8192
Elevation type : 1
(Windows 7 SP1 x64 上的所有测试 运行。)
启用 UAC 并使用管理帐户登录后,您将获得两个令牌:
提升令牌;这已启用管理员组,具有高完整性(即强制性完整性标签 SID 为 S-1-16-12288)并且具有提升类型 TokenElevationTypeFull。
限量代币;这已禁用管理员组,中等完整性 (S-1-16-8192) 并且具有提升类型 TokenElevationTypeLimited。
这三个因素总是这样匹配吗?即内核是否要求只有启用了Administrators组的token才能具有高完整性and/orTokenElevationTypeFull?
是否存在进程不具有管理员权限但 运行 高度完整性 and/or TokenElevationTypeFull 的情况?
(问题的基本原理:答案会影响程序员安全测试提升权限的方式。例如,it came up here。)
不,内核不要求令牌的完整性级别和提升类型与管理员组的状态匹配。这意味着具有高完整性级别或 TokenElevationTypeFull
的进程不一定具有管理员访问权限。
特别是,请注意,在管理命令提示符下使用 runas /trustlevel:0x20000
将导致进程没有管理员权限,但仍然 运行s具有高完整性并且(如果启用 UAC)将具有 TokenElevationTypeFull
。 (As discovered here.) 我认为这是 runas
.
此示例代码演示了该行为;如果 运行 具有管理员权限,它会启动一个禁用管理员组(以及除 SeChangeNotifyPrivilege
之外的所有权限)的子进程,但它仍然是 运行 高完整性和 TokenElevationTypeFull
.
#include <Windows.h>
#include <Sddl.h>
#include <stdio.h>
PSID admins_sid;
void get_membership(HANDLE token)
{
BOOL is_enabled;
HANDLE itoken;
if (!DuplicateToken(token, SecurityIdentification, &itoken))
{
printf("DuplicateToken: %u\n", GetLastError());
return;
}
if (!CheckTokenMembership(itoken, admins_sid, &is_enabled))
{
printf("CheckTokenMembership: %u\n", GetLastError());
CloseHandle(itoken);
return;
}
CloseHandle(itoken);
printf("Administrators group enabled: %u\n", is_enabled);
return;
}
void get_integrity(HANDLE token)
{
char buffer[4096];
char * stringsid;
TOKEN_MANDATORY_LABEL *token_mandatory_label = (TOKEN_MANDATORY_LABEL *)buffer;
DWORD dw;
if (!GetTokenInformation(token, TokenIntegrityLevel, buffer, sizeof(buffer), &dw))
{
printf("GetTokenInformation: %u\n", GetLastError());
return;
}
if (!ConvertSidToStringSidA(token_mandatory_label->Label.Sid, &stringsid))
{
printf("ConvertSidToStringSid: %u\n", GetLastError());
return;
}
printf("SID: %s\n", stringsid);
}
void get_elevation(HANDLE token)
{
TOKEN_ELEVATION_TYPE elevation;
DWORD dw;
if (!GetTokenInformation(token,
TokenElevationType, &elevation, sizeof(elevation), &dw))
{
printf("GetTokenInformation: %u\n", GetLastError());
return;
}
printf("Elevation type : %u\n", (DWORD)elevation);
}
void test(void)
{
HANDLE token1, token2;
SID_AND_ATTRIBUTES sids_to_disable;
STARTUPINFOA si = {sizeof(STARTUPINFOA)};
PROCESS_INFORMATION pi;
if (!OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token1))
{
printf("OpenProcessToken: %u\n", GetLastError());
return;
}
printf("token1:\n");
get_membership(token1);
get_integrity(token1);
get_elevation(token1);
sids_to_disable.Attributes = 0;
sids_to_disable.Sid = admins_sid;
if (!CreateRestrictedToken(token1,
DISABLE_MAX_PRIVILEGE, 1, &sids_to_disable, 0, NULL, 0, NULL, &token2))
{
printf("CreateRestrictedToken: %u\n", GetLastError());
return;
}
printf("token2:\n");
get_membership(token2);
get_integrity(token2);
get_elevation(token2);
if (!CreateProcessAsUserA(token2,
NULL, "cmd", NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
printf("CreateProcessAsUser: %u\n", GetLastError());
return;
}
}
int main(int argc, char ** argv)
{
{
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
if(! AllocateAndInitializeSid( &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&admins_sid) )
{
printf( "AllocateAndInitializeSid: %u\n", GetLastError());
return 1;
}
}
test();
return 0;
}
从提升的命令提示符 运行 时输出:
token1:
Administrators group enabled: 1
SID: S-1-16-12288
Elevation type : 2
token2:
Administrators group enabled: 0
SID: S-1-16-12288
Elevation type : 2
如果您从子进程中再次运行示例代码,您可以确认子进程确实保留了这些属性:
token1:
Administrators group enabled: 0
SID: S-1-16-12288
Elevation type : 2
如果禁用 UAC,则提升类型为 TokenElevationTypeDefault,否则结果相同:
token1:
Administrators group enabled: 1
SID: S-1-16-12288
Elevation type : 1
token2:
Administrators group enabled: 0
SID: S-1-16-12288
Elevation type : 1
正如预期的那样,受限令牌如下所示:
token1:
Administrators group enabled: 0
SID: S-1-16-8192
Elevation type : 3
或者如果您以非管理员用户身份登录,无论 UAC 是否启用:
token1:
Administrators group enabled: 0
SID: S-1-16-8192
Elevation type : 1
(Windows 7 SP1 x64 上的所有测试 运行。)