> Windows Syscalls
ntoskrnl.exeT1134T1134.001T1068

NtAdjustGroupsToken

Active ou désactive des groupes (SIDs) dans un token d'accès, ou réinitialise les attributs aux valeurs par défaut.

Prototype

NTSTATUS NtAdjustGroupsToken(
  HANDLE         TokenHandle,
  BOOLEAN        ResetToDefault,
  PTOKEN_GROUPS  NewState,
  ULONG          BufferLength,
  PTOKEN_GROUPS  PreviousState,
  PULONG         ReturnLength
);

Arguments

NameTypeDirDescription
TokenHandleHANDLEinHandle de token ouvert avec l'accès TOKEN_ADJUST_GROUPS (et TOKEN_QUERY si PreviousState est demandé).
ResetToDefaultBOOLEANinTRUE restaure les attributs de chaque groupe à leur défaut (NewState ignoré) ; FALSE applique NewState.
NewStatePTOKEN_GROUPSinTableau de SID_AND_ATTRIBUTES à appliquer. Les attributs basculent typiquement SE_GROUP_ENABLED / SE_GROUP_ENABLED_BY_DEFAULT.
BufferLengthULONGinTaille du buffer PreviousState en octets. Passer 0 si PreviousState est NULL.
PreviousStatePTOKEN_GROUPSoutBuffer optionnel qui reçoit l'ensemble précédent d'attributs de groupes pour permettre un revert.
ReturnLengthPULONGoutReçoit le nombre d'octets écrits dans PreviousState (ou requis si STATUS_BUFFER_TOO_SMALL).

IDs de syscalls par version de Windows

Version de WindowsID de syscallBuild
Win10 15070x6Awin10-1507
Win10 16070x6Awin10-1607
Win10 17030x6Bwin10-1703
Win10 17090x6Bwin10-1709
Win10 18030x6Bwin10-1803
Win10 18090x6Bwin10-1809
Win10 19030x6Bwin10-1903
Win10 19090x6Bwin10-1909
Win10 20040x6Cwin10-2004
Win10 20H20x6Cwin10-20h2
Win10 21H10x6Cwin10-21h1
Win10 21H20x6Cwin10-21h2
Win10 22H20x6Cwin10-22h2
Win11 21H20x6Cwin11-21h2
Win11 22H20x6Cwin11-22h2
Win11 23H20x6Cwin11-23h2
Win11 24H20x6Cwin11-24h2
Server 20160x6Awinserver-2016
Server 20190x6Bwinserver-2019
Server 20220x6Cwinserver-2022
Server 20250x6Cwinserver-2025

Module noyau

ntoskrnl.exeNtAdjustGroupsToken

APIs liées

AdjustTokenGroupsCheckTokenMembershipNtAdjustPrivilegesTokenNtFilterTokenNtDuplicateTokenNtOpenProcessToken

Stub du syscall

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

Le côté noyau de l'API Win32 `AdjustTokenGroups`. Frère de `NtAdjustPrivilegesToken` — les privilèges vivent dans TOKEN_PRIVILEGES, l'appartenance aux groupes dans TOKEN_GROUPS. `NtAdjustGroupsToken` ne peut pas *ajouter* un SID à un token ; il peut seulement activer, désactiver ou restaurer-par-défaut les SIDs déjà présents (qu'ils soient activés, désactivés, deny-only ou restricted). Pour désactiver l'attribut SE_GROUP_USE_FOR_DENY_ONLY d'un SID, il faut typiquement passer d'abord par `NtFilterToken` pour produire une variante non-deny. Chaque SID dans NewState se couple avec un masque Attributes (SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_OWNER, SE_GROUP_USE_FOR_DENY_ONLY) ; fournir SE_GROUP_ENABLED sur un SID précédemment désactivé l'active.

Usage courant par les malwares

**Réactivation de SID de groupe pour chaînes d'escalade de privilège** : la configuration canonique est un attaquant qui a volé un token (via SeImpersonatePrivilege, Rotten/Juicy Potato, PrintSpoofer, etc.) contenant BUILTIN\Administrators en SID deny-only (état typique sous UAC split-token IL Medium). L'attaquant appelle NtFilterToken ou duplique le token pour produire une variante non-deny, puis NtAdjustGroupsToken pour réactiver SE_GROUP_ENABLED sur le SID Administrators — donnant instantanément l'appartenance admin sur le thread live sans prompt UAC interactif. Plus rarement, sert à supprimer un SID que l'attaquant ne veut pas voir évalué (désactiver un SID de groupe de logging qui déclenche un audit supplémentaire à l'accès fichier). Documenté dans les chaînes offensives autour des familles AlwaysInstallElevated et SeImpersonatePrivilege.

Opportunités de détection

Microsoft-Windows-Security-Auditing event ID 4672 (privilèges spéciaux assignés) et 4673 (service privilégié appelé) aident côté privilèges ; le côté ajustement de groupes n'est couvert qu'indirectement par 4670 (permissions sur un objet modifiées). Les EDR qui suivent les primitives de modification de token exposent une séquence comme (NtOpenProcessToken sur un processus plus privilégié → NtDuplicateToken → NtFilterToken → NtAdjustGroupsToken → NtSetInformationThread(ImpersonationToken)) comme une chaîne d'abus de token. L'invariant défensif utile : les processus légitimes n'appellent quasi jamais NtAdjustGroupsToken pour *activer* un SID haut-privilège précédemment désactivé ; des auditeurs qui snapshottent l'état du token à la création de processus et comparent à l'état runtime peuvent flagger le delta. ETW Microsoft-Windows-Kernel-Audit-API-Calls expose le syscall à un volume modéré.

Exemples de syscalls directs

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtAdjustGroupsToken (SSN 0x6C on Win10 2004+/Win11)
NtAdjustGroupsToken PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 6Ch          ; SSN — stable across modern builds
    syscall
    ret
NtAdjustGroupsToken ENDP

cPrivesc — re-enable BUILTIN\Administrators in a stolen token

// Assumes hTok came from NtDuplicateToken + NtFilterToken (non-deny variant).
// Re-enable SE_GROUP_ENABLED on the Administrators SID in-place.
#include <windows.h>
#include <winternl.h>

static VOID EnableAdminsGroup(HANDLE hTok) {
    SID_IDENTIFIER_AUTHORITY nt = SECURITY_NT_AUTHORITY;
    PSID adminSid = NULL;
    AllocateAndInitializeSid(&nt, 2,
        SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
        0, 0, 0, 0, 0, 0, &adminSid);

    BYTE buf[sizeof(TOKEN_GROUPS) + sizeof(SID_AND_ATTRIBUTES)];
    TOKEN_GROUPS* tg = (TOKEN_GROUPS*)buf;
    tg->GroupCount = 1;
    tg->Groups[0].Sid = adminSid;
    tg->Groups[0].Attributes = SE_GROUP_ENABLED; // flip the bit

    // Win32 wrapper -> NtAdjustGroupsToken
    AdjustTokenGroups(hTok, FALSE, tg, 0, NULL, NULL);
    FreeSid(adminSid);
}

cSnapshot then restore previous group state

// Defensive / red-team utility: change group state, do work, restore exactly.
#include <windows.h>
#include <winternl.h>

typedef NTSTATUS (NTAPI *pNtAdjustGroupsToken)(
    HANDLE, BOOLEAN, PTOKEN_GROUPS, ULONG, PTOKEN_GROUPS, PULONG);

VOID WithToggledGroup(HANDLE hTok, TOKEN_GROUPS* desired) {
    pNtAdjustGroupsToken NtAdjustGroupsToken = (pNtAdjustGroupsToken)
        GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtAdjustGroupsToken");
    BYTE prev[4096]; ULONG ret = 0;
    NtAdjustGroupsToken(hTok, FALSE, desired,
                        sizeof(prev), (PTOKEN_GROUPS)prev, &ret);
    DoWorkWithToggledGroups();
    NtAdjustGroupsToken(hTok, FALSE, (PTOKEN_GROUPS)prev,
                        0, NULL, NULL); // revert exact prior state
}

Mappings MITRE ATT&CK

Last verified: 2026-05-20