From bee9b2fcc6cbe03251778e439ffb5f408fba650e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?George=20Bi=C8=99oc?= Date: Mon, 28 Feb 2022 18:35:53 +0100 Subject: [PATCH] [LSASRV] Set up a security descriptor for the token object LSASS implements a default ACL inside the token structure field but it doesn't actually set a protective security descriptor for the token object itself. This happens so that the kernel gets whatever default ACLs it finds for the object which is incorrect. SYSTEM has full and supreme control over tokens, administrators can only read the token as such. The logged in user of their own token has full access. Credits and courtesy goes to Thomas Faber for the patch. --- dll/win32/lsasrv/authpackage.c | 15 ++- dll/win32/lsasrv/lsasrv.h | 6 ++ dll/win32/lsasrv/security.c | 176 +++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+), 1 deletion(-) diff --git a/dll/win32/lsasrv/authpackage.c b/dll/win32/lsasrv/authpackage.c index 8a335be6d6b..462329b826e 100644 --- a/dll/win32/lsasrv/authpackage.c +++ b/dll/win32/lsasrv/authpackage.c @@ -1627,9 +1627,18 @@ LsapLogonUser(PLSA_API_MSG RequestMsg, else if (TokenInformationType == LsaTokenInformationV1) { TOKEN_PRIVILEGES NoPrivileges = {0}; + PSECURITY_DESCRIPTOR TokenSd; + ULONG TokenSdSize; TokenInfo1 = (PLSA_TOKEN_INFORMATION_V1)TokenInformation; + /* Set up a security descriptor for token object itself */ + Status = LsapCreateTokenSd(&TokenInfo1->User, &TokenSd, &TokenSdSize); + if (!NT_SUCCESS(Status)) + { + TokenSd = NULL; + } + Qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); Qos.ImpersonationLevel = SecurityImpersonation; Qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; @@ -1639,7 +1648,7 @@ LsapLogonUser(PLSA_API_MSG RequestMsg, ObjectAttributes.RootDirectory = NULL; ObjectAttributes.ObjectName = NULL; ObjectAttributes.Attributes = 0; - ObjectAttributes.SecurityDescriptor = NULL; + ObjectAttributes.SecurityDescriptor = TokenSd; ObjectAttributes.SecurityQualityOfService = &Qos; /* Create the logon token */ @@ -1656,6 +1665,10 @@ LsapLogonUser(PLSA_API_MSG RequestMsg, &TokenInfo1->PrimaryGroup, &TokenInfo1->DefaultDacl, &RequestMsg->LogonUser.Request.SourceContext); + + /* Free the allocated security descriptor */ + RtlFreeHeap(RtlGetProcessHeap(), 0, TokenSd); + if (!NT_SUCCESS(Status)) { ERR("NtCreateToken failed (Status 0x%08lx)\n", Status); diff --git a/dll/win32/lsasrv/lsasrv.h b/dll/win32/lsasrv/lsasrv.h index a73b66c672e..2ba5fa1b917 100644 --- a/dll/win32/lsasrv/lsasrv.h +++ b/dll/win32/lsasrv/lsasrv.h @@ -436,6 +436,12 @@ NTSTATUS LsapCreateSecretSd(PSECURITY_DESCRIPTOR *SecretSd, PULONG SecretSdSize); +NTSTATUS +LsapCreateTokenSd( + _In_ const TOKEN_USER *User, + _Outptr_ PSECURITY_DESCRIPTOR *TokenSd, + _Out_ PULONG TokenSdSize); + /* session.c */ VOID LsapInitLogonSessions(VOID); diff --git a/dll/win32/lsasrv/security.c b/dll/win32/lsasrv/security.c index 10fd7352a23..6bb61cdfa65 100644 --- a/dll/win32/lsasrv/security.c +++ b/dll/win32/lsasrv/security.c @@ -599,4 +599,180 @@ done: return Status; } + +/** + * @brief + * Creates a security descriptor for the token + * object. + * + * @param[in] User + * A primary user to be given to the function. + * This user represents the owner that is in + * charge of this object. + * + * @param[out] TokenSd + * A pointer to an allocated security descriptor + * for the token object. + * + * @param[out] TokenSdSize + * A pointer to a returned size of the descriptor. + * + * @return + * STATUS_SUCCESS is returned if the function has + * successfully created the security descriptor. + * STATUS_INVALID_PARAMETER is returned if one of the + * parameters are not valid. STATUS_INSUFFICIENT_RESOURCES + * is returned if memory heap allocation for specific + * security buffers couldn't be done. A NTSTATUS status + * code is returned otherwise. + * + * @remarks + * Bot the local system and user are given full access rights + * for the token (they can open it, read and write into it, etc.) + * whereas admins can only read from the token. This security + * descriptor is TO NOT BE confused with the default DACL of the + * token which is another thing that serves different purpose. + */ +NTSTATUS +LsapCreateTokenSd( + _In_ const TOKEN_USER *User, + _Outptr_ PSECURITY_DESCRIPTOR *TokenSd, + _Out_ PULONG TokenSdSize) +{ + SECURITY_DESCRIPTOR AbsoluteSd; + PSECURITY_DESCRIPTOR RelativeSd = NULL; + ULONG RelativeSdSize = 0; + PSID AdministratorsSid = NULL; + PSID LocalSystemSid = NULL; + PACL Dacl = NULL; + ULONG DaclSize; + NTSTATUS Status; + + if (TokenSd == NULL || TokenSdSize == NULL) + return STATUS_INVALID_PARAMETER; + + *TokenSd = NULL; + *TokenSdSize = 0; + + /* Initialize the SD */ + Status = RtlCreateSecurityDescriptor(&AbsoluteSd, + SECURITY_DESCRIPTOR_REVISION); + if (!NT_SUCCESS(Status)) + return Status; + + Status = RtlAllocateAndInitializeSid(&NtAuthority, + 1, + SECURITY_LOCAL_SYSTEM_RID, + 0, 0, 0, 0, 0, 0, 0, + &LocalSystemSid); + if (!NT_SUCCESS(Status)) + goto done; + + Status = RtlAllocateAndInitializeSid(&NtAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &AdministratorsSid); + if (!NT_SUCCESS(Status)) + goto done; + + /* Allocate and initialize the DACL */ + DaclSize = sizeof(ACL) + + sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(LocalSystemSid) + + sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(AdministratorsSid) + + sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(User->User.Sid); + + Dacl = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + DaclSize); + if (Dacl == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto done; + } + + Status = RtlCreateAcl(Dacl, + DaclSize, + ACL_REVISION); + if (!NT_SUCCESS(Status)) + goto done; + + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + TOKEN_ALL_ACCESS, + LocalSystemSid); + if (!NT_SUCCESS(Status)) + goto done; + + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + TOKEN_READ, + AdministratorsSid); + if (!NT_SUCCESS(Status)) + goto done; + + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + TOKEN_ALL_ACCESS, + User->User.Sid); + if (!NT_SUCCESS(Status)) + goto done; + + Status = RtlSetDaclSecurityDescriptor(&AbsoluteSd, + TRUE, + Dacl, + FALSE); + if (!NT_SUCCESS(Status)) + goto done; + + Status = RtlSetOwnerSecurityDescriptor(&AbsoluteSd, + AdministratorsSid, + FALSE); + if (!NT_SUCCESS(Status)) + goto done; + + Status = RtlAbsoluteToSelfRelativeSD(&AbsoluteSd, + RelativeSd, + &RelativeSdSize); + if (Status != STATUS_BUFFER_TOO_SMALL) + goto done; + + RelativeSd = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + RelativeSdSize); + if (RelativeSd == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto done; + } + + Status = RtlAbsoluteToSelfRelativeSD(&AbsoluteSd, + RelativeSd, + &RelativeSdSize); + if (!NT_SUCCESS(Status)) + goto done; + + *TokenSd = RelativeSd; + *TokenSdSize = RelativeSdSize; + +done: + if (Dacl != NULL) + RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl); + + if (AdministratorsSid != NULL) + RtlFreeHeap(RtlGetProcessHeap(), 0, AdministratorsSid); + + if (LocalSystemSid != NULL) + RtlFreeHeap(RtlGetProcessHeap(), 0, LocalSystemSid); + + if (!NT_SUCCESS(Status)) + { + if (RelativeSd != NULL) + RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd); + } + + return Status; +} + /* EOF */