diff --git a/Recon/PowerView.ps1 b/Recon/PowerView.ps1 index 2dc5234a..3194c49c 100755 --- a/Recon/PowerView.ps1 +++ b/Recon/PowerView.ps1 @@ -7777,6 +7777,168 @@ System.Security.AccessControl.AuthorizationRule } +function Get-DomainObjectOwner { +<# +.SYNOPSIS + +Get the owner of a specified Active Directory object. + +Author: William Bruneau (@WilliamBruneau) +License: BSD 3-Clause +Required Dependencies: Get-DomainObject + +.DESCRIPTION + +Retrieves the owner of the Active Directory object specified by -Identity by +splatting to Get-DomainObject, returning the raw searchresult object. + +.PARAMETER OnlySID + +Only return the owner SID. + +.PARAMETER Identity + +A SamAccountName (e.g. harmj0y), DistinguishedName (e.g. CN=harmj0y,CN=Users,DC=testlab,DC=local), +SID (e.g. S-1-5-21-890171859-3433809279-3366196753-1108), or GUID (e.g. 4c435dd7-dc58-4b14-9a5e-1fdb0e80d201) +of the AD object to set the owner for. + +.PARAMETER Domain + +Specifies the domain to use for the query, defaults to the current domain. + +.PARAMETER LDAPFilter + +Specifies an LDAP query string that is used to filter Active Directory objects. + +.PARAMETER SearchBase + +The LDAP source to search through, e.g. "LDAP://OU=secret,DC=testlab,DC=local" +Useful for OU queries. + +.PARAMETER Server + +Specifies an Active Directory server (domain controller) to bind to. + +.PARAMETER SearchScope + +Specifies the scope to search under, Base/OneLevel/Subtree (default of Subtree). + +.PARAMETER ResultPageSize + +Specifies the PageSize to set for the LDAP searcher object. + +.PARAMETER ServerTimeLimit + +Specifies the maximum amount of time the server spends searching. Default of 120 seconds. + +.PARAMETER Tombstone + +Switch. Specifies that the searcher should also return deleted/tombstoned objects. + +.PARAMETER Credential + +A [Management.Automation.PSCredential] object of alternate credentials +for connection to the target domain. + +.EXAMPLE + +Get-DomainObjectOwner -Identity dfm + +Get the owner of 'dfm' in the current domain +#> + + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')] + [CmdletBinding()] + Param( + [Switch] + $OnlySID, + + [Parameter(Position = 0, Mandatory = $True, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)] + [Alias('DistinguishedName', 'SamAccountName', 'Name')] + [String] + $Identity, + + [ValidateNotNullOrEmpty()] + [String] + $Domain, + + [ValidateNotNullOrEmpty()] + [Alias('Filter')] + [String] + $LDAPFilter, + + [ValidateNotNullOrEmpty()] + [Alias('ADSPath')] + [String] + $SearchBase, + + [ValidateNotNullOrEmpty()] + [Alias('DomainController')] + [String] + $Server, + + [ValidateSet('Base', 'OneLevel', 'Subtree')] + [String] + $SearchScope = 'Subtree', + + [ValidateRange(1, 10000)] + [Int] + $ResultPageSize = 200, + + [ValidateRange(1, 10000)] + [Int] + $ServerTimeLimit, + + [Switch] + $Tombstone, + + [Management.Automation.PSCredential] + [Management.Automation.CredentialAttribute()] + $Credential = [Management.Automation.PSCredential]::Empty + ) + + BEGIN { + $SearcherArguments = @{} + if ($PSBoundParameters['Domain']) { $SearcherArguments['Domain'] = $Domain } + if ($PSBoundParameters['LDAPFilter']) { $SearcherArguments['LDAPFilter'] = $LDAPFilter } + if ($PSBoundParameters['SearchBase']) { $SearcherArguments['SearchBase'] = $SearchBase } + if ($PSBoundParameters['Server']) { $SearcherArguments['Server'] = $Server } + if ($PSBoundParameters['SearchScope']) { $SearcherArguments['SearchScope'] = $SearchScope } + if ($PSBoundParameters['ResultPageSize']) { $SearcherArguments['ResultPageSize'] = $ResultPageSize } + if ($PSBoundParameters['ServerTimeLimit']) { $SearcherArguments['ServerTimeLimit'] = $ServerTimeLimit } + if ($PSBoundParameters['Tombstone']) { $SearcherArguments['Tombstone'] = $Tombstone } + if ($PSBoundParameters['Credential']) { $SearcherArguments['Credential'] = $Credential } + } + + PROCESS { + $SearcherArguments['SecurityMasks'] = 'Owner' + $SearcherArguments['Raw'] = $True + $SearcherArguments['Identity'] = $Identity + + # splat the appropriate arguments to Get-DomainObject + $Objects = Get-DomainObject @SearcherArguments + + ForEach ($Object in $Objects) { + # parse ntsecuritydescriptor + $ObjectSd = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $Object.Properties['ntsecuritydescriptor'][0], 0 + + $OwnerSid = $ObjectSd.Owner + if ($PSBoundParameters['OnlySID']) { + $OwnerSid + } + else { + $Owner = Get-DomainObject $OwnerSid + if (!$Owner) { + throw "[Get-DomainObjectOwner] Cannot find object with SID: $($OwnerSid.Value)" + } + $Owner + } + } + } +} + + function Set-DomainObjectOwner { <# .SYNOPSIS