У линок с высокой степенью целостности * есть *, чтобы включить группу "Администраторы"?

Когда UAC включен, и вы входите в систему с учетной записью администратора, вы получаете два токена:

  • повышенный токен; это имеет включенную группу "Администраторы" , имеет высокую целостность (т.е. идентификатор обязательной целостности SID - S-1-16-12288) и имеет тип отметки TokenElevationTypeFull.

  • ограниченный токен; это отключает группу "Администраторы" , имеет среднюю целостность (S-1-16-8192) и имеет тип отметки TokenElevationTypeLimited.

Соответствуют ли эти три фактора таким образом? То есть, требует ли ядро, чтобы только токены с включенной группой "Администраторы" могли иметь высокую целостность и/или TokenElevationTypeFull?

Существуют ли какие-либо обстоятельства, при которых процесс не будет иметь привилегий администратора, но будет работать с высокой степенью целостности и/или TokenElevationTypeFull?

(Обоснование вопроса: ответ влияет на то, как программист может безопасно тестировать повышенные привилегии. Например, он появился здесь.)

Ответ 1

Нет, ядро ​​не требует, чтобы уровень целостности и тип отметки совпадали со статусом группы "Администраторы". Это означает, что процесс с высоким уровнем целостности или TokenElevationTypeFull не обязательно имеет доступ администратора.

В частности, обратите внимание, что использование runas /trustlevel:0x20000 из командной строки администрирования приведет к процессу, который не имеет прав администратора, но тем не менее работает с высокой степенью целостности и (если UAC включен) будет иметь TokenElevationTypeFull. (Как обнаружено здесь.) Я считаю, что это ошибка в 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 с пакетом обновления 1 (SP1) x64.)