Kerberos与SPN

一、SPN 简介

SPN(ServicePrincipal Names)服务主体名称,是服务实例(比如:HTTP、SMB、MySQL等服务)的唯一标识符。

Kerberos认证过程使用SPN将服务实例与服务登录账户相关联,如果想使用 Kerberos 协议来认证服务,那么必须正确配置SPN。如果在整个林或域中的计算机上安装多个服务实例,则每个实例都必须具有自己的 SPN。如果客户端可能使用多个名称进行身份验证,则给定服务实例可以具有多个SPN。SPN 始终包含运行服务实例的主机的名称,因此服务实例可以为其主机的每个名称或别名注册SPN。一个用户账户下可以有多个SPN,但一个SPN只能注册到一个账户。在内网中,SPN扫描通过查询向域控服务器执行服务发现。这对于红队而言,可以帮助他们识别正在运行重要服务的主机,如终端,交换机等。SPN的识别是kerberoasting攻击的第一步。

下面通过一个例子来说明SPN的作用:

当某用户需要访问MySQL服务时,系统会以当前用户的身份向域控查询SPN为MySQL的记录。当找到该SPN记录后,用户会再次与KDC通信,将KDC发放的TGT作为身份凭据发送给KDC,并将需要访问的SPN发送给KDC。KDC中的TGS服务对TGT进行解密。确认无误后,由TGS将一张允许访问该SPN所对应的服务的ST服务票据和该SPN所对应的服务的地址发送给用户,用户使用该票据即可访问MySQL服务。

二、SPN分为两种类型:

1.一种是注册在活动目录的机器帐户(Computers)下,当一个服务的权限为 Local System 或 Network Service,则SPN注册在机器帐户(Computers)下。域中的每个机器都会有注册两个SPN:HOST/主机名 和 HOST/主机名.xie.com

2.另一种是注册在活动目录的域用户帐户(Users)下,当一个服务的权限为一个域用户,则SPN注册在域用户帐户(Users)下。

image-20220213004516395

这里以SQLServer服务注册为例:

SQLServer在每次启动的时候,都会去尝试用自己的启动账号注册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” 的权限即可。

三、SPN 格式与配置:

微软官方文档:https://docs.microsoft.com/zh-cn/windows-server/networking/sdn/security/kerberos-with-spn

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

SPN格式:/:/

:标识服务类的字符串,可以理解为服务的名称,常见的有WWW、MySQL、SMTP、MSSQL等;必须元素

:服务所在主机名,host有两种形式,FQDN(win7.xie.com)和NetBIOS(win7)名;必须元素

:服务端口,如果服务运行在默认端口上,则端口号(port)可以省略;额外元素

:服务名称,可以省略;额外元素

一些服务的SPN示例:

#Exchange服务

exchangeMDB/ex01.xie.com

#RDP服务

TERMSERV/te01.xie.com

#WSMan/WinRM/PSRemoting服务

WSMAN/ws01.xie.com

image-20220213005306335

四、使用SetSPN注册SPN

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

主机:win7.xie.com

域控:win2008.xie.com

当前用户:xie/test

注:注册SPN需要域管理员权限,普通域成员注册会提示权限不够!

把主机win7.xie.com的mysql服务注册到spn中

image-20220213010820938

这里有个tips:因为有些文章用的setspn -A 所以 介绍一下两个的区别:
根据Setspn概述,不建议使用它Setspn -A来添加SPN记录,建议改为使用它Setspn -S

据说Setspn -S在添加新SPN之前先检查SPN是否已经存在。Setspn –A不执行此检查。

尽管可以使用Setspn -A添加SPN,但应改用Setspn -S,因为-S将验证没有重复的SPN。

但是,在Windows Server 2012上,我看到了Setspn -SSetspn -A以相同的方式进行操作:如果存在帐户的SPN记录,则使用-A-S参数都会失败。

以test用户的身份进行SPN服务的注册

1
2
3
setspn -S SQLServer/win7.xie.com:1433 test    #test必须是当前的用户

setspn -U -A SQLServer/win7.xie.com:1433 test #test必须是当前的用户

-u 是指定test为用户账户 参考:https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc731241(v=ws.11)

image-20220213011808653

以WIN7主机的身份在DC(win2008.xie.com)上进行SPN服务(SQLServer)的注册

1
setspn -S SQLServer/win7.xie.com:1533/MSSQL win7    #win7必须是当前的主机名

这里由于之前用 test 用户注册过,所以会提示重复,我们可以将端口修改为其他端口,则不是重复的SPN了

image-20220213012130079

五、SPN的发现

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

使用SetSPN查询:

windows系统自带的setspn可以查询域内的SPN。

1
2
3
4
5
查看当前域内所有的SPN:setspn  -Q  */*
查看指定域xie.com注册的SPN:setspn -T xie.com -Q */* 如果指定域不存在,则默认切换到查找本域的SPN
查找本域内重复的SPN:setspn -X
删除指定SPN:setspn -D MySQL/win7.xie.com:1433/MSSQL hack
查找指定用户/主机名注册的SPN:setspn -L username/hostname

image-20220213015244379

机器账户:

  • CN=DC
  • CN=PC2

域用户账户:

  • CN=krbtgt,CN=Users,DC=redteam,DC=com

注册于域用户下的SPN仅有一个:

  • kadmin/changepw

image-20220213015146908

image-20220213015306013

image-20220213015406626

图是用的我自己虚拟机

六、扫描工具

PowerShell-AD-Recon:

该工具包提供了一些探测指定SPN的脚本,例如Exchange,Microsoft SQLServer,Terminal等

image-20220213020151584

1
#Discover-PSMSSQLServers.ps1的使用,扫描MSSQL服务 Import-Module ./Discover-PSMSSQLServers.ps1;Discover-PSMSSQLServers #Discover-PSMSExchangeServers.ps1的使用,扫描Exchange服务 Import-Module ./Discover-PSMSExchangeServers.ps1;Discover-PSMSExchangeServers #扫描域中所有的SPN信息 Import-Module ./Discover-PSInterestingServices.ps1;Discover-PSInterestingServices

GetUserSPNs.ps1:

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

1
Import-Module ./GetUserSPNs.ps1

image-20220213020222523

GetUserSPNs.vbs:

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

1
cscript ./GetUserSPNs.vbs

image-20220213020244356

PowerView.ps1:

PowerView是 PowerSpolit 中 Recon目录下的一个powershell脚本,PowerView 相对于上面几种是根据不同用户的 objectsid 来返回,返回的信息更加详细。

1
2
Import-Module ./PowerView.ps1
Get-NetUser -SPN

image-20220213020303044

RiskySPN中的Find-PotentiallyCrackableAccounts.ps1:

该脚本可以帮助我们自动识别弱服务票据,主要作用是对属于用户的可用服务票据执行审计,并根据用户帐户和密码过期时限来查找最容易包含弱密码的票据。

1
Import-Module ./Find-PotentiallyCrackableAccounts.ps1;Find-PotentiallyCrackableAccounts -FullData -Verbose

image-20220213020402293

该脚本将提供比klist和Mimikatz更详细的输出,包括组信息,密码有效期和破解窗口。

image-20220213020420487

使用domain参数,将返回所有具有关联服务主体名称的用户帐户,也就是将返回所有SPN注册在域用户下的用户。

1
Import-Module ./Find-PotentiallyCrackableAccounts.ps1;Find-PotentiallyCrackableAccounts -Domain "xie.com"

image-20220213020435777

更多扫描工具参考:

https://www.freebuf.com/articles/web/262953.html

https://www.freebuf.com/articles/system/174229.html

原理说明

​ 在 SPN 扫描时我们可以直接通过脚本,或者命令去获悉内网已经注册的 SPN 内容。那 如果想了解这个过程是如何实现的,就需要提到 LDAP 协议。

​ LDAP 协议全称是 Lightweight Directory Access Protocol,一般翻译成轻量目录访问协议。 是一种用来查询与更新 Active Directory 的目录服务通信协议。AD 域服务利用 LDAP 命名 路径(LDAP naming path)来表示对象在 AD 内的位置,以便用它来访问 AD 内的对象。

​ 运行在 tcp/ip之上, 一般使用389端口进行数据传输。

LDAP 数据的组织方式:

image-20220213155139066

更直观的说可以把 LDAP 协议理解为一个关系型数据库,其中存储了域内主机的各种配 置信息。 在域控中默认安装了 ADSI 编辑器,全称 Active Directory Service Interfaces Editor (ADSI Edit),是一种 LDAP 的编辑器,可以通过在域控中运行 adsiedit.msc 来打开(服务器上都有, 但是只有域控中的有整个域内的配置信息)。

image-20220213155213484

通过 adsiedit.msc 我们可以修改和编辑 LADP,在 SPN 查询时实际上就是查询 LADP 中存 储的内容。 比如在我们是实验环境域 whoami.org 中,存在名为computer的一个CN(Organization Unit,可以理解为一个部门,如开发部、财务部等等),其中包含了PC2 这个主机,从主机 属性中可以看到 PC2注册过的 SPN 内容。

这里是上面用我虚拟机实验添加的spn

image-20220213155758406

下面是云影 系列的例子:

比如在我们是实验环境域 YUNYING.LAB 中,存在名为 svcserver 的一个 OU(Organization Unit,可以理解为一个部门,如开发部、财务部等等),其中包含了 tsvc 这个用户,从用户 属性中可以看到 tsvc 注册过的 SPN 内容。

image-20220213155912550

当我们在一台主机执行 setspn -T yunying.lab -q */*命令查询域内 SPN 时,通过抓包可以 看到正是通过 LDAP 协议向域控中安装的 LDAP 服务查询了 SPN 的内容。

image-20220213155930590

所以其实那些Powershell脚本其实主要就是通过查询LDAP的内容并对返回结果做一个过滤, 然后展示出来。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!