SPN 泄露
当Service Principal Names(SPNs)泄露时,可能会引发严重的安全风险,特别是在使用Kerberos身份验证的环境中。
- 身份欺骗(Identity Spoofing): 攻击者可以用泄露的SPN来伪装成合法的服务。
- 中间人攻击(Man-in-the-Middle Attacks): 攻击者可以用泄露的SPN作为中间人,截取和篡改通过Kerberos身份验证的通信。
- 凭据盗窃(Credential Theft): 如果泄露的SPN包含身份验证的凭据,攻击者可以用这些凭据进行凭据盗窃攻击。
- 服务拒绝攻击(Service Denial Attacks): 攻击者会用泄露的SPN对服务进行拒绝服务攻击。
- 认证绕过(Authentication Bypass): 攻击者可以绕过认证控制,直接访问受保护的资源。
维护措施:
- 定期审查SPN配置: 确保仅配置必要的SPN,定期审查以检测潜在的泄露。
- 敏感信息掩盖: 在SPN中避免包含敏感信息,减轻泄露的潜在风险。
- 加强凭据安全性: 使用服务帐户的凭据是强密码,并定期更改。
- 监控和审计: 实施监控和审计机制,及时检测并处理SPN泄露。
SPN 格式
服务主体名称(SPN)在利用Kerberos身份验证的服务发现中是必需的。
Microsoft Kerberos规范:
SPN格式介绍
SPN = serviceclass “/” hostname [“:”port] [“/” servicename]
serviceclass 是标识服务类别的字符串,例如Web服务的“www”或目录服务的“ldap”。
hostname 是系统名称的字符串,完全限定的域名(FQDN)。
port 是服务的端口号的数字。
servicename 段是服务的区别名称(DN)、objectGuid、Internet主机名或完全限定域名(FQDN)的字符串。
SPN 示例:
SQL 服务器、实例、端口:
MSSQLSvc/host01.example.com:1433
Exchange:
exchangeMDB/EXCAS01.example.com
RDP:
TERMSERV/EXCAS01.example.com
WSMan / WinRM / PS Remoting:
WSMAN/EXCAS01.example.com
Hyper-V主机:
Microsoft Virtual Console Service/HV01.example.com
VMWare VCenter:
STS/VC01.example.com
SPN 扫描
相对于网络端口扫描,SPN扫描对攻击者的主要优势在于不需要连接到网络上的每个IP来检查服务端口。SPN扫描通过LDAP查询到域控制器对服务扫描。由于SPN查询是正常Kerberos票证行为的一部分,很难发现。而网络端口扫描就很容易发现了。
# 服务器和域接口
$search = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
$search.filter = "(servicePrincipalName=*)"
$results = $search.Findall()
# 遍历SPN
foreach($result in $results)
{
$userEntry = $result.GetDirectoryEntry()
Write-host "Object Name = " $userEntry.name -backgroundcolor "yellow" -foregroundcolor "black"
Write-host "DN = " $userEntry.distinguishedName
Write-host "Object Catch = " $userEntry.objectCategory
Write-host "servicePrincipalNames:"
$i=1
foreach($SPN in $userEntry.servicePrincipalName)
{
Write-host "SPN(" $i ") = " $SPN $i+=1
}
Write-host ""
}
用户账户控制发现服务账户
在搜索Active Directory中寻找服务账户的另一种隐秘方法是账户控制设置,因为服务账户一般与常规用户账户设置不同。
一个不错的案例: “密码永不过期”设置
— 服务账户的密码被设置为永不过期,因为重置很麻烦,而且会导致应用程序或服务中断。
$ldapFilter = "(&(servicePrincipalName=*)(useraccountcontrol:1.2.840.113556.1.4.803:=65536))"
$search = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
$search.Filter = $ldapFilter
$results = $search.Findall()