windows - 高完整性 token 是否*必须*启用管理员组?

标签 windows uac

启用 UAC 并使用管理帐户登录后,您将获得两个 token :

  • 提升的 token ;这已启用 Administrators 组,具有高完整性(即强制性完整性标签 SID 为 S-1-16-12288)并且具有提升类型 TokenElevationTypeFull。

  • 有限的代币;这已禁用 Administrators 组,具有中等完整性 (S-1-16-8192) 并且具有提升类型 TokenElevationTypeLimited。

这三个因素总是以这种方式匹配吗?也就是说,内核是否要求只有启用 Administrators 组的 token 才能具有高完整性和/或 TokenElevationTypeFull?

是否存在进程不具有管理员权限但会以高完整性和/或 TokenElevationTypeFull 运行的任何情况?

(问题的基本原理:答案会影响程序员安全测试提升权限的方式。例如,it came up here。)

最佳答案

不,内核不要求 token 的完整性级别和提升类型与管理员组的状态相匹配。这意味着具有高完整性级别或 TokenElevationTypeFull 的进程不一定具有管理员访问权限。

特别是请注意,在管理命令提示符下使用 runas/truSTLevel:0x20000 将导致进程没有管理员权限,但仍然以高完整性运行并且(如果启用了 UAC)将具有 TokenElevationTypeFull。 ( As discovered here. ) 我相信这表示 runas 中的错误。

2022 年 10 月附录:我怀疑 runas 中的错误是它只允许您指定某些完整性级别,并弄错了! 中等完整性是 0x2000,不是 0x20000。

此示例代码演示了该行为;如果以管理员权限运行,它会启动一个禁用管理员组(以及除 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

正如预期的那样,受限 token 如下所示:

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 上运行。)

关于windows - 高完整性 token 是否*必须*启用管理员组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30970433/

相关文章:

windows - Windows 10 上的环境变量太大

windows - Docker Windows 构建失败并出现错误 : "The system cannot find the path specified"

windows - bat-Script : execute command, 重新打开cmd并执行另一个命令

c++ - 我如何从同意流程 (UAC) 获取流程路径或 pid

vb6 - UAC 给我的应用程序带来问题

vb.net - 如何向我的 VB.NET 应用程序添加 list (用于 UAC 支持)?

security - Win32 : bypassing UAC using user/password

windows - 如何在 Git Bash for windows 中更改 RGB 颜色?

windows - 在上午 9 点之前运行的 Bat 文件会给出错误,无效数字。数字常量是十进制 (17),

c# - 确定对应用程序文件夹的写入权限