NtQueryInformationToken
Retrieves a specified class of information about an access token.
Prototype
NTSTATUS NtQueryInformationToken( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, PVOID TokenInformation, ULONG TokenInformationLength, PULONG ReturnLength );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| TokenHandle | HANDLE | in | Handle to the token to query. Must have TOKEN_QUERY access (0x8); some classes need TOKEN_QUERY_SOURCE (0x10). |
| TokenInformationClass | TOKEN_INFORMATION_CLASS | in | Class of information to retrieve, e.g. TokenUser, TokenGroups, TokenPrivileges, TokenIntegrityLevel, TokenElevation. |
| TokenInformation | PVOID | out | Caller-allocated buffer that receives the requested information. |
| TokenInformationLength | ULONG | in | Size in bytes of the TokenInformation buffer. |
| ReturnLength | PULONG | out | Receives the bytes written, or the required size if STATUS_BUFFER_TOO_SMALL is returned. |
Syscall IDs by Windows version
| Windows version | Syscall ID | Build |
|---|---|---|
| Win10 1507 | 0x21 | win10-1507 |
| Win10 1607 | 0x21 | win10-1607 |
| Win10 1703 | 0x21 | win10-1703 |
| Win10 1709 | 0x21 | win10-1709 |
| Win10 1803 | 0x21 | win10-1803 |
| Win10 1809 | 0x21 | win10-1809 |
| Win10 1903 | 0x21 | win10-1903 |
| Win10 1909 | 0x21 | win10-1909 |
| Win10 2004 | 0x21 | win10-2004 |
| Win10 20H2 | 0x21 | win10-20h2 |
| Win10 21H1 | 0x21 | win10-21h1 |
| Win10 21H2 | 0x21 | win10-21h2 |
| Win10 22H2 | 0x21 | win10-22h2 |
| Win11 21H2 | 0x21 | win11-21h2 |
| Win11 22H2 | 0x21 | win11-22h2 |
| Win11 23H2 | 0x21 | win11-23h2 |
| Win11 24H2 | 0x21 | win11-24h2 |
| Server 2016 | 0x21 | winserver-2016 |
| Server 2019 | 0x21 | winserver-2019 |
| Server 2022 | 0x21 | winserver-2022 |
| Server 2025 | 0x21 | winserver-2025 |
Kernel module
Related APIs
Syscall stub
4C 8B D1 mov r10, rcx B8 21 00 00 00 mov eax, 0x21 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
Undocumented notes
NtQueryInformationToken is the read-side counterpart to NtSetInformationToken and what `advapi32!GetTokenInformation` wraps. The SSN has been **stable at `0x21`** from Windows 10 1507 through Windows 11 24H2. The most operationally useful classes for offensive work are `TokenUser` (the user SID), `TokenGroups` (group SIDs — reveals Administrators, BUILTIN\Backup Operators, etc.), `TokenPrivileges`, `TokenStatistics` (contains the LUID needed for `NtFilterToken`-style impersonation linkage), `TokenIntegrityLevel`, `TokenElevation`, and `TokenLinkedToken` (the elevated split-token sibling used by Make-Me-Admin UAC bypasses).
Common malware usage
Implants use NtQueryInformationToken for situational awareness right after landing: are we elevated? are we SYSTEM? what groups do we belong to? what privileges are enabled? `TokenLinkedToken` is the linchpin of the silent Make-Me-Admin UAC bypass family (`AppInfo!RAiLaunchAdminProcess` shortcut chains): a medium-IL admin process queries its own linked token to obtain a high-IL token handle, then duplicates and impersonates without prompting consent.exe. Mimikatz' `token::list` simply enumerates handles and calls NtQueryInformationToken with `TokenUser` and `TokenStatistics`.
Detection opportunities
NtQueryInformationToken is extraordinarily noisy in benign software — every COM call, every shell extension, every `whoami`-style operation hits it. It is not a useful detection on its own. What *is* useful: correlating queries of `TokenLinkedToken` from medium-IL processes followed shortly by NtDuplicateToken + CreateProcessWithTokenW (Make-Me-Admin pattern), or queries of `TokenStatistics` immediately followed by `NtSetInformationThread(ThreadImpersonationToken)` (impersonation chain). The ETW provider `Microsoft-Windows-Kernel-Audit-API-Calls` does not specifically log token queries; defenders typically rely on the EDR's user-mode hook on `ntdll!NtQueryInformationToken`.
Direct syscall examples
asmx64 direct stub (stable SSN 0x21)
NtQueryInformationToken PROC
mov r10, rcx ; TokenHandle
mov eax, 21h ; SSN stable across all builds
syscall
ret
NtQueryInformationToken ENDPcAm I SYSTEM? (TokenUser + well-known SID compare)
// Check if the current token belongs to NT AUTHORITY\SYSTEM.
BOOL IsRunningAsSystem(HANDLE hToken) {
BYTE buf[256];
ULONG ret = 0;
if (!NT_SUCCESS(NtQueryInformationToken(
hToken, TokenUser, buf, sizeof(buf), &ret)))
return FALSE;
PTOKEN_USER tu = (PTOKEN_USER)buf;
PSID systemSid = NULL;
SID_IDENTIFIER_AUTHORITY ntAuth = SECURITY_NT_AUTHORITY;
AllocateAndInitializeSid(&ntAuth, 1, SECURITY_LOCAL_SYSTEM_RID,
0,0,0,0,0,0,0, &systemSid);
BOOL eq = EqualSid(tu->User.Sid, systemSid);
FreeSid(systemSid);
return eq;
}rustMake-Me-Admin scout: locate linked elevated token
// Locate the elevated split-token sibling of an elevated-but-filtered process.
// If present, a high-IL token handle can be duplicated without UAC prompt.
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::Security::{
TOKEN_LINKED_TOKEN, TOKEN_INFORMATION_CLASS,
};
const TOKEN_LINKED_TOKEN_CLASS: TOKEN_INFORMATION_CLASS = 19; // TokenLinkedToken
extern "system" {
fn NtQueryInformationToken(
h: HANDLE, class: TOKEN_INFORMATION_CLASS,
buf: *mut u8, len: u32, ret: *mut u32) -> i32;
}
pub unsafe fn try_get_linked_token(h: HANDLE) -> Option<HANDLE> {
let mut lt = TOKEN_LINKED_TOKEN { LinkedToken: 0 };
let mut ret = 0u32;
let s = NtQueryInformationToken(
h, TOKEN_LINKED_TOKEN_CLASS,
&mut lt as *mut _ as *mut u8,
std::mem::size_of::<TOKEN_LINKED_TOKEN>() as u32,
&mut ret);
if s == 0 && lt.LinkedToken != 0 { Some(lt.LinkedToken) } else { None }
}MITRE ATT&CK mappings
- T1134Access Token Manipulation
- T1033System Owner/User Discovery
- T1548.002Bypass User Account Control
- T1106Native API
Last verified: 2026-05-20