DirSync: Leveraging Replication Get-Changes and Get-Changes-In-Filtered-Set
- A Quick Glance at What Can Be Done
- Describing Concepts
- The Technique
- DirSync: A Proof of Concept Tool
- Some Unorganized Notes
- To Conclude
DCSync can be categorized as one of the most effective technique on a domain, since retrieving the
krbtgt NT hash allows to forge a valid ticket-granting ticket for any domain user. To manage to do so, a principal must possess the right privileges over the root of a domain: DS-Replication-Get-Changes and DS-Replication-Get-Changes-All. The combination renders it possible to successfully call MS-DRSR’s GetNCChanges to replicate secret attributes.
Recently, I stumbled upon a principal with only
DS-Replication-Get-Changes over a domain, which lead to investigating the impact, along with its sibling DS-Replication-Get-Changes-In-Filtered-Set.
This post is dedicated to presenting the consequences of delegating these privileges, and includes a proof of concept PowerShell module to demonstrate the technique for defensive and adversarial simulation purposes.
A Quick Glance at What Can Be Done
DS-Replication-Get-Changesallows to read the value of confidential attributes.
DS-Replication-Get-Changes-In-Filtered-Set, coupled with
DS-Replication-Get-Changes, allows to read the value of confidential and Read-Only Domain Controller (RODC) filtered attributes, such as Local Administrator Password Solution’s (LAPS)
Before we move on, some Active Directory concepts must first be described.
The searchFlags Attribute
The Schema Naming Context, located at
CN=Schema,CN=Configuration,DC=contoso,DC=com contains an object for all attributes that can be set on objects found in Active Directory. Just as regular objects, these objects also have attributes set on them, effectively having attributes on an attribute object.
To make sense out of this, let us look at this concrete example.
CN=ms-Mcs-AdmPwd,CN=Schema,CN=Configuration,DC=contoso,DC=com resides the object of an attribute that you may be familiar with:
ms-Mcs-AdmPwd. This attribute is used to store the password of the local administrator managed by LAPS. When viewing its object, we can see some attributes that are either set or unset, and more specifically in our case, searchFlags:
CN=Search-Flags) includes an important feature: it can dictate whether an attribute is to be shown to a user that requests to see its value. Indeed, when the
searchFlags attribute contains the flag
fCONFIDENTIAL (0x00000080), a user requesting to see the value must have the explicit privileges to read it (RIGHT_DS_READ_PROPERTY and RIGHT_DS_CONTROL_ACCESS).
Going back to our example, since
searchFlags has the flag
fCONFIDENTIAL, a user that wants to read the attribute
ms-Mcs-AdmPwd on a computer object must have
RIGHT_DS_CONTROL_ACCESS on it; otherwise, the attribute will be returned as empty. By doing so, LAPS ensures that only principals with the right privileges delegated over computer objects can read the attribute.
One last flag supported by
searchFlags worth mentioning is
fRODCFilteredAttribute (0x00000200). Essentially, this states that an attribute cannot be replicated to a RODC. Note that
ms-Mcs-AdmPwd also has this flag, and will come into play later on.
LDAP Extended Controls
LDAP Extended Controls, often simply named LDAP Controls, is a feature that was introduced in LDAPv3. By specifically crafting a request message with an object identifier (OID), a Domain Controller (DC) can be asked to perform a certain set of operations. For instance, the control named LDAP_SERVER_CROSSDOM_MOVE_TARGET_OID (OID 1.2.840.1135188.8.131.521) is used to request that a DC moves an object to another domain.
This control is used to retrieve from a DC any changes made to Active Directory objects since the last time a synchronization was requested, and is the technique that will be used to read the values of attributes with the flags
The documentation also contains a valuable piece of information: pseudocode of the security check performed when a directory synchronization is requested:
Experimenting With LDAP_SERVER_DIRSYNC_OID
After going through some documentation, interesting points arise:
- .NET’s System.DirectoryServices.Protocols.DirSyncRequestControl is an easy way to request a directory synchronization, and an example script can be found here.
- The flag
LDAP_DIRSYNC_OBJECT_SECURITYcan be used to request a synchronization without having the
DS-Replication-Get-Changesprivileges, but only returns attributes that the requester can read. Since we wish to read attributes that we normally cannot, we will avoid sending this.
- An LDAP filter can be specified to only synchronize objects that match it.
- We can also request a specific set of attributes to be synchronized.
Before executing the aforementioned example script, the following has been altered:
- The script handles a cookie to only get the changes made since our last request, but has been removed since this serves us no purpose.
- Filtering is done on
- We only print a few attributes from the response for the sake of clarity, despite requesting all of them.
Once the executing user has been delegated
DS-Replication-Get-Changes, the directory synchronization succeeds:
Without these delegated privileges, the
SendRequest function fails, and returns the error message
The user has insufficient access rights, as we also saw from the security check pseudocode.
So far so good, but nothing impressive; these can be retrieved with a standard LDAP query.
Accessing Confidential Attributes With DS-Replication-Get-Changes
In the previous
searchFlags section, we have established that some attributes are confidential, and cannot be read without having explicit privileges over the object. While some attributes are confidential by default, it is possible to alter existing
searchFlags to set some other attributes to confidential, or to create your own confidential attribute.
You can query for confidential attributes like so:
1.2.840.1135184.108.40.2064is a bitwise OR operator ensuring that we look for the flag
fCONFIDENTIALwithin all the other flags, and not just this value.
128(0x00000080) refers to
- We exclude
fRODCFilteredAttribute, requiring more privileges.
As a proof of concept, the attribute
unixUserPassword will be used. It is sometimes used to store a user’s UNIX password hash.
In our example, when querying for this attribute through a regular LDAP query for the user
Administrator, nothing is returned, confirming that we do not have the right privileges over the object:
However, if we modify our script to print this attribute, we see that it was indeed synchronized:
Accessing RODC Filtered Attributes With DS-Replication-Get-Changes-In-Filtered-Set
In order to successfully use these privileges, one must also have
DS-Replication-Get-Changes, otherwise the LDAP control will deny the request, as denoted in the pseudocode.
Similarly to the last section, we can query for attributes with the flag
fRODCFilteredAttribute. We do not need to exclude confidential attributes; we also have the required privileges for these:
ms-Mcs-AdmPwd, these attributes should all be present in a modern, vanilla installation of Active Directory.
Let us focus on
ms-Mcs-AdmPwd. As briefly mentioned in the impact section, this attribute is used by LAPS to store the current password of the managed local administrator, which will either be the default
Administrator account, or a custom one.
With our new privileges, we attempt to retrieve the attribute of a LAPS-enabled computer object through a LDAP query, but to no avail:
What if we mimic the same procedure as before, and simply print the attribute through our script? The value of the attribute turns out to be empty.
To successfully get the value of a
fRODCFilteredAttribute attribute, we must explicitly specify that we wish to synchronize it when constructing the
SearchRequest. It can be done by replacing the
$null value in the
SearchRequest object of our previous script to an array containing the list of attributes, for instance
('ms-Mcs-AdmPwd'), that we desire to fetch.
Once edited and executed again, the password is printed:
If attempting to run this modified script without
DS-Replication-Get-Changes-In-Filtered-Set, we will be greeted with the same error message
The user has insufficient access rights as before, due to attempting to synchronize a specific attribute with
fRODCFilteredAttribute. Again, this is on par with what was written in the security check pseudocode.
DirSync: A Proof of Concept Tool
DirSync is a simple proof of concept PowerShell module to demonstrate the impact of delegating these privileges. It offers two functions:
Sync-LAPS to directly focus on LAPS, and
Sync-Attributes to synchronize any desired attributes. Usage can be found in the README.md file, and via the usual
Get-Help PowerShell command.
A Remark for Blue Teamers
Keep in mind that this technique uses an LDAP request, and not RPC like
DCSync. While the tool is designed by default to communicate over plain text for compatibility reasons, it also supports LDAPS. If your DCs have a certificate installed allowing to use LDAPS, do not rely on over-the-wire detection, unless you hold decryption capabilities.
The Wireshark website contains an example capture file of the
DirSync control over plain LDAP, filtering on
(ObjectClass=*) and requesting no specific attributes.
Some Unorganized Notes
- It might very well be possible to achieve the same result with these privileges using
- I did not manage to read secret attributes such as unicodePwd using
- As mentioned in the pseudocode,
DS-Replication-Get-Changes-Allcan be used instead of
DS-Replication-Get-Changes-In-Filtered-Setto read RODC filtered attributes. As you can also perform a full-blown
DCSyncwith those privileges, I do not expect
DirSyncto be the technique of choice, unless it offers some operational security.
- There are multiple ways to track changes in a directory.
- I have not investigated the significance of being able to read the built-in confidential and RODC filtered attributes.
While clearly not as impactful as
DirSync presents an alternative to synchronize confidential and RODC filtered attributes. The demonstrated LAPS scenario could be used to introduce a new edge into BloodHound, and is a good candidate to look for during Active Directory privileges assessments.
A thank you to @joewaredotnet for the article Replicating Changes Control Access Right series that contributed to my curiousness.