今天要來介紹的是 Access Check,也就是當我們以 Token 去存取某個 Object 時會需要通過的檢查。
驗證 token 的實作上分為 user mode 和 kernel mode 兩種:
NTSTATUS NTAPI NtAccessCheck(
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
_In_ HANDLE ClientToken,
_In_ ACCESS_MASK DesiredAccess,
_In_ PGENERIC_MAPPING GenericMapping,
_Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
_Inout_ PULONG PrivilegeSetLength,
_Out_ PACCESS_MASK GrantedAccess,
_Out_ PNTSTATUS AccessStatus
);
BOOLEAN SeAccessCheck(
[in] PSECURITY_DESCRIPTOR SecurityDescriptor,
[in] PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
[in] BOOLEAN SubjectContextLocked,
[in] ACCESS_MASK DesiredAccess,
[in] ACCESS_MASK PreviouslyGrantedAccess,
[out] PPRIVILEGE_SET *Privileges,
[in] PGENERIC_MAPPING GenericMapping,
[in] KPROCESSOR_MODE AccessMode,
[out] PACCESS_MASK GrantedAccess,
[out] PNTSTATUS AccessStatus
);
其中比較重要的有 SubjectSecurityContext、DesiredAccess、GenericMapping 和 SecurityDescriptor。
在 Kernel Mode 中的 Security Context 會是以下結構:
typedef struct _SECURITY_SUBJECT_CONTEXT {
PACCESS_TOKEN ClientToken;
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
PACCESS_TOKEN PrimaryToken;
PVOID ProcessAuditId;
} SECURITY_SUBJECT_CONTEXT, *PSECURITY_SUBJECT_CONTEXT;
整個 SeAccessCheck 會像是這張圖所示,但是這只適用在一般的 token, restricted token 會有更多額外的檢查。
根據投影片,SeAccessCheck 會有3個階段:
檢查 Token 的 Integrity Level 是否足夠
a. 是,進行下個檢查
b. 否,如果 Resource 本身的 Ppolicy 允許存取則通過;否則拒絕存取
檢查是不是該 Object 的 owner
a. 是,如果請求的權限是允許的則通過;否則進行下個檢查
b. 否,進行下個檢查
檢查 Token 的 User 和 Gorup 對應到 DACL 的 ACE 是否允許
a. 是,通過
b. 否,拒絕存取
以上就是 Access Check 的流程。
下一篇,我要介紹的是 Token Impersonate!