Do high-integrity tokens *have* to have the Administrators group enabled?

前端 未结 1 1140
攒了一身酷
攒了一身酷 2020-12-04 00:23

When UAC is enabled, and you log in with an administrative account, you get two tokens:

  • the elevated token; this has the Administrators group enabled, is hi

相关标签:
1条回答
  • 2020-12-04 00:31

    No, the kernel does not require that the integrity level and elevation type of a token match up with the status of the Administrators group. This means that a process having a high integrity level, or TokenElevationTypeFull, does not necessarily have administrator access.

    In particular, note that using runas /trustlevel:0x20000 from an administrative command prompt will result in a process that does not have administrator privilege but nonetheless runs with high integrity and (if UAC is enabled) will have TokenElevationTypeFull. (As discovered here.) I believe this represents a bug in runas.

    This sample code demonstrates the behaviour; if run with admin privilege, it launches a subprocess with the administrators group (and all privileges except SeChangeNotifyPrivilege) disabled but which is still running with high integrity and 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;
    }
    

    Output when run from an elevated command prompt:

    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
    

    If you run the sample code again from the child process, you can confirm that the child process did retain these properties:

    token1:
    Administrators group enabled: 0
    SID: S-1-16-12288
    Elevation type : 2
    

    If UAC is disabled, the elevation type is TokenElevationTypeDefault but otherwise the outcome is the same:

    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
    

    As expected, the limited token looks like this:

    token1:
    Administrators group enabled: 0
    SID: S-1-16-8192
    Elevation type : 3
    

    Or if you're logged in as a non-admin user, whether UAC is enabled or not:

    token1:
    Administrators group enabled: 0
    SID: S-1-16-8192
    Elevation type : 1
    

    (All tests run on Windows 7 SP1 x64.)

    0 讨论(0)
提交回复
热议问题