SPN 简介
服务主体名称(SPN:ServicePrincipal Names)是服务实例(可以理解为一个服务,比如 HTTP、MSSQL)的唯一标识符。Kerberos 身份验证使用 SPN 将服务实例与服务登录帐户相关联。如果在整个林或域中的计算机上安装多个服务实例,则每个实例都必须具有自己的 SPN。如果客户端可能使用多个名称进行身份验证,则给定服务实例可以具有多个 SPN。SPN 始终包含运行服务实例的主机的名称,因此服务实例可以为其主机的每个名称或别名注册 SPN。
如果用一句话来说明的话就是如果想使用 Kerberos 协议来认证服务,那么必须正确配置 SPN。
由于每台服务器都需要注册用于Kerberos身份验证服务的SPN因此这为在不进行大规模端口扫描的情况下收集有关内网域环境的信息提供了一个更加隐蔽的方法
SPN的作用
当某用户需要访问MySQL服务时,系统会以当前用户的身份向域控查询SPN为MySQL的记录。当找到该SPN记录后,用户会再次与KDC通信,将KDC发放的TGT作为身份凭据发送给客户,并将需要访问的SPN发送给KDC。
KDC中的TGS服务对TGT进行解密。确认无误后,由TGS将一张允许访问该SPN所对应的服务的ST服务票据和该SPN所对应的服务的地址发送给用户,用户使用该票据即可访问MySQL服务。
SPN类型
SPN的类型分为两种:
-
一种是注册在活动目录的机器帐户(Computers)下,当一个服务的权限为 Local System 或 Network Service,则SPN注册在机器帐户(Computers)下。
-
一种是注册在活动目录的域用户帐户(Users)下,当一个服务的权限为一个域用户,则SPN注册在域用户帐户(Users)下。
一般想要利用的话都是找以域用户身份注册的,因为Local System和Network Service没有利用价值,就算跑出来了,在自己的理解方面,也没有可以利用的方向
如下图所示,CN=Computers那就是主机,CN=Users那就是在域用户下注册:
SPN语法格式与配置
SPN的语法格式
在 SPN 的语法中存在四种元素,两个必须元素和两个额外元素,其中<service class>和为<host>必须元素:
<serviceclass>/<host>:<port>/<service name>
<service class>:标识服务类的字符串
<host>:服务所在主机名称
<port>:服务端口
<service name>:服务名称,所谓的实例名称
例如下面的一条:
MSSQLSvc(标识服务类)/SQL.hack.lab(服务所在主机名称):1433(服务端口)/mssql(服务名称)
主机名称:可以分为FQDN和netbios,一个是运行SQL Server的计算机的FQDN(SQL.hack.lab)。还有一种就是SQL Server的计算机的netbios名字(SQL),俗称短名。
端口号/实例名:服务所监听的计算机端口号。对于SQL Server而言,如果SQL运行在默认端口(1433)上,则端口号可以省略。
例如:
MSSQLSvc/myserver.corp.mycomany.com:1433
MSSQLSvc/myserver:1433
MSSQLSvc/myserver.corp.mycomany.com
MSSQLSvc/myserver:
MSSQLSvc/myserver.corp.mycomany.com:instancename
MSSQLSvc/myserver:instancename
SPN的配置
这一块分为SPN的查询、注册、删除等操作,更详细的可以查阅官方文档:Setspn
1、查询
查询全部已注册的条目:
setspn –q */*
查询指定域注册的条目:
setspn –L lucky(域用户)
所有域内的用户都有权限查询SPN
如果查询出现以下的错误:
Ldap 错误(0x31 -- 无效凭据): ldap_bind_sW
无法检索域“”的 DN: 0x00000031
警告: 未指定有效的目标,正在还原为当前域。
Ldap 错误(0x31 -- 无效凭据): ldap_bind_sW
搜索现有 SPN 时出错: 0x00000031
因是:域主机未能和域控时间同步
解决的办法就是配置域控的时间与互联网同步,可以参考文章:域控服务器时间不准
然后在域主机上配置同步域控时间:
net time \dc.hack.lab /set
2、注册
setspn -A MSSQLSvc/SQL.chen.test:1433 test
意思就是说注册一条服务类为MSSQLSvc,主机为SQL.chen.test,端口为1433,注册在test域用户下。
部分的服务会自动尝试利用自己的账户进行注册SPN,比如SQLServer在每次启动的时候,都会去尝试注册SPN。
方法二:
setspn -S MSSQLSvc/SQL.hack.lab:1433 test
跟上面的区别就是,-S可以验证是否有重复的SPN,如果有就禁止注册。因为如果有重复的SPN会导致kerberos认证的时候失败,在下面的MSSQL实战中会有一个例子。
域管理用户和机器用户本身有注册SPN的权限,域用户没有,如果要注册要赋予Read servicePrincipalName和Write serverPrincipalName权限
3、删除
setspn -D MSSQLSvc/SQL.hack.lab:1433 test
4、查重
setspn -X
LDAP协议
去查询SPN的时候,都会用到一个协议,叫做LDAP(LightweightDirectory Access Protocol),中文名为轻量目录访问协议。是一种用来查询与更新 Active Directory 的目录服务通信协议。AD 域服务利用 LDAP 命名路径(LDAP naming path)来表示对象在 AD 内的位置,以便用它来访问 AD 内的对象。
LDAP 数据的组织方式:
更直观的说可以把 LDAP 协议理解为一个关系型数据库,其中存储了域内主机的各种配置信息。
在域控中默认安装了 ADSI 编辑器,全称 ActiveDirectory Service Interfaces Editor (ADSI Edit),是一种 LDAP 的编辑器,可以通过在域控中运行 adsiedit.msc 来打开(服务器上都有,但是只有域控中的有整个域内的配置信息)。
Kerberoast攻击
扫描SPN
我们除了可以使用SetSPN也可以使用其他的一些脚本进行查询。
PowerView
项目地址https://github.com/PowerShellMafia/PowerSploit
PowerView是PowerSpolit中Recon目录下的一个powershell脚本PowerView 相对于上面几种是根据不同用户的 objectsid 返回的信息更加详细。
1.Import-Module .PowerView.ps1
2.Get-NetUser -SPN
GetUserSPNs.vbs
GetUserSPNs 是 Kerberoast 工具集中的一个 vbs 脚本用来查询域内用户注册的 SPN。
下载地址:
https://github.com/nidem/kerberoast/blob/master/GetUserSPNs.vbs
执行命令:
cscript ./GetUserSPNs.vbs
GetUserSPNs.ps1
GetUserSPNs 是 Kerberoast 工具集中的一个 powershell 脚本用来查询域内用户注册的 SPN。
下载地址:
https://github.com/nidem/kerberoast/blob/master/GetUserSPNs.ps1
执行命令:
Import-Module .GetUserSPNs.ps1
GetUserSPNs.py
GetUserSPNs.py是impacket工具包的一款工具,该工具包用于对SMB1-3或IPv4/IPv6上的TCP、UDP、ICMP、IGMP,ARP,IPv4,IPv6,SMB,MSRPC,NTLM,Kerberos,WMI,LDAP等协议进行低级编程访问,可使用该工具对目标主机进行SPN探测。
安装地址:
https://github.com/SecureAuthCorp/impacket
该工具在最新版本的kali是内置的,直接运行即可
GetUserSPNs.py hack.lab/lucky:p@ssw0rd -dc-ip 172.16.0.106 -request
参考
https://xxe.icu/posts/ad_spn/#spn%E7%9A%84%E9%85%8D%E7%BD%AE
https://www.modb.pro/db/62849
https://www.freebuf.com/articles/system/196434.html
https://chowdera.com/2021/12/20211201194023144R.html
http://f5.pm/go-8673.html
https://www.anquanke.com/post/id/219934
https://www.cnblogs.com/zpchcbd/p/11707776.html
关注转发参与抽奖
若有收获的话点个赞吧~
原文始发于微信公众号(钟毓安全):域渗透-SPN【转发文章——文末抽奖】
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论