0x01 关于SPN

服务主体名称(SPN)是Kerberos客户端用于唯一标识给特定Kerberos目标计算机的服务实例名称。

服务主体名称是服务实例(可以理解为一个服务,比如 HTTP、MSSQL)的唯一标识符。Kerberos 身份验证使用 SPN 将服务实例与服务登录帐户相关联

在内部网络中,SPN扫描通过 查询向域控制器执行服务发现。这对于红队而言,可以帮助他们识别正在运行重要服务的主机,如终端、交换机、微软SQL等,并隐藏他们。此外,SPN的识别也是kerberoasting攻击的第一步。

0x02 SPN基础配置

详细可以查看微软官方手册

https://docs.microsoft.com/zh-cn/windows-server/networking/sdn/security/kerberos-with-spn

在 SPN 的语法中存在四种元素,两个必须元素和两个额外元素,其中<service class>和<host>为必须元素:

<serviceclass>/<host>:<port>/<service name>

<service class>:标识服务类的字符串

<host>:服务所在主机名称

<port>:服务端口

<service name>:服务名称
常见服务和spn服务实例名称
MSSQL

MSSQLSvc/adsmsSQLAP01.adsecurity.org:

Exchange

exchangeMDB/adsmsEXCAS01.adsecurity.org

RDP

TERMSERV/adsmsEXCAS01.adsecurity.org

WSMan / WinRM / PS Remoting

WSMAN/adsmsEXCAS01.adsecurity.org

Hyper-V Host

Microsoft Virtual Console Service/adsmsHV01.adsecurity.org

VMWare VCenter

STS/adsmsVC01.adsecurity.org
提一下SPN的注册

这里以SQL Server服务为例子。

SQL Server在每次启动的时候,都会去尝试用自己的启动账号注册SPN。但是在Windows域里,默认普通机器账号有权注册SPN,但是普通域用户账号是没有权利注册SPN的。这就会导致这样一个现象,SQL Server如果使用“Local System account”来启动,Kerberos就能够成功,因为SQL Server这时可以在DC上注册SPN。如果用一个域用户来启动,Kerberos就不能成功,因为这时SPN注册不上去。

解决的方法之一,当然可以使用工具SetSPN -S来手动注册SPN。但是这不是一个最好的方法,毕竟手工注册不是长久之计。如果SPN下次丢了,又要再次手动注册。所以比较好的方法,是让SQL Server当前的启动账号有注册SPN的权力。要DC上为域账号赋予“Read servicePrincipalName”和“Write serverPrincipalName”的权限即可。

SetSPN

SetSPN是一个本地windows二进制文件,可用于检索用户帐户和服务之间的映射。该实用程序可以添加,删除或查看SPN注册。

这里在我dc上进行SPN服务(MSSQL)的注册。

Setspn -A MSSQLSvc/DC-1.qing.com:1433 tsvc

注册成功之后可以通过下面两个命令来查看已经注册的 SPN。

setspn -Q */*
 setspn -T DC-1.qing.com -Q */*

 注意这里是写机器的FQDN

0x03 SPN扫描

附上MSSQL的spn扫描脚本

function Discover-PSMSSQLServers
{ <#
.SYNOPSIS
This script is used to discover Microsoft SQL servers without port scanning.
SQL discovery in the Active Directory Forest is performed by querying an Active Directory Gloabl Catalog via ADSI. Discover-PSMSSQLServers
Author: Sean Metcalf, Twitter: @PyroTek3
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None Last Updated: 2/04/2015
Version: 2.3 .DESCRIPTION
This script is used to discover Microsoft SQL servers in the Active Directory Forest. Currently, the script performs the following actions:
* Queries a Global Catalog in the Active Directory root domain for all Microsoft SQL SPNs in the forest
* Displays the Microsoft SQL server FQDNs ports and instances
* Identifies any service accounts associated with the SQL instance and includes the account info REQUIRES: Active Directory user authentication. Standard user access is fine - admin access is not necessary. .EXAMPLE
Discover-PSMSSQLServers
Perform Microsoft SQL Server discovery via AD and returns the results in a custom PowerShell object. .NOTES
This script is used to discover Microsoft SQL servers in the Active Directory Forest and can also provide additional computer information such as OS and last bootup time. .LINK
Blog: http://www.ADSecurity.org
Github repo: https://github.com/PyroTek3/PowerShell-AD-Recon #> Param
( ) Write-Verbose "Get current Active Directory domain... "
$ADForestInfo = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$ADForestInfoRootDomain = $ADForestInfo.RootDomain
$ADForestInfoRootDomainDN = "DC=" + $ADForestInfoRootDomain -Replace("\.",',DC=') $ADDomainInfoLGCDN = 'GC://' + $ADForestInfoRootDomainDN Write-Verbose "Discovering Microsoft SQL Servers in the AD Forest $ADForestInfoRootDomainDN "
$root = [ADSI]$ADDomainInfoLGCDN
$ADSearcher = new-Object System.DirectoryServices.DirectorySearcher($root,"(serviceprincipalname=mssql*)")
$ADSearcher.PageSize = 50000
$AllADSQLServerSPNs = $ADSearcher.FindAll() $AllADSQLServerSPNsCount = $AllADSQLServerSPNs.Count Write-Output "Processing $AllADSQLServerSPNsCount (user and computer) accounts with MS SQL SPNs discovered in AD Forest $ADForestInfoRootDomainDN `r " $AllMSSQLSPNs = $NULL
$AllMSSQLSPNHashTable =@{}
$AllMSSQLServiceAccountHashTable =@{}
ForEach ($AllADSQLServerSPNsItem in $AllADSQLServerSPNs)
{
$AllADSQLServerSPNsItemDomainName = $NULL
[array]$AllADSQLServerSPNsItemArray = $AllADSQLServerSPNsItem.Path -Split(",DC=")
[int]$DomainNameFECount = 0
ForEach ($AllADSQLServerSPNsItemArrayItem in $AllADSQLServerSPNsItemArray)
{
IF ($DomainNameFECount -gt 0)
{ [string]$AllADSQLServerSPNsItemDomainName += $AllADSQLServerSPNsItemArrayItem + "." }
$DomainNameFECount++
}
$AllADSQLServerSPNsItemDomainName = $AllADSQLServerSPNsItemDomainName.Substring(0,$AllADSQLServerSPNsItemDomainName.Length-1) ForEach ($ADSISQLServersItemSPN in $AllADSQLServerSPNsItem.properties.serviceprincipalname)
{
IF ( ($ADSISQLServersItemSPN -like "MSSQL*") -AND ($ADSISQLServersItemSPN -like "*:*") )
{
IF (($AllADSQLServerSPNsItem.properties.objectcategory -like "CN=Person*") -AND ($ADSISQLServersItemSPNServerFQDN) )
{
$AllMSSQLServiceAccountHashTable.Set_Item($ADSISQLServersItemSPNServerFQDN,$AllADSQLServerSPNsItem.properties.distinguishedname)
}
$ADSISQLServersItemSPNArray1 = $ADSISQLServersItemSPN -Split("/")
$ADSISQLServersItemSPNArray2 = $ADSISQLServersItemSPNArray1 -Split(":")
[string]$ADSISQLServersItemSPNServerFQDN = $ADSISQLServersItemSPNArray2[1]
IF ($ADSISQLServersItemSPNServerFQDN -notlike "*$AllADSQLServerSPNsItemDomainName*" )
{ $ADSISQLServersItemSPNServerFQDN = $ADSISQLServersItemSPNServerFQDN + "." + $AllADSQLServerSPNsItemDomainName }
[string]$AllMSSQLSPNsItemServerInstancePort = $ADSISQLServersItemSPNArray2[2] $AllMSSQLSPNsItemServerName = $ADSISQLServersItemSPNServerFQDN -Replace(("."+ $AllADSQLServerSPNsItemDomainName),"") $AllMSSQLSPNHashTableData = $AllMSSQLSPNHashTable.Get_Item($ADSISQLServersItemSPNServerFQDN)
IF ( ($AllMSSQLSPNHashTableData) -AND ($AllMSSQLSPNHashTableData -notlike "*$AllMSSQLSPNsItemServerInstancePort*") )
{
$AllMSSQLSPNHashTableDataUpdate = $AllMSSQLSPNHashTableData + ";" + $AllMSSQLSPNsItemServerInstancePort
$AllMSSQLSPNHashTable.Set_Item($ADSISQLServersItemSPNServerFQDN,$AllMSSQLSPNHashTableDataUpdate)
}
ELSE
{ $AllMSSQLSPNHashTable.Set_Item($ADSISQLServersItemSPNServerFQDN,$AllMSSQLSPNsItemServerInstancePort) }
}
}
} ###
Write-Verbose "Loop through the discovered MS SQL SPNs and build the report "
###
$ALLSQLServerReport = @()
#$AllMSSQLServerFQDNs = $NULL
ForEach ($AllMSSQLSPNsItem in $AllMSSQLSPNHashTable.GetEnumerator())
{
$AllMSSQLSPNsItemServerDomainName = $NULL
$AllMSSQLSPNsItemServerDomainDN = $NULL
$AllMSSQLSPNsItemServiceAccountDN = $NULL
$AllMSSQLSPNsItemServiceAccountDomainDN = $NULL $AllMSSQLSPNsItemServerFQDN = $AllMSSQLSPNsItem.Name
#[array]$AllMSSQLServerFQDNs += $AllMSSQLSPNsItemServerFQDN
$AllMSSQLSPNsItemInstancePortArray = ($AllMSSQLSPNsItem.Value) -Split(';') $AllMSSQLSPNsItemServerFQDNArray = $AllMSSQLSPNsItemServerFQDN -Split('\.')
[int]$FQDNArrayFECount = 0
ForEach ($AllMSSQLSPNsItemServerFQDNArrayItem in $AllMSSQLSPNsItemServerFQDNArray)
{
IF ($FQDNArrayFECount -ge 1)
{
[string]$AllMSSQLSPNsItemServerDomainName += $AllMSSQLSPNsItemServerFQDNArrayItem + "."
[string]$AllMSSQLSPNsItemServerDomainDN += "DC=" + $AllMSSQLSPNsItemServerFQDNArrayItem + ","
}
$FQDNArrayFECount++
} $AllMSSQLSPNsItemServerDomainName = $AllMSSQLSPNsItemServerDomainName.Substring(0,$AllMSSQLSPNsItemServerDomainName.Length-1)
$AllMSSQLSPNsItemServerDomainDN = $AllMSSQLSPNsItemServerDomainDN.Substring(0,$AllMSSQLSPNsItemServerDomainDN.Length-1)
$AllMSSQLSPNsItemServerDomainLDAPDN = "LDAP://$AllMSSQLSPNsItemServerDomainDN" $AllMSSQLSPNsItemServerName = $AllMSSQLSPNsItemServerFQDN -Replace(("."+$AllMSSQLSPNsItemServerDomainName),"") $AllMSSQLSPNsItemServiceAccountDN = $AllMSSQLServiceAccountHashTable.Get_Item($AllMSSQLSPNsItemServerFQDN)
IF ($AllMSSQLSPNsItemServiceAccountDN)
{
$ADServiceAccountSearchInfo = @()
$AllMSSQLSPNsItemServiceAccountDNArray = $AllMSSQLSPNsItemServiceAccountDN -Split(",")
ForEach ($AllMSSQLSPNsItemServiceAccountDNArrayItem in $AllMSSQLSPNsItemServiceAccountDNArray)
{
IF ($AllMSSQLSPNsItemServiceAccountDNArrayItem -like 'DC=*')
{ [string]$AllMSSQLSPNsItemServiceAccountDomainDN += "$AllMSSQLSPNsItemServiceAccountDNArrayItem," } }
$AllMSSQLSPNsItemServiceAccountDomainDN = $AllMSSQLSPNsItemServiceAccountDomainDN.Substring(0,$AllMSSQLSPNsItemServiceAccountDomainDN.Length-1) $AllMSSQLSPNsItemServiceAccountDomainLDAPDN = "LDAP://$AllMSSQLSPNsItemServiceAccountDomainDN" $ADServiceAccountSearch = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
$ADServiceAccountSearch.SearchRoot = $AllMSSQLSPNsItemServiceAccountDomainLDAPDN
$ADServiceAccountSearch.PageSize = 50000
$ADServiceAccountSearch.Filter = "distinguishedname=$AllMSSQLSPNsItemServiceAccountDN"
$ADServiceAccountSearchInfo = $ADServiceAccountSearch.FindAll() IF ($ADServiceAccountSearchInfo)
{
[string]$ADServiceAccountSAMAccountName = $ADServiceAccountInfo[0].Properties.samaccountname
[string]$ADServiceAccountdescription = $ADServiceAccountSearchInfo[0].Properties.description
[string]$ADServiceAccountpwdlastset = $ADServiceAccountSearchInfo[0].Properties.pwdlastset
[string]$ADServiceAccountPasswordLastSetDate = [datetime]::FromFileTimeUTC($ADServiceAccountpwdlastset)
[string]$ADServiceAccountlastlogon = $ADServiceAccountSearchInfo[0].Properties.lastlogon
[string]$ADServiceAccountLastLogonDate = [datetime]::FromFileTimeUTC($ADServiceAccountlastlogon) $ADServiceAccountadmincount = $ADServiceAccountSearchInfo[0].Properties.admincount [string]$ADServiceAccountDistinguishedName = $ADServiceAccountSearchInfo[0].Properties.distinguishedname
}
$ADServiceAccountLDAPDN = "LDAP://"+$ADServiceAccountDistinguishedName
$ADServiceAccountInfo = ([adsi] $ADServiceAccountLDAPDN) }
ForEach ($AllMSSQLSPNsItemInstancePortArrayItem in $AllMSSQLSPNsItemInstancePortArray)
{
$AllMSSQLSPNsItemServerPort = $NULL
$AllMSSQLSPNsItemServerInstance = $NULL $SQLServerReport = New-Object -TypeName System.Object
$SQLServerReport | Add-Member -MemberType NoteProperty -Name Domain -Value $AllMSSQLSPNsItemServerDomainName
$SQLServerReport | Add-Member -MemberType NoteProperty -Name ServerName -Value $AllMSSQLSPNsItemServerFQDN IF ($AllMSSQLSPNsItemInstancePortArrayItem -match "^[\d\.]+$")
{ [int]$AllMSSQLSPNsItemServerPort = $AllMSSQLSPNsItemInstancePortArrayItem }
IF ($AllMSSQLSPNsItemInstancePortArrayItem -NOTmatch "^[\d\.]+$")
{ [string]$AllMSSQLSPNsItemServerInstance = $AllMSSQLSPNsItemInstancePortArrayItem } $SQLServerReport | Add-Member -MemberType NoteProperty -Name Port -Value $AllMSSQLSPNsItemServerPort
$SQLServerReport | Add-Member -MemberType NoteProperty -Name Instance -Value $AllMSSQLSPNsItemServerInstance
$SQLServerReport | Add-Member -MemberType NoteProperty -Name ServiceAccountDN -Value $AllMSSQLSPNsItemServiceAccountDN TRY
{
$ADComputerSearch = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
$ADComputerSearch.SearchRoot = $AllMSSQLSPNsItemServerDomainLDAPDN
$ADComputerSearch.PageSize = 50000
$ADComputerSearch.Filter = "(&(objectCategory=Computer)(name=$AllMSSQLSPNsItemServerName))"
$ADComputerSearchInfo = $ADComputerSearch.FindAll() [string]$ComputerADInfoLastLogonTimestamp = ($ADComputerSearchInfo[0].properties.lastlogontimestamp)
TRY { [datetime]$ComputerADInfoLLT = [datetime]::FromFileTime($ComputerADInfoLastLogonTimestamp) }
CATCH { } #$ComputerADInfo.Values $SQLServerReport | Add-Member -MemberType NoteProperty -Name OperatingSystem -Value ($ADComputerSearchInfo[0].properties.operatingsystem)
$SQLServerReport | Add-Member -MemberType NoteProperty -Name OSServicePack -Value ($ADComputerSearchInfo[0].properties.operatingsystemservicepack)
$SQLServerReport | Add-Member -MemberType NoteProperty -Name LastBootup -Value $ComputerADInfoLLT
$SQLServerReport | Add-Member -MemberType NoteProperty -Name OSVersion -Value ($ADComputerSearchInfo[0].properties.operatingsystemversion)
$SQLServerReport | Add-Member -MemberType NoteProperty -Name Description -Value ($ADComputerSearchInfo[0].properties.description)
}
CATCH { } IF ($AllMSSQLSPNsItemServiceAccountDN)
{
$SQLServerReport | Add-Member -MemberType NoteProperty -Name SrvAcctUserID -Value $ADServiceAccountSAMAccountName
$SQLServerReport | Add-Member -MemberType NoteProperty -Name SrvAcctDescription -Value $ADServiceAccountdescription
#$SQLServerReport | Add-Member -MemberType NoteProperty -Name SrvAcctPasswordLastSet -Value $ADServiceAccountPasswordLastSetDate
#$SQLServerReport | Add-Member -MemberType NoteProperty -Name SAadmincount -Value $ADServiceAccountadmincount
} [array]$ALLSQLServerReport += $SQLServerReport
}
} # Find all SQL service account that may be a domain-level admin in the domain
# $ALLSQLServerReport | Where {$_.SAadmincount -eq 1} | select ServerName,SrvAcctUserID,SrvAcctPasswordLastSet,SrvAcctDescription | sort SrvAcctUserID -unique | format-table -auto
return $ALLSQLServerReport }
下面列出常见spn扫描工具:

由于每台服务器都需要注册用于Kerberos身份验证服务的SPN,因此这为在不进行端口扫描的情况下收集有关环境的信息提供了一个完美的方法。

PowerShell-AD-Recon

除了Tim Medin开发的工具外,Sean Metcalf也开发了各种PowerShell脚本来执行Kerberos侦察。这些脚本是PowerShell AD Recon存储库的一部分,可以在Active Directory中查询服务,例如Exchange,Microsoft SQL,Terminal等。Sean将每个脚本绑定到一个特定的服务,具体取决于你想要发现的SPN。以下脚本将标识网络上的所有Microsoft SQL实例。

参考

http://en.hackdig.com/?17699.htm

GetUserSPNs:

GetUserSPNs 是 Kerberoast 工具集中的一个 powershell 脚本,用来查询域内注册的 SPN。

查看当前 域 qing.com的spn

PowerView:

PowerView 是由 Will Schroeder(https://twitter.com/harmj0y)开发的 Powershell 脚本,在 Powersploit 和 Empire 工具里都有集成,PowerView 相对于上面几种是根据不同用户的 objectsid 来返回,返回的信息更加详细。

查看当前 域 qing.com的spn

暂时写到这里,有空后面补充

域渗透-Kerberos协议中spn的应用的更多相关文章

  1. 域渗透-Kerberos身份验证流程

    域渗透-Kerberos身份验证流程 Kerberos协议框架 在 Kerberos 协议中主要是有三个角色的存在: 1. 访问服务的 Client: 2. 提供服务的 Server: 3.KDC(K ...

  2. 域渗透 | kerberos认证及过程中产生的攻击

    ​文章首发于公众号<Z2O安全攻防>​ 直接公众号文章复制过来的,排版可能有点乱, 可以去公众号看. https://mp.weixin.qq.com/s/WMGkQoMnQdyG8UmS ...

  3. 内网学习之Kerberos协议

    学习了解kerberos协议,有助于我们后期理解黄金票据和白银票据的原理 kerberos协议 kerberos是一种由麻省理工大学提出的一种网络身份验证协议.旨在通过使用密钥加密技术为客户端/服务器 ...

  4. 域渗透:SPN(ServicePrincipal Names)的利用

    SPN 简介:服务主体名称(SPN:ServicePrincipal Names)是服务实例(可以理解为一个服务,比如 HTTP.MSSQL)的唯一标识符.Kerberos 身份验证使用 SPN 将服 ...

  5. 域渗透基础之NTLM认证协议

    域渗透基础的两个认证协议ntlm和Kerberos协议是必须总结的~ 这篇简单总结下ntlm协议 晚上写下kerberos 0x01 NTLM简介 NTLM使用在Windows NT和Windows ...

  6. 域渗透-企业应用SAML签名攻击

    在项目中遇到SAML企业应用      想留个后门时候一脸懵 随便的整理记录 记录项目中SAML渗透的知识点. 0x01 前置知识  SAML单点登陆 SAML(Security Assertion ...

  7. 初级AD域渗透系列

      net group /domain 获得所有域用户组列表 net group “domain admins” /domain 获得域管理员列表 net group “enterprise admi ...

  8. AD域渗透总结

    域渗透总结 学习并做了一段时间域网络渗透,给我直观的感受就是思路问题和耐心,这个不像技术研究,需要对一个点进行研究,而是遇到问题后要从多个方面思考,寻找"捷径"思路,只要思路正确, ...

  9. 关于Kerberos协议流程的总结

    Kerberos协议工作原理分析 这里面借用一下师傅们的图来说明一下    Kerberos协议的流程大致如下(假设A要获取对Server B的访问权限) 第一步(KRB_AS_REQ) 这一步客户 ...

随机推荐

  1. FreeSql (十七)联表查询

    FreeSql在查询数据下足了功能,链式查询语法.多表查询.表达式函数支持得非常到位. IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnect ...

  2. js操作cookie(创建、读取、删除)方法总结

    js操作cookie,可以通过开源的插件实现,方便快捷,兼容性好,同样也可以自己写: 此文主要介绍两个常用的插件: Js.cookie.js 和 jQuery.cookie.js 0.Js.cooki ...

  3. 手把手教程: CentOS 6.5 LVS + KeepAlived 搭建 负载均衡 高可用 集群

    为了实现服务的高可用和可扩展,在网上找了几天的资料,现在终于配置完毕,现将心得公布处理,希望对和我一样刚入门的菜鸟能有一些帮助. 一.理论知识(原理) 我们不仅要知其然,而且要知其所以然,所以先给大家 ...

  4. 解决在Filter中读取Request中的流后,后续controller或restful接口中无法获取流的问题

    首先我们来描述一下在开发中遇到的问题,场景如下: 比如我们要拦截所有请求,获取请求中的某个参数,进行相应的逻辑处理:比如我要获取所有请求中的公共参数 token,clientVersion等等:这个时 ...

  5. Python 2.X和3.X主要区别和下载安装

    一.python 2.X和3.X的区别 https://wenda.so.com/q/1459639143721779?src=140 二.Python的下载安装 1.Python下载 在python ...

  6. 关于java属性字段命名

    最近项目定义vo的时候,boolean类型数据定义成isProperty类型的,导致系统间数据交互过程中报错. 网上爬了良久: JavaBean命名规范里面规定,对于primitive和自定义类类型的 ...

  7. APP自動化測試腳本2

    package com.lemon.day01; import java.net.MalformedURLException; import java.net.URL; import java.uti ...

  8. ajax发送PUT请求,使用HttpPutFormContentFilter过滤器接受办法

    相信在使用ajax发送put请求时候,肯定遇到过后端数据无法被接受到的405错误. 为什么会遇到这个问题? 1.首先查看Tomcat源码 关于如何将数据封装到Request public class ...

  9. C# 时间戳的相关操作

    一般的 时间戳 格式分为两种 即 10位(秒)时间戳 与 13位(毫秒)时间戳 时间戳 类型也分为两种 即 本地时间戳 与 世界统一(UTC)时间戳 废话不多说,直接上代码: 一.时间戳获取方法 // ...

  10. FreeSql 导航属性的联级保存功能

    写在前面 FreeSql 一个款 .net 平台下支持 .net framework 4.5+..net core 2.1+ 的开源 ORM.单元测试超过3100+,正在不断吸引新的开发者,生命不息开 ...