NtAccessCheckByType
Führt eine Sicherheitszugriffsprüfung gegen einen Security Descriptor durch und respektiert eine typisierte Objekt-Hierarchie (OBJECT_TYPE_LIST).
Prototyp
NTSTATUS NtAccessCheckByType( PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, HANDLE ClientToken, ACCESS_MASK DesiredAccess, POBJECT_TYPE_LIST ObjectTypeList, ULONG ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, PULONG PrivilegeSetLength, PACCESS_MASK GrantedAccess, PNTSTATUS AccessStatus );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| SecurityDescriptor | PSECURITY_DESCRIPTOR | in | Security Descriptor des typisierten Objekts, das geprüft wird. Muss Owner, Group und DACL enthalten. |
| PrincipalSelfSid | PSID | in | Optionaler SID, der für PRINCIPAL_SELF-Einträge in der DACL eingesetzt wird (z. B. AD-Account-Self-ACE). |
| ClientToken | HANDLE | in | Impersonation-Token des Clients, dessen Zugriff geprüft wird. |
| DesiredAccess | ACCESS_MASK | in | Bitmaske der angeforderten Rechte (spezifisch + standard + generisch; MAXIMUM_ALLOWED unterstützt). |
| ObjectTypeList | POBJECT_TYPE_LIST | in | Array, das die Objekt-Typ-Hierarchie beschreibt (Root + Children). Jede Ebene kann eine andere Teilmenge von DesiredAccess gewähren. |
| ObjectTypeListLength | ULONG | in | Anzahl der OBJECT_TYPE_LIST-Einträge. Vom Kernel auf 256 begrenzt. |
| GenericMapping | PGENERIC_MAPPING | in | Mappt GENERIC_READ/WRITE/EXECUTE/ALL auf objektspezifische Rechte. |
| PrivilegeSet | PPRIVILEGE_SET | out | Empfängt die während der Prüfung verwendeten Privilegien (z. B. SeSecurityPrivilege für SACL-Zugriff). |
| PrivilegeSetLength | PULONG | in/out | Beim Eintritt: Größe des PrivilegeSet-Puffers; beim Austritt: tatsächlich verwendete / benötigte Bytes. |
| GrantedAccess | PACCESS_MASK | out | Empfängt die tatsächlich gewährte Access-Maske (Teilmenge von DesiredAccess). |
| AccessStatus | PNTSTATUS | out | Empfängt STATUS_SUCCESS bei gewährtem Zugriff, sonst STATUS_ACCESS_DENIED. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0x63 | win10-1507 |
| Win10 1607 | 0x63 | win10-1607 |
| Win10 1703 | 0x63 | win10-1703 |
| Win10 1709 | 0x63 | win10-1709 |
| Win10 1803 | 0x63 | win10-1803 |
| Win10 1809 | 0x63 | win10-1809 |
| Win10 1903 | 0x63 | win10-1903 |
| Win10 1909 | 0x63 | win10-1909 |
| Win10 2004 | 0x63 | win10-2004 |
| Win10 20H2 | 0x63 | win10-20h2 |
| Win10 21H1 | 0x63 | win10-21h1 |
| Win10 21H2 | 0x63 | win10-21h2 |
| Win10 22H2 | 0x63 | win10-22h2 |
| Win11 21H2 | 0x63 | win11-21h2 |
| Win11 22H2 | 0x63 | win11-22h2 |
| Win11 23H2 | 0x63 | win11-23h2 |
| Win11 24H2 | 0x63 | win11-24h2 |
| Server 2016 | 0x63 | winserver-2016 |
| Server 2019 | 0x63 | winserver-2019 |
| Server 2022 | 0x63 | winserver-2022 |
| Server 2025 | 0x63 | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 63 00 00 00 mov eax, 0x63 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
Erweiterter Cousin von `NtAccessCheck`, der eine *typisierte Objekt-Hierarchie* versteht. Wo `NtAccessCheck` eine DACL gegen ein DesiredAccess auswertet, läuft `NtAccessCheckByType` eine `OBJECT_TYPE_LIST` (Root → Child-Types, per GUID identifiziert) ab und kann den angeforderten Zugriff auf Eltern-Ebene gewähren, während er auf einem spezifischen Child-Type abgelehnt wird — das Modell, das AD für feingranulare Permissions wie 'Read All Properties' versus 'Read PasswordLastSet' nutzt. Object-spezifische ACEs (`ACCESS_ALLOWED_OBJECT_ACE`, `ACCESS_DENIED_OBJECT_ACE`) tragen einen GUID, der einem der OBJECT_TYPE_LIST-Einträge entspricht. Die Syscall-Nummer `0x63` ist von Windows 10 1507 durchgehend bis Server 2025 und Win11 24H2 stabil — einer der stabilsten Syscalls in der Tabelle.
Häufige Malware-Nutzung
Schwaches Malware-Signal — dies ist eine Self-Service-Sicherheitsprimitive, die von **serverseitiger Software** genutzt wird, nicht von Malware. Sie taucht in Active-Directory-Authorisierungspfaden auf (lsass.exe, dsamain.exe), in COM+/Component Services (catsrv.dll), im Authorization Manager (azroles.dll) und in Teilen des MS-SQL-Zugriffsbroker-Codes. Dokumentierte offensive Nutzungen beschränken sich auf: (1) AD-Privilege-Mapping-Recon, bei der ein Angreifer AccessCheckByType lokal gegen das eigene Token plus einen vom DC geholten Security Descriptor aufruft, um exakt aufzuzählen, welche AD-Attribute der aktuelle Principal lesen/schreiben kann — Äquivalent zu BloodHounds User-Rights-Collection, aber client-seitig und ohne Netz-Lärm; (2) einige COM-basierte UAC-Bypass-Forschung hat es genutzt, um zu verifizieren, dass eine Exploit-Kette tatsächlich ein zuvor verweigertes Access-Bit umlegt. Es gibt keinen dokumentierten Einsatz durch eine große Malware-Familie als primäre Primitive.
Erkennungsmöglichkeiten
Das Telemetrie-Signal ist für den Syscall selbst praktisch null — in legitimen AD- und COM+-Workloads zu laut, um darauf zu alarmieren. Verteidiger konzentrieren sich stattdessen auf: Object-Access-Auditing (Event ID 4663) bei den Ressourcen-Eignern (AD über 4662 'object operation', COM+ über Component-Services-Audit), das *nach* der AccessCheckByType-Entscheidung feuert. ETW Microsoft-Windows-Security-Auditing deckt die AD-seitige Audit-Kategorie ab. Bei COM- und Authorization-Manager-Apps können benutzerdefinierte AppLog-ETW-Provider Access-Check-Verdikte emittieren. Aus EDR-Sicht ist AccessCheckByType aus einem Nicht-Server-Prozess gegen einen AD-Objekt-Deskriptor (an den GUIDs in der OBJECT_TYPE_LIST erkennbar) ein schwacher Indikator für BloodHound-artige Recon.
Direkte Syscall-Beispiele
asmx64 direct stub (all builds)
; Direct syscall stub for NtAccessCheckByType (SSN 0x63 stable across all builds)
NtAccessCheckByType PROC
mov r10, rcx ; syscall convention
mov eax, 63h ; SSN — stable everywhere
syscall
ret
NtAccessCheckByType ENDPcAD attribute-level access check (server-side pattern)
// AD authorization sample: the caller wants to read the 'unicodePwd' attribute
// on a user object. OBJECT_TYPE_LIST has the user class at level 0 and the
// attribute at level 1; AccessCheckByType returns per-level masks.
#include <windows.h>
#include <accctrl.h>
#include <aclapi.h>
BOOL CheckCanReadAttribute(PSECURITY_DESCRIPTOR sd, HANDLE clientToken,
const GUID* classGuid, const GUID* attrGuid)
{
OBJECT_TYPE_LIST otl[2] = {
{ ACCESS_OBJECT_GUID, 0, (GUID*)classGuid },
{ ACCESS_PROPERTY_GUID, 0, (GUID*)attrGuid },
};
GENERIC_MAPPING gm = { 0x20094, 0x20028, 0, 0xF01FF };
PRIVILEGE_SET ps; ULONG psLen = sizeof(ps);
ACCESS_MASK granted = 0; BOOL accessStatus = FALSE;
return AccessCheckByType(sd, NULL, clientToken, ACTRL_DS_READ_PROP,
otl, 2, &gm, &ps, &psLen, &granted, &accessStatus) && accessStatus;
}cLocal AD-rights enumeration (red-team recon)
// Variant: caller passes its own impersonation token plus a DC-fetched SD
// for a target object and probes a list of attribute GUIDs to discover the
// effective rights without round-tripping LDAP queries to the DC.
#include <windows.h>
#include <stdio.h>
void EnumerateLocalRights(PSECURITY_DESCRIPTOR sd, HANDLE myToken,
const GUID* classGuid,
const GUID* attrGuids, size_t n)
{
for (size_t i = 0; i < n; ++i) {
if (CheckCanReadAttribute(sd, myToken, classGuid, &attrGuids[i])) {
wprintf(L"+ readable attr %zu\n", i);
}
}
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20