0x00 前言

SPN是服务器上所运行服务的唯一标示,每个使用Kerberos的服务都需要一个SPN,这样客户端才可以辨认这个服务。

在之前写的一篇关于kerberos认证域渗透-Kerberos认证里面就有相关与SPN的知识,但是没有展开写,这里就详细写一篇关于SPN的文章。

SPN的识别也是Kerberoasting攻击的第一步,所以我们也要了解SPN才可以去做相关的攻击,那我们接下来就从基础概念由浅入深来介绍SPN。

0x01 基础概念

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的类型分为两种:

  1. 一种是注册在活动目录的机器帐户(Computers)下,当一个服务的权限为 Local System 或 Network Service,则SPN注册在机器帐户(Computers)下。
  2. 一种是注册在活动目录的域用户帐户(Users)下,当一个服务的权限为一个域用户,则SPN注册在域用户帐户(Users)下。

一般想要利用的话都是找以域用户身份注册的,因为Local System和Network Service没有利用价值,就算跑出来了,在自己的理解方面,也没有可以利用的方向

如下图所示,CN=Computers那就是主机,CN=Users那就是在域用户下注册:

1

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

想再详细了解可以在微软的官方文档中阅读:Name Formats for Unique SPNs

SPN的配置

这一块分为SPN的查询、注册、删除等操作,更详细的可以查阅官方文档:Setspn

  1. 查询

    查询全部已注册的条目:

    setspn –q */* 
    

    查询指定域注册的条目:

    setspn –T hack.lab –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
  1. 注册

    方法一:

    setspn -A MSSQLSvc/SQL.hack.lab:1433 lucky
    

    意思就是说注册一条服务类为MSSQLSvc,主机为SQL.hack.lab,端口为1433,注册在lucky域用户下。

    部分的服务会自动尝试利用自己的账户进行注册SPN,比如SQLServer在每次启动的时候,都会去尝试注册SPN。

    方法二:

    setspn -S MSSQLSvc/SQL.hack.lab:1433 lucky
    

    跟上面的区别就是,-S可以验证是否有重复的SPN,如果有就禁止注册。因为如果有重复的SPN会导致kerberos认证的时候失败,在下面的MSSQL实战中会有一个例子。

    域管理用户和机器用户本身有注册SPN的权限,域用户没有,如果要注册要赋予Read servicePrincipalName和Write serverPrincipalName权限

  2. 删除

    setspn -D MSSQLSvc/SQL.hack.lab:1433 lucky
    
  3. 查重

    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 来打开(服务器上都有,但是只有域控中的有整个域内的配置信息)。

2

通过 adsiedit.msc 我们可以修改和编辑 LADP,在 SPN 查询时实际上就是查询 LADP 中存储的内容。

LDAP默认是监听在DC的389端口

我们可以看到使用Wireshark抓波ldap协议的内容:

3

0x02 MSSQL注册SPN实践

环境

主机名称 IP地址 所在域 作用
DC 172.16.0.106 hack.lab 提供SPN服务和kerberos认证
SQL 172.16.0.111 hack.lab 提供SQL Server服务
WIN7A 172.16.0.105 hack.lab 使用域用户登录SQL主机的SQL Server服务

在主机SQL(172.16.0.111)上安装SQL Server 2019 Express 版本,我们先去官网下载:立即下载

我们还要去安装一个SQL管理工具: SQL Server Management Studio (SSMS)

具体安装步骤在此就不再讲述,可以参考网上的文章:SQL Server 2019 安装教程

如果想在IIS上注册SPN可以参考文章:IIS 开启 Kerberos 认证

注册SPN

我们可以发现,在安装完SQL Server的时候已经在SPN中自动注册了:

4

这个是因为在安装的时候是默认使用Network Service来启动服务,内置账户Network Service和Local System代表计算机本身,SPN需要注册在运行SQL Server的计算机账户下。但Network Service和Local System本身有权限为本机注册和删除SPN,一般情况不需要手动修改。

Local System权限过大,不推荐使用做服务启动账户

首先我们要开启远程连接,打开配置管理器:

6

在网络配置里面启用TCP/IP:

7

完成上面的远程访问配置我们开始从WIN7A主机连接SQL主机的SQL Sever服务:

5

登录之后我们可以在SQL主机用sa或者是域管理用户去查询该连接:

select auth_scheme,* from sys.dm_exec_connections

结果如下图:

8

然而我们一般是会使用域用户去注册SPN的MSSQL服务,我们首先要在MSSQL的配置器中修改成域用户,因为我们的Kerberoasting攻击就要用到这一块的内容:

9

修改完后我们再从WIN7A主机进行登录,发现报错了:

10

The target principal name is incorrect.  Cannot generate SSPI context

这个是什么原因呢,因为我们一开始安装SQL Server的时候是自动使用机器用户注册在SPN上的,而且现在我们选择的这个testsql用户没有权限去注册SPN,所以就会导致进行登录的时候去查询SPN发现testsql用户下没有注册。

现在我们需要正确去配置SPN,我这里是利用域管的账户进行操作,首先是添加正确的SPN:

setspn -S MSSQLSvc/SQL.hack.lab:1433 testsql
setspn -S MSSQLSvc/SQL.hack.lab testsql

11

我们再查询一下SPN记录:

setspn -L testsql

12

现在我们重新去使用WIN7A主机进行登录,发现成功登录了。

如果发现总是出现错误可以使用微软的Kerberos Configuration Manager for SQL Server的工具:

https://www.microsoft.com/en-ca/download/details.aspx?id=39046

下载安装后要在目录才可以找到:

24

打开后直接点connect即可,不用输入任何信息:

25

它会显示出我们那些出现了错误,点击旁边的fix即可修复:

26

具体可以参考文章:Using Kerberos Configuration Manager for SPNs Validation

赋予普通域用户读写SPN权限

如果权限不够执行注册SPN会出现下面的错误:

19

由于我们上面说到因为使用testsql域用户来启动SQL Server服务没有权限注册SPN,所以我们想要普通的域用户我们可以执行下面的操作。

在ADSI 编辑器(adsiedit.msc)中,选择testsql用户,然后点击下面的高级按钮:

13

弹出高级安全设置后点击下面的添加按钮:

14

这里我们选择主体:

15

选择SELF:

16

确定后,我们在下面的这两项打勾即可:

17

现在我们域用户testsql就有权限去注册SPN了:

18

0x03 扫描SPN

我们除了可以使用SetSPN也可以使用其他的一些脚本进行查询。

PowerView

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

Import-Module .\PowerView.ps1
Get-NetUser -SPN

结果如图:

20

GetUserSPNs.vbs

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

下载地址:https://github.com/nidem/kerberoast/blob/master/GetUserSPNs.vbs

执行命令:

cscript ./GetUserSPNs.vbs

结果如图:

21

GetUserSPNs.ps1

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

下载地址:https://github.com/nidem/kerberoast/blob/master/GetUserSPNs.ps1

执行命令:

Import-Module .\GetUserSPNs.ps1

结果如图:

22

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

结果如下图:

23

当然这款工具也利用于Kerberoasting的攻击,Kerberoasting在另外一篇文章中讲到:

0x04 参考

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