2015-06-21 93 views
3

当UAC被启用,您使用管理帐户登录,你会得到两个令牌:高完整性令牌*是否已启用管理员组?

  • 的提升令牌;这启用了管理员组,具有高完整性(即,强制完整性标签SID是S-1-16-12288)并且具有提升类型TokenElevationTypeFull。

  • 有限令牌;这使管理员组被禁用,中等完整性(S-1-16-8192)并且具有海拔类型TokenElevationTypeLimited。

这三个因素是否总是以这种方式匹配?也就是说,内核是否需要只有启用管理员组的令牌可以具有较高的完整性和/或TokenElevationTypeFull?

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

(理由的问题:答案会影响其中一个程序员可以安全地测试提升权限的方式。例如,it came up here。)

回答

2

没有,内核不需要完整性级别和升降式的令牌与管理员组的状态相匹配。这意味着具有高完整性级别或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 SP1 x64上运行。)

+0

这在Windows 10 x64中对我来说是崩溃的。错误代码是'STATUS_DLL_INIT_FAILED'。它发生在conhost.exe执行时,但在创建新窗口之前。我检查了子cmd.exe和conhost.exe进程都将Administrators组设置为只拒绝和高完整性。这可能是Windows 10中的一个错误,或者表明一个假设某个高完整性进程具有管理员权限。我的Windows 10版本过时(10.0.10074);它可能在更新的版本中工作。 – eryksun

+0

@eryksun:你的意思是cmd.exe的子实例崩溃?听起来像是与桌面/窗口站的权限有关。 (如果您不使用CREATE_NEW_CONSOLE,是否仍然会崩溃,让它继承现有的控制台?)我已经在家里安装了最新的Windows 10安装程序,如果我有时间我会在今晚尝试它。 –

+0

肯定是由于创建了一个新的控制台。就像我说的,当新的conhost.exe实例启动时,子cmd.exe失败(可能是kernelbase的初始化,但我没有检查)。如果我删除了'CREATE_NEW_CONSOLE'并等待进程句柄,那就好了。 – eryksun

相关问题