NtAdjustPrivilegesToken
Active ou désactive des privilèges dans un jeton d'accès spécifié.
Prototype
NTSTATUS NtAdjustPrivilegesToken( HANDLE TokenHandle, BOOLEAN DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, ULONG BufferLength, PTOKEN_PRIVILEGES PreviousState, PULONG ReturnLength );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| TokenHandle | HANDLE | in | Handle vers un jeton ouvert avec TOKEN_ADJUST_PRIVILEGES (et TOKEN_QUERY si PreviousState est demandé). |
| DisableAllPrivileges | BOOLEAN | in | Si TRUE, désactive tous les privilèges du jeton ; NewState est ignoré. |
| NewState | PTOKEN_PRIVILEGES | in | Tableau de LUID_AND_ATTRIBUTES décrivant les privilèges à activer/désactiver/retirer. |
| BufferLength | ULONG | in | Taille en octets du buffer PreviousState. 0 si PreviousState vaut NULL. |
| PreviousState | PTOKEN_PRIVILEGES | out | Buffer optionnel recevant l'état antérieur des privilèges modifiés, utile pour annuler. |
| ReturnLength | PULONG | out | Reçoit le nombre d'octets réellement écrits dans PreviousState. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x41 | win10-1507 |
| Win10 1607 | 0x41 | win10-1607 |
| Win10 1703 | 0x41 | win10-1703 |
| Win10 1709 | 0x41 | win10-1709 |
| Win10 1803 | 0x41 | win10-1803 |
| Win10 1809 | 0x41 | win10-1809 |
| Win10 1903 | 0x41 | win10-1903 |
| Win10 1909 | 0x41 | win10-1909 |
| Win10 2004 | 0x41 | win10-2004 |
| Win10 20H2 | 0x41 | win10-20h2 |
| Win10 21H1 | 0x41 | win10-21h1 |
| Win10 21H2 | 0x41 | win10-21h2 |
| Win10 22H2 | 0x41 | win10-22h2 |
| Win11 21H2 | 0x41 | win11-21h2 |
| Win11 22H2 | 0x41 | win11-22h2 |
| Win11 23H2 | 0x41 | win11-23h2 |
| Win11 24H2 | 0x41 | win11-24h2 |
| Server 2016 | 0x41 | winserver-2016 |
| Server 2019 | 0x41 | winserver-2019 |
| Server 2022 | 0x41 | winserver-2022 |
| Server 2025 | 0x41 | winserver-2025 |
Module noyau
APIs liées
Stub du syscall
4C 8B D1 mov r10, rcx B8 41 00 00 00 mov eax, 0x41 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
NtAdjustPrivilegesToken est ce qu'enrobe `advapi32!AdjustTokenPrivileges`. Comportement subtil mais critique : la fonction renvoie `STATUS_SUCCESS` (`0`) même quand un ou plusieurs privilèges demandés ne sont *pas* détenus — les appelants doivent vérifier `GetLastError() == ERROR_NOT_ALL_ASSIGNED` (ou `STATUS_NOT_ALL_ASSIGNED` côté NTSTATUS). Omettre cette vérification produit des bugs silencieux d'élévation dans les outils défensifs. Le SSN est **resté stable à `0x41`** de Windows 10 1507 à Windows 11 24H2, ce qui en fait un choix populaire pour des tables de SSN codées en dur.
Usage courant par les malwares
Étape obligatoire avant toute manipulation de jeton inter-processus : activer SeDebugPrivilege pour que l'implant puisse appeler `NtOpenProcess` sur LSASS ou d'autres services protégés. Autres privilèges couramment activés par les malwares : SeImpersonatePrivilege (requis par la famille Potato pour l'impersonation), SeAssignPrimaryTokenPrivilege (requis par `CreateProcessWithTokenW`), SeTcbPrivilege (niveau LSASS), SeBackupPrivilege / SeRestorePrivilege (vol de ruches registre pour les dumps SAM/SYSTEM via `reg save HKLM\SAM`). `privilege::debug` de Mimikatz est littéralement un wrapper autour de ce syscall.
Opportunités de détection
L'événement Windows Security **4703** (Token Right Adjusted) enregistre chaque ajustement de privilège réussi, en indiquant quels privilèges ont été activés et le processus appelant. L'événement 4672 (Special Privileges Assigned) se déclenche au logon et de nouveau quand des privilèges sensibles (SeDebug, SeTcb, SeImpersonate, SeAssignPrimaryToken, SeLoadDriver, SeBackup, SeRestore, SeTakeOwnership, SeCreateToken) sont activés dans un nouveau processus. Corréler 4703 puis 4663/4673 ciblant LSASS est un motif à très haute fidélité pour la détection de dump de credentials. Le provider ETW `Microsoft-Windows-Kernel-Audit-API-Calls` couvre également l'appel.
Exemples de syscalls directs
asmx64 direct stub (stable SSN 0x41)
NtAdjustPrivilegesToken PROC
mov r10, rcx
mov eax, 41h ; SSN stable across all builds
syscall
ret
NtAdjustPrivilegesToken ENDPcEnable SeDebugPrivilege the classic way
// Enable SeDebugPrivilege via direct Nt* calls — required before opening LSASS.
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tp = { 0 };
NtOpenProcessTokenEx(NtCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
0, &hToken);
LookupPrivilegeValueW(NULL, L"SeDebugPrivilege", &luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
NTSTATUS s = NtAdjustPrivilegesToken(hToken,
FALSE,
&tp,
0, NULL, NULL);
// IMPORTANT: also test STATUS_NOT_ALL_ASSIGNED (0x06000000+) — success isn't enough.
if (s == 0x00000106 /* STATUS_NOT_ALL_ASSIGNED */) {
// Privilege wasn't held — abort the elevation chain.
}rustPrivilege-enable helper inside an impersonation chain
// Tiny helper used right after NtOpenProcessTokenEx, before NtDuplicateToken.
use windows_sys::Win32::Foundation::{HANDLE, LUID};
use windows_sys::Win32::Security::{LookupPrivilegeValueW, TOKEN_PRIVILEGES, SE_PRIVILEGE_ENABLED};
pub unsafe fn enable_privilege(token: HANDLE, name: &str) -> bool {
let wide: Vec<u16> = name.encode_utf16().chain(std::iter::once(0)).collect();
let mut luid: LUID = std::mem::zeroed();
if LookupPrivilegeValueW(std::ptr::null(), wide.as_ptr(), &mut luid) == 0 {
return false;
}
let mut tp = TOKEN_PRIVILEGES {
PrivilegeCount: 1,
Privileges: [windows_sys::Win32::Security::LUID_AND_ATTRIBUTES {
Luid: luid,
Attributes: SE_PRIVILEGE_ENABLED,
}],
};
// Direct syscall stub elsewhere; signature matches NtAdjustPrivilegesToken.
extern "system" { fn NtAdjustPrivilegesToken(
h: HANDLE, disable_all: u8,
new_state: *mut TOKEN_PRIVILEGES, len: u32,
prev: *mut TOKEN_PRIVILEGES, ret_len: *mut u32) -> i32; }
let s = NtAdjustPrivilegesToken(token, 0, &mut tp, 0, std::ptr::null_mut(), std::ptr::null_mut());
// STATUS_NOT_ALL_ASSIGNED == 0x00000106 — treat as failure for elevation.
s == 0
}Mappings MITRE ATT&CK
Last verified: 2026-05-20