Skip to content
This repository has been archived by the owner on Jan 21, 2021. It is now read-only.

PowerView: add Get-DomainObjectOwner #327

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions Recon/PowerView.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down