AD replication-based attacks [1]

The specification of the MS-DRSR protocol used by DCs when replicating in an Active Directory environment dictates the IDL_DRSGetNCChanges method of the DRSUAPI RPC interface used to replicate changes to NC replicas.

The requisite permissions to conduct a DCSync operation, as prescribed by default, are vested in the following categories of entities:

  • Domain Controllers:
  • The Ds-Replication-Get-Changes privilege is delegated from NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS.
  • The DS-Replication-Get-Changes-All privilege is delegated from $DOMAIN\Domain Controllers.
  • Members of the BUILTIN\Administrators group, which encompasses the Domain Admins and Enterprise Admins.

The enumeration of the proprietors of the aforesaid privileges can be done via the Get-ACL cmdlet:

$dcdn = 'DC=CONTOSO,DC=LOCAL';
$guid = '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2';
(Get-ACL -Path 'AD:$dcdn').Access | Where-Object {$_.ObjectType -match '$guid'}

During the processing of the IDL_DRSGetNCChanges request by a domain controller, the validation of access rights is executed by means of a IsGetNCChangesPermissionGranted procedure. This procedure is composed of several phases, which are articulated as follows:

  1. An evaluation of the client's extended privilege denominated as Ds-Replication-Get-Changes (1131f6aa-9c07-11d1-f79f-00c04fc2dcd2) against the domain object.
  2. The IsRevealSecretRequest method confirms an attempt to request secret attributes followed by checking the client right DS-Replication-Get-Changes-All (1131f6ad-9c07-11d1-f79f-00c04fc2dcd2) against the domain object.
  3. The IsRevealFilteredAttr method confirms an attempt to request attributes as part of a filtered set, followed by a check of client rights Ds-Replication-Get-Changes-In-Filtered-Set (89e95b76-444d-4c62-991a-0facbeda640c) chained with DS-Replication-Get-Changes-All

The confidentiality of an attribute is determined using an IsSecretAttribute($ATTRIBUTE) procedure, which matches the type of an attribute against a predefined list.

Detecting and blocking dangerous replication traffic at the network level is easier in a segmented network, where DCs are located within a separate VLAN. Correct segmentation allows for signatures to be introduced that target DCE/RPC DRSUAPI calls originating from sources outside the DC VLAN, namely IDL_DRSGetNCChanges requests from a client address other than those in the DC list.

Native event 4662 (“An operation was performed on an object”) is generated during replication from objects that have an entry in the domain object’s SACL and during the operation use the Ds-Replication-Get-Changes / DS-Replication-Get-Changes-All rights /Ds-Replication-Get-Changes-In-Filtered-Set against domain.

POC Adding records with the extended rights Ds-Replication-Get-Changes and Ds-Replication-Get-Changes-All to the DACL of the domain ACE object. Adding can be done through the native cmdlets Get-Acl and Set-Acl. The ACE of the ActiveDirectoryAuditRule class is generally identical to the ActiveDirectoryAccessRule, with the only difference being the required AuditFlags attribute and the addition via AddAuditRule.

>> $path = 'AD:\DC=contoso,DC=local';
>> $acl = Get-ACL -Path $path -Audit;
>> $ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
>> 	[System.Security.Principal.IdentityReference] ([System.Security.Principal.SecurityIdentifier] 'S-1-5-21-3711008237-1532375651-712317569-500'),
>> 	[System.DirectoryServices.ActiveDirectoryRights] 'ExtendedRight',
>> 	[System.Security.AccessControl.AccessControlType] 'Allow',
>> 	[System.GUID] '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2'); # 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2
>> $acl.AddAccessRule($ace);
>>
>> Set-ACL -Path $path -AclObject $acl

For example, logging of the execution process of mimikatz' lsadump::dcsync module on behalf of a test user is viewed by the Get-WinEvent cmdlet with filtering settings.

.\mimikatz.exe "lsadump::dcsync /domain:contoso.local /user:Administrator" exit

Get-WinEvent -FilterHashtable @{ID = 4662; LogName = '*'; StartTime = ((Get-Date) - (New-TimeSpan -Days 1))} | Where-Object {$_.Message -match 'Access Mask:.*0x100' -and $_Message -match 'Properties:.*\n.*{1131f6ad-9c07-11d1-f79f-00c04fc2dcd2}' -and ($_Message -notmatch 'Account Name:.*WIN-IPNA74QL8IE' -and $_Message -notmatch 'Account Name:.*WIN-9IGSLDJ4THF')} | Format-List