Skip to content

Commit bee9b2f

Browse files
committed
[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.
1 parent de6c514 commit bee9b2f

File tree

3 files changed

+196
-1
lines changed

3 files changed

+196
-1
lines changed

dll/win32/lsasrv/authpackage.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1627,9 +1627,18 @@ LsapLogonUser(PLSA_API_MSG RequestMsg,
16271627
else if (TokenInformationType == LsaTokenInformationV1)
16281628
{
16291629
TOKEN_PRIVILEGES NoPrivileges = {0};
1630+
PSECURITY_DESCRIPTOR TokenSd;
1631+
ULONG TokenSdSize;
16301632

16311633
TokenInfo1 = (PLSA_TOKEN_INFORMATION_V1)TokenInformation;
16321634

1635+
/* Set up a security descriptor for token object itself */
1636+
Status = LsapCreateTokenSd(&TokenInfo1->User, &TokenSd, &TokenSdSize);
1637+
if (!NT_SUCCESS(Status))
1638+
{
1639+
TokenSd = NULL;
1640+
}
1641+
16331642
Qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
16341643
Qos.ImpersonationLevel = SecurityImpersonation;
16351644
Qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
@@ -1639,7 +1648,7 @@ LsapLogonUser(PLSA_API_MSG RequestMsg,
16391648
ObjectAttributes.RootDirectory = NULL;
16401649
ObjectAttributes.ObjectName = NULL;
16411650
ObjectAttributes.Attributes = 0;
1642-
ObjectAttributes.SecurityDescriptor = NULL;
1651+
ObjectAttributes.SecurityDescriptor = TokenSd;
16431652
ObjectAttributes.SecurityQualityOfService = &Qos;
16441653

16451654
/* Create the logon token */
@@ -1656,6 +1665,10 @@ LsapLogonUser(PLSA_API_MSG RequestMsg,
16561665
&TokenInfo1->PrimaryGroup,
16571666
&TokenInfo1->DefaultDacl,
16581667
&RequestMsg->LogonUser.Request.SourceContext);
1668+
1669+
/* Free the allocated security descriptor */
1670+
RtlFreeHeap(RtlGetProcessHeap(), 0, TokenSd);
1671+
16591672
if (!NT_SUCCESS(Status))
16601673
{
16611674
ERR("NtCreateToken failed (Status 0x%08lx)\n", Status);

dll/win32/lsasrv/lsasrv.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,12 @@ NTSTATUS
436436
LsapCreateSecretSd(PSECURITY_DESCRIPTOR *SecretSd,
437437
PULONG SecretSdSize);
438438

439+
NTSTATUS
440+
LsapCreateTokenSd(
441+
_In_ const TOKEN_USER *User,
442+
_Outptr_ PSECURITY_DESCRIPTOR *TokenSd,
443+
_Out_ PULONG TokenSdSize);
444+
439445
/* session.c */
440446
VOID
441447
LsapInitLogonSessions(VOID);

dll/win32/lsasrv/security.c

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,4 +599,180 @@ LsapCreateSecretSd(PSECURITY_DESCRIPTOR *SecretSd,
599599
return Status;
600600
}
601601

602+
603+
/**
604+
* @brief
605+
* Creates a security descriptor for the token
606+
* object.
607+
*
608+
* @param[in] User
609+
* A primary user to be given to the function.
610+
* This user represents the owner that is in
611+
* charge of this object.
612+
*
613+
* @param[out] TokenSd
614+
* A pointer to an allocated security descriptor
615+
* for the token object.
616+
*
617+
* @param[out] TokenSdSize
618+
* A pointer to a returned size of the descriptor.
619+
*
620+
* @return
621+
* STATUS_SUCCESS is returned if the function has
622+
* successfully created the security descriptor.
623+
* STATUS_INVALID_PARAMETER is returned if one of the
624+
* parameters are not valid. STATUS_INSUFFICIENT_RESOURCES
625+
* is returned if memory heap allocation for specific
626+
* security buffers couldn't be done. A NTSTATUS status
627+
* code is returned otherwise.
628+
*
629+
* @remarks
630+
* Bot the local system and user are given full access rights
631+
* for the token (they can open it, read and write into it, etc.)
632+
* whereas admins can only read from the token. This security
633+
* descriptor is TO NOT BE confused with the default DACL of the
634+
* token which is another thing that serves different purpose.
635+
*/
636+
NTSTATUS
637+
LsapCreateTokenSd(
638+
_In_ const TOKEN_USER *User,
639+
_Outptr_ PSECURITY_DESCRIPTOR *TokenSd,
640+
_Out_ PULONG TokenSdSize)
641+
{
642+
SECURITY_DESCRIPTOR AbsoluteSd;
643+
PSECURITY_DESCRIPTOR RelativeSd = NULL;
644+
ULONG RelativeSdSize = 0;
645+
PSID AdministratorsSid = NULL;
646+
PSID LocalSystemSid = NULL;
647+
PACL Dacl = NULL;
648+
ULONG DaclSize;
649+
NTSTATUS Status;
650+
651+
if (TokenSd == NULL || TokenSdSize == NULL)
652+
return STATUS_INVALID_PARAMETER;
653+
654+
*TokenSd = NULL;
655+
*TokenSdSize = 0;
656+
657+
/* Initialize the SD */
658+
Status = RtlCreateSecurityDescriptor(&AbsoluteSd,
659+
SECURITY_DESCRIPTOR_REVISION);
660+
if (!NT_SUCCESS(Status))
661+
return Status;
662+
663+
Status = RtlAllocateAndInitializeSid(&NtAuthority,
664+
1,
665+
SECURITY_LOCAL_SYSTEM_RID,
666+
0, 0, 0, 0, 0, 0, 0,
667+
&LocalSystemSid);
668+
if (!NT_SUCCESS(Status))
669+
goto done;
670+
671+
Status = RtlAllocateAndInitializeSid(&NtAuthority,
672+
2,
673+
SECURITY_BUILTIN_DOMAIN_RID,
674+
DOMAIN_ALIAS_RID_ADMINS,
675+
0, 0, 0, 0, 0, 0,
676+
&AdministratorsSid);
677+
if (!NT_SUCCESS(Status))
678+
goto done;
679+
680+
/* Allocate and initialize the DACL */
681+
DaclSize = sizeof(ACL) +
682+
sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(LocalSystemSid) +
683+
sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(AdministratorsSid) +
684+
sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(User->User.Sid);
685+
686+
Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
687+
HEAP_ZERO_MEMORY,
688+
DaclSize);
689+
if (Dacl == NULL)
690+
{
691+
Status = STATUS_INSUFFICIENT_RESOURCES;
692+
goto done;
693+
}
694+
695+
Status = RtlCreateAcl(Dacl,
696+
DaclSize,
697+
ACL_REVISION);
698+
if (!NT_SUCCESS(Status))
699+
goto done;
700+
701+
Status = RtlAddAccessAllowedAce(Dacl,
702+
ACL_REVISION,
703+
TOKEN_ALL_ACCESS,
704+
LocalSystemSid);
705+
if (!NT_SUCCESS(Status))
706+
goto done;
707+
708+
Status = RtlAddAccessAllowedAce(Dacl,
709+
ACL_REVISION,
710+
TOKEN_READ,
711+
AdministratorsSid);
712+
if (!NT_SUCCESS(Status))
713+
goto done;
714+
715+
Status = RtlAddAccessAllowedAce(Dacl,
716+
ACL_REVISION,
717+
TOKEN_ALL_ACCESS,
718+
User->User.Sid);
719+
if (!NT_SUCCESS(Status))
720+
goto done;
721+
722+
Status = RtlSetDaclSecurityDescriptor(&AbsoluteSd,
723+
TRUE,
724+
Dacl,
725+
FALSE);
726+
if (!NT_SUCCESS(Status))
727+
goto done;
728+
729+
Status = RtlSetOwnerSecurityDescriptor(&AbsoluteSd,
730+
AdministratorsSid,
731+
FALSE);
732+
if (!NT_SUCCESS(Status))
733+
goto done;
734+
735+
Status = RtlAbsoluteToSelfRelativeSD(&AbsoluteSd,
736+
RelativeSd,
737+
&RelativeSdSize);
738+
if (Status != STATUS_BUFFER_TOO_SMALL)
739+
goto done;
740+
741+
RelativeSd = RtlAllocateHeap(RtlGetProcessHeap(),
742+
HEAP_ZERO_MEMORY,
743+
RelativeSdSize);
744+
if (RelativeSd == NULL)
745+
{
746+
Status = STATUS_INSUFFICIENT_RESOURCES;
747+
goto done;
748+
}
749+
750+
Status = RtlAbsoluteToSelfRelativeSD(&AbsoluteSd,
751+
RelativeSd,
752+
&RelativeSdSize);
753+
if (!NT_SUCCESS(Status))
754+
goto done;
755+
756+
*TokenSd = RelativeSd;
757+
*TokenSdSize = RelativeSdSize;
758+
759+
done:
760+
if (Dacl != NULL)
761+
RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
762+
763+
if (AdministratorsSid != NULL)
764+
RtlFreeHeap(RtlGetProcessHeap(), 0, AdministratorsSid);
765+
766+
if (LocalSystemSid != NULL)
767+
RtlFreeHeap(RtlGetProcessHeap(), 0, LocalSystemSid);
768+
769+
if (!NT_SUCCESS(Status))
770+
{
771+
if (RelativeSd != NULL)
772+
RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
773+
}
774+
775+
return Status;
776+
}
777+
602778
/* EOF */

0 commit comments

Comments
 (0)