NtAdjustPrivilegesToken
Aktiviert oder deaktiviert Privilegien in einem angegebenen Zugriffstoken.
Prototyp
NTSTATUS NtAdjustPrivilegesToken( HANDLE TokenHandle, BOOLEAN DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, ULONG BufferLength, PTOKEN_PRIVILEGES PreviousState, PULONG ReturnLength );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| TokenHandle | HANDLE | in | Handle auf ein Token, das mit TOKEN_ADJUST_PRIVILEGES (und TOKEN_QUERY, falls PreviousState angefordert wird) geöffnet wurde. |
| DisableAllPrivileges | BOOLEAN | in | Falls TRUE, deaktiviert alle Privilegien des Tokens; NewState wird ignoriert. |
| NewState | PTOKEN_PRIVILEGES | in | Array von LUID_AND_ATTRIBUTES, das beschreibt, welche Privilegien aktiviert/deaktiviert/entfernt werden sollen. |
| BufferLength | ULONG | in | Größe des PreviousState-Puffers in Bytes. 0, wenn PreviousState NULL ist. |
| PreviousState | PTOKEN_PRIVILEGES | out | Optionaler Puffer, der den vorherigen Zustand der geänderten Privilegien empfängt — nützlich zum Zurücksetzen. |
| ReturnLength | PULONG | out | Erhält die tatsächlich in PreviousState geschriebene Byte-Anzahl. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | 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 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
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
Undokumentierte Hinweise
NtAdjustPrivilegesToken ist die Funktion, die `advapi32!AdjustTokenPrivileges` umhüllt. Subtile, aber kritische Eigenheit: Die Funktion liefert `STATUS_SUCCESS` (`0`) zurück, selbst wenn ein oder mehrere angeforderte Privilegien *nicht* gehalten wurden — Aufrufer müssen `GetLastError() == ERROR_NOT_ALL_ASSIGNED` (oder `STATUS_NOT_ALL_ASSIGNED` auf NTSTATUS-Seite) prüfen. Wer das vergisst, produziert stille Eskalations-Bugs in defensiver Tooling. Der SSN ist von Windows 10 1507 bis Windows 11 24H2 **stabil bei `0x41`**, was ihn zum beliebten Eintrag für hartkodierte SSN-Tabellen macht.
Häufige Malware-Nutzung
Pflichtschritt vor jeder Cross-Process-Token-Manipulation: SeDebugPrivilege aktivieren, damit der Implant `NtOpenProcess` auf LSASS oder andere geschützte Dienste anwenden kann. Weitere von Malware häufig aktivierte Privilegien: SeImpersonatePrivilege (für die Potato-Familie zur Impersonation), SeAssignPrimaryTokenPrivilege (für `CreateProcessWithTokenW`), SeTcbPrivilege (LSASS-Stufe), SeBackupPrivilege / SeRestorePrivilege (Registry-Hive-Diebstahl für SAM/SYSTEM-Dumps via `reg save HKLM\SAM`). Mimikatz' `privilege::debug` ist buchstäblich ein Wrapper um diesen Syscall.
Erkennungsmöglichkeiten
Windows-Security-Event **4703** (Token Right Adjusted) protokolliert jede erfolgreiche Privilegien-Anpassung samt aktivierter Privilegien und Aufrufer-Prozess. Event 4672 (Special Privileges Assigned) feuert beim Logon und erneut, wenn sensible Privilegien (SeDebug, SeTcb, SeImpersonate, SeAssignPrimaryToken, SeLoadDriver, SeBackup, SeRestore, SeTakeOwnership, SeCreateToken) in einem neuen Prozess aktiviert werden. Die Korrelation 4703 + nachfolgende 4663/4673 auf LSASS ist ein hochpräzises Muster zur Erkennung von Credential-Dumping. Der ETW-Provider `Microsoft-Windows-Kernel-Audit-API-Calls` erfasst den Aufruf ebenfalls.
Direkte Syscall-Beispiele
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
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20