Last active
June 10, 2025 13:10
-
-
Save zjorz/06a5cfa5211aaf40092effe9647fdd08 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ####### | |
| # Finding All Candidate EXPLICIT Allow ACEs To Investigate For dMSA Abuse In AD Domain | |
| ####### | |
| Clear-Host | |
| # Execution Date/Time | |
| $datetime = Get-Date | |
| # Local Computer Domain | |
| $fqdnADDomainOfComputer = $(Get-WmiObject -Class Win32_ComputerSystem).Domain # Focusing On The AD Domain FQDN Of The Computer | |
| # List Of SIDs To Filter Out | |
| # REMARK: To Filter Out Additional SIDs, Add The Well-Known Object SID(s) (Like e.g. Administrators) Or RID Specific Object SID(s) (Like e.g. Domain Admins) | |
| $sidsToFilterOut = @() | |
| $sidsToFilterOut += "S-1-5-32-544" # ADMINISTRATORS | |
| $sidsToFilterOut += "S-1-3-0" # CREATOR OWNER | |
| $sidsToFilterOut += "S-1-5-9" # NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS | |
| $sidsToFilterOut += "S-1-5-18" # NT AUTHORITY\SYSTEM | |
| $sidsToFilterOut += "DOMAIN_SID-512" # Domain Admins ("DOMAIN_SID" Will Be Replaced By The Respective SID Of The AD Domain) | |
| $sidsToFilterOut += "FOREST_SID-519" # Enterprise Admins ("FOREST_SID" Will Be Replaced By The Respective SID Of The Root AD Domain) | |
| # Locate An RWDC For The Current AD Domain And The Forest Root AD Domain | |
| $dcLocatorFlag = [System.DirectoryServices.ActiveDirectory.LocatorOptions]::"ForceRediscovery", "WriteableRequired" # Writeable DC | |
| $adDomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain", $fqdnADDomainOfComputer) # AD Domain Context | |
| $adDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($adDomainContext) # AD Domain Object | |
| $rwdcFQDN = $adDomain.FindDomainController($dcLocatorFlag).Name # RWDC In The AD Domain | |
| $adForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest() # AD Forest Object | |
| $rwdcFQDNDNM = $adForest.NamingRoleOwner.Name # RWDC In Forest Root With The Domain Naming Master FSMO Role | |
| $rwdcFQDNSCH = $adForest.SchemaRoleOwner.Name # RWDC In Forest Root With The Schema Master FSMO Role | |
| # Get The Default Naming Context, The Root Domain Naming Context, The Domain Object SID And The Root Domain Object SID From The RootDSE | |
| $rootDSE = [ADSI]"LDAP://$rwdcFQDN/RootDSE" # Root Dse Of RWDC In The AD Domain | |
| $domainNCDN = $rootDSE.defaultNamingContext # AD Domain NC DN, a.k.a. The Default Naming Context | |
| $domainFQDN = $domainNCDN.Replace(",DC=",".").Replace("DC=","") # AD Domain FQDN | |
| $rootDomainNCDN = $rootDSE.rootDomainNamingContext # Root AD Domain NC DN, a.k.a. The Root Naming Context | |
| $schemaNCDN = $rootDSE.schemaNamingContext # Schema NC DN, a.k.a. The Schema Naming Context | |
| $domain = [ADSI]"LDAP://$rwdcFQDN/$domainNCDN" # AD Domain Object | |
| $domainSid = $(New-Object Security.Principal.SecurityIdentifier($($domain.objectSid),0)).ToString() # AD Domain ObjectSID | |
| $forest = [ADSI]"LDAP://$rwdcFQDNDNM/$rootDomainNCDN" # Root AD Domain Object | |
| $forestSid = $(New-Object Security.Principal.SecurityIdentifier($($forest.objectSid),0)).ToString() # Root AD Domain ObjectSID | |
| $schema = [ADSI]"LDAP://$rwdcFQDN/$schemaNCDN" # AD Schema Object | |
| # List Of Security Principals To Filter Out, Translated From ObjectSIDs To Also Support Non-English ADs | |
| $securityPrincipalsToFilterOut = @() | |
| $sidsToFilterOut | ForEach-Object { | |
| $sid = $_.Replace("FOREST_SID","$forestSid").Replace("DOMAIN_SID","$domainSid") | |
| $objSID = New-Object System.Security.Principal.SecurityIdentifier($sid) | |
| $securityPrincipal = ($objSID.Translate([System.Security.Principal.NTAccount])).Value | |
| $securityPrincipalsToFilterOut += $securityPrincipal | |
| } | |
| # Query The Schema Naming Context For Object Classes That Can Have a Child msDS-DelegatedManagedServiceAccount | |
| $dsDirSearcher = New-Object DirectoryServices.DirectorySearcher([ADSI]"") | |
| $dsDirSearcher.SearchRoot = "LDAP://$rwdcFQDN/$schemaNCDN" | |
| $dsDirSearcher.SearchScope = "OneLevel" | |
| $dsDirSearcher.Filter = "(objectClass=classSchema)" | |
| [void]($dsDirSearcher.PropertiesToLoad.Add("lDAPDisplayName")) | |
| [void]($dsDirSearcher.PropertiesToLoad.Add("name")) | |
| [void]($dsDirSearcher.PropertiesToLoad.Add("possibleInferiors")) | |
| $listOfPossibleParentObjectTypesToInvestigate = @() | |
| $dsDirSearcher.FindAll() | Where-Object {$_.Properties.possibleinferiors -eq "msDS-DelegatedManagedServiceAccount"} | ForEach-Object { | |
| $listOfPossibleParentObjectTypesToInvestigate += $_.Properties.ldapdisplayname | |
| } | |
| # Query The Default Naming Context | |
| $dsDirSearcher = New-Object DirectoryServices.DirectorySearcher([ADSI]"") | |
| $dsDirSearcher.SearchRoot = "LDAP://$rwdcFQDN/$domainNCDN" | |
| $dsDirSearcher.SearchScope = "Subtree" | |
| $ldapFilterQueryDefaultNC = "(|" | |
| $listOfPossibleParentObjectTypesToInvestigate | ForEach-Object { | |
| $ldapFilterQueryDefaultNC += "(" | |
| $ldapFilterQueryDefaultNC += "objectClass=$_" | |
| $ldapFilterQueryDefaultNC += ")" | |
| } | |
| $ldapFilterQueryDefaultNC += "(objectClass=msDS-DelegatedManagedServiceAccount)" | |
| $ldapFilterQueryDefaultNC += ")" | |
| $dsDirSearcher.Filter = $ldapFilterQueryDefaultNC | |
| [void]($dsDirSearcher.PropertiesToLoad.Add("allowedChildClasses")) | |
| [void]($dsDirSearcher.PropertiesToLoad.Add("distinguishedName")) | |
| [void]($dsDirSearcher.PropertiesToLoad.Add("canonicalName")) | |
| [void]($dsDirSearcher.PropertiesToLoad.Add("nTSecurityDescriptor")) | |
| [void]($dsDirSearcher.PropertiesToLoad.Add("objectClass")) | |
| $listOfACEsToInvestigate = @() | |
| $dsDirSearcher.FindAll() | Where-Object { | |
| $_.Properties.distinguishedname[0] -notlike "*CN=System,$domainNCDN" -And ` | |
| ($_.Properties.allowedchildclasses -eq "msDS-DelegatedManagedServiceAccount" -Or ` | |
| $_.Properties.objectclass -eq "msDS-DelegatedManagedServiceAccount") | |
| } | ForEach-Object { | |
| $objDN = $_.Properties.distinguishedname[0] | |
| $objCanonicalName = $_.Properties.canonicalname[0] | |
| $objClass = ($_.Properties.objectclass)[$($_.Properties.objectclass | Measure-Object).Count - 1] | |
| $objNTSecurityDescriptor = $_.Properties.ntsecuritydescriptor[0] | |
| $adSecurity = $null | |
| $adSecurity = New-Object System.DirectoryServices.ActiveDirectorySecurity | |
| $adSecurity.SetSecurityDescriptorBinaryForm($objNTSecurityDescriptor) | |
| # Check The Current Owner Of The Object | |
| If ($adSecurity.Owner -notin $securityPrincipalsToFilterOut) { | |
| $aceToInvestigate = New-Object -TypeName System.Object | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Distinguished Name" -Value $objDN | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Canonical Name" -Value $objCanonicalName | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Object Class" -Value $objClass | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Security Principal" -Value $($adSecurity.Owner) | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Permissions" -Value "Owner Of Object" | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Applies To" -Value "Not Applicable" | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Attributes" -Value "Not Applicable" | |
| $listOfACEsToInvestigate += $aceToInvestigate | |
| } | |
| # Check The Current ACEs Of The Object | |
| $adSecurity.Access | Where-Object { | |
| $_.AccessControlType -eq "Allow" -And ` # Allow ACEs Only | |
| $_.IdentityReference.Value -notin $securityPrincipalsToFilterOut -And ` # Only Security Principals NOT In The Filter Out List | |
| $_.IsInherited -eq $false -And ` # Explicit (Non-Inherited) ACEs Only! | |
| ( ` | |
| ($_.ActiveDirectoryRights -match "CreateChild" -And ` | |
| ($_.ObjectType.Guid -eq "0feb936f-47b3-49f2-9386-1dedc2c23765" -Or ` # msDS-DelegatedManagedServiceAccount Objects | |
| $_.ObjectType.Guid -eq "00000000-0000-0000-0000-000000000000") ` # msDS-DelegatedManagedServiceAccount Objects | |
| ) -Or ` | |
| (($_.ActiveDirectoryRights -match "GenericAll" -Or ` | |
| $_.ActiveDirectoryRights -match "WriteDacl" -Or ` | |
| $_.ActiveDirectoryRights -match "WriteOwner") -And ` | |
| ($_.InheritedObjectType.Guid -eq "0feb936f-47b3-49f2-9386-1dedc2c23765" -Or ` # msDS-DelegatedManagedServiceAccount Objects | |
| $_.InheritedObjectType.Guid -eq "00000000-0000-0000-0000-000000000000" ` # All Objects (When Defined On A Container/OU) | |
| )) -Or ` | |
| ($_.ActiveDirectoryRights -match "WriteProperty" -And ` | |
| ($_.ObjectType.Guid -eq "2f5c138a-bd38-4016-88b4-0ec87cbb4919" -Or ` # msDS-DelegatedMSAState Attribute | |
| $_.ObjectType.Guid -eq "a0945b2b-57a2-43bd-b327-4d112a4e8bd1" -Or ` # msDS-ManagedAccountPrecededByLink Attribute | |
| $_.ObjectType.Guid -eq "00000000-0000-0000-0000-000000000000") -And ` # All Attributes | |
| ($_.InheritedObjectType.Guid -eq "0feb936f-47b3-49f2-9386-1dedc2c23765" -Or ` # msDS-DelegatedManagedServiceAccount Objects | |
| $_.InheritedObjectType.Guid -eq "00000000-0000-0000-0000-000000000000") ` # All Objects (When Defined On A Container/OU) | |
| )) | |
| } | ForEach-Object { | |
| $aceToInvestigate = New-Object -TypeName System.Object | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Distinguished Name" -Value $objDN | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Canonical Name" -Value $objCanonicalName | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Object Class" -Value $objClass | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Security Principal" -Value $($_.IdentityReference.Value) | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Permissions" -Value $($_.ActiveDirectoryRights) | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Applies To" -Value $( ` | |
| If ($_.ActiveDirectoryRights -match "CreateChild" -And $_.ObjectType.Guid -eq "00000000-0000-0000-0000-000000000000" -And $_.InheritanceType -eq "None") { | |
| "This Object Only (All Object Types)" | |
| } ElseIf ($_.ActiveDirectoryRights -match "CreateChild" -And $_.ObjectType.Guid -eq "00000000-0000-0000-0000-000000000000" -And $_.InheritanceType -eq "All") { | |
| "This Object And All Descendant Objects (All Object Types)" | |
| } ElseIf ($_.ActiveDirectoryRights -match "CreateChild" -And $_.ObjectType.Guid -eq "00000000-0000-0000-0000-000000000000" -And $_.InheritanceType -eq "Descendents") { | |
| "All Descendant Objects (All Object Types)" | |
| } ElseIf ($_.ActiveDirectoryRights -match "CreateChild" -And $_.ObjectType.Guid -eq "0feb936f-47b3-49f2-9386-1dedc2c23765" -And $_.InheritanceType -eq "None") { | |
| "This Object Only ('msDS-DelegatedManagedServiceAccount' Object Types)" | |
| } ElseIf ($_.ActiveDirectoryRights -match "CreateChild" -And $_.ObjectType.Guid -eq "0feb936f-47b3-49f2-9386-1dedc2c23765" -And $_.InheritanceType -eq "All") { | |
| "This Object And All Descendant Objects ('msDS-DelegatedManagedServiceAccount' Object Types)" | |
| } ElseIf ($_.ActiveDirectoryRights -match "CreateChild" -And $_.ObjectType.Guid -eq "0feb936f-47b3-49f2-9386-1dedc2c23765" -And $_.InheritanceType -eq "Descendents") { | |
| "All Descendant Objects 'msDS-DelegatedManagedServiceAccount' Object Types)" | |
| } ElseIf ($_.InheritanceType -eq "None") { | |
| "This Object Only" | |
| } ElseIf ($_.InheritanceType -eq "All") { | |
| "This Object And All Descendant Objects" | |
| } ElseIf ($_.InheritanceType -eq "Descendents" -And $_.InheritedObjectType.Guid -eq "00000000-0000-0000-0000-000000000000") { | |
| "All Descendant Objects" | |
| } ElseIf ($_.InheritanceType -eq "Descendents" -And $_.InheritedObjectType.Guid -eq "0feb936f-47b3-49f2-9386-1dedc2c23765") { | |
| "All Descendant 'msDS-DelegatedManagedServiceAccount' Objects" | |
| } Else { | |
| # PlaceHolder | |
| } ` | |
| ) | |
| $aceToInvestigate | Add-Member -MemberType NoteProperty -Name "Attributes" -Value $( ` | |
| If ($_.ActiveDirectoryRights -match "GenericAll") { | |
| "All Attributes" | |
| } ElseIf ($_.ActiveDirectoryRights -match "WriteDacl" -Or $_.ActiveDirectoryRights -match "WriteOwner") { | |
| "Not Applicable" | |
| } ElseIf ($_.ActiveDirectoryRights -match "WriteProperty" -And $_.ObjectType.Guid -eq "2f5c138a-bd38-4016-88b4-0ec87cbb4919") { | |
| "'msDS-DelegatedMSAState' Attribute" | |
| } ElseIf ($_.ActiveDirectoryRights -match "WriteProperty" -And $_.ObjectType.Guid -eq "a0945b2b-57a2-43bd-b327-4d112a4e8bd1") { | |
| "'msDS-ManagedAccountPrecededByLink' Attribute" | |
| } ElseIf ($_.ActiveDirectoryRights -match "WriteProperty" -And $_.ObjectType.Guid -eq "00000000-0000-0000-0000-000000000000") { | |
| "All Attributes" | |
| } Else { | |
| "All Attributes" | |
| } | |
| ) | |
| $listOfACEsToInvestigate += $aceToInvestigate | |
| } | |
| } | |
| # Export To XML File | |
| $listOfACEsToInvestigate | Export-CliXml -Path ".\$(Get-Date $datetime -Format 'yyyy-MM-dd_HH.mm.ss')_Candidate-EXPLICIT-Allow-ACEs-To-Investigate-For-dMSA-Abuse-In-Domain-$domainFQDN.xml" | |
| # Export To Grid View | |
| $listOfACEsToInvestigate | Sort-Object -Property "Canonical Name" | Out-GridView -Title "Candidate EXPLICIT Allow ACEs To Investigate For dMSA Abuse In Domain '$domainFQDN' ($(Get-Date $datetime -Format 'yyyy-MM-dd HH:mm:ss'))" | |
| # Import XML Into Grid View | |
| # Import-CliXml -Path ".\$(Get-Date $datetime -Format 'yyyy-MM-dd_HH.mm.ss')_Candidate-EXPLICIT-Allow-ACEs-To-Investigate-For-dMSA-Abuse-In-Domain-$domainFQDN.xml" | Sort-Object -Property "Canonical Name" | Out-GridView -Title "Candidate EXPLICIT Allow ACEs To Investigate For dMSA Abuse In Domain '$domainFQDN' ($(Get-Date $datetime -Format 'yyyy-MM-dd HH:mm:ss'))" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment