[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.
This commit is contained in:
George Bișoc 2022-02-28 18:35:53 +01:00
parent de6c514c3e
commit bee9b2fcc6
No known key found for this signature in database
GPG key ID: 688C4FBE25D7DEF6
3 changed files with 196 additions and 1 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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 */