SPN(ServicePrincipal Names)服務主體名稱,是服務實例(如:HTTP、SMB、Exchange等服務)的唯一標識符。Kerberos身份驗證使用SPN將服務實例與服務登錄帳戶相關聯。如果在整個林或域中的計算機上安裝多個服務實例,則每個實例都必須具有自己的 SPN。如果客戶端使用多個名稱進行身份驗證,則給定服務實例可以具有多個SPN。SPN 始終包含運行服務實例的主機名,因此服務實例可以為其主機的每個名稱或別名注冊SPN。一個用戶賬戶下可以有多個SPN,但一個SPN只能注冊到一個賬戶。如果想使用 Kerberos 協議來認證服務,那么必須正確配置SPN。
在 Kerberos 身份驗證服務使用 SPN 對服務進行身份驗證之前,必須在服務實例用于登錄的帳戶對象上注冊 SPN。 只能在一個帳戶上注冊給定的 SPN。 對于 Win32 服務,服務安裝程序在安裝服務實例時指定登錄帳戶。 然后,安裝程序將編寫 SPN,并作為帳戶對象的屬性寫入 Active Directory 數據庫中。 如果服務實例的登錄帳戶發生更改,則必須在新帳戶下重新注冊 SPN。 當客戶端想要連接到某個服務時,它將查找該服務的實例,然后連接到該服務并顯示該服務的 SPN 以進行身份驗證。
在內網中,SPN掃描通過查詢向域控服務器執行服務發現。這對于紅隊而言,可以幫助他們識別正在運行重要服務的主機,如Exchange服務器等。SPN的識別是kerberoasting攻擊的第一步。
下面通過一個例子來說明SPN的作用:
Exchange郵箱服務在安裝的過程中,就會在活動目錄中注冊一個Exchange的SPN。當用戶需要訪問Exchange郵箱服務時,系統會以當前用戶的身份向域控查詢SPN為Exchange的記錄。當找到該SPN記錄后,用戶會再次與KDC通信,將KDC發放的TGT作為身份憑據發送給KDC,并將需要訪問的SPN發送給KDC。KDC中的TGS服務對TGT進行解密。確認無誤后,由TGS將一張允許訪問該SPN所對應的服務的ST服務票據和該SPN所對應的服務的地址發送給用戶,用戶使用該票據即可訪問Exchange郵箱服務。
SPN分為兩種類型:
- 一種是注冊在活動目錄的機器帳戶(Computers)下,當一個服務的權限為 Local System 或 Network Service時,則SPN注冊在機器帳戶(Computers)下。域中的每個機器賬戶都會注冊兩個SPN:HOST/主機名 和 HOST/主機名.xie.com
- 另一種是注冊在活動目錄的域用戶帳戶(Users)下,當一個服務的權限為一個域用戶,則SPN注冊在域用戶帳戶下。
如圖所示,可以看到機器win2008下注冊的SPN和hack用戶下注冊的SPN。

這里以SQLServer服務注冊為例:
SQLServer在每次啟動的時候,都會去嘗試用自己的啟動賬號注冊SPN。但是在Windows域里,默認普通機器賬號有權注冊SPN,但是普通域用戶賬號是沒有權注冊SPN的。這就會導致這樣一個現象,SQL Server如果使用“Local System account”來啟動,Kerberos就能夠成功,因為SQL Server這時可以在DC上注冊SPN。如果用一個域用戶來啟動,Kerberos就不能成功,因為這時SPN注冊不上去。
解決辦法:
- 可以使用工具Setspn來手動注冊SPN。但是這不是一個最好的方法,畢竟手工注冊不是長久之計。如果SPN下次丟了,又要再次手動注冊。
- 所以比較好的方法,是讓SQL Server當前啟動域賬號有注冊SPN的權力。要在DC上為域賬號賦予 “Read servicePrincipalName” 和 “Write serverPrincipalName” 的權限即可。
SPN的配置
SPN 在注冊它的林中必須是唯一的。 如果它不唯一,身份驗證將失敗。 SPN 語法包含四個元素:兩個必需的元素和兩個其他元素,其中 <service class> 和 <host> 為必須元素。如有必要,可以使用這些元素生成下表中列出的唯一名稱。如下是SPN的格式:
<service class>/<host>:<port>/<service name>
- <service class>:服務類,用于標識服務常規類的字符串;例如,"HOST"。 有一些已知的服務類名稱,例如 Web 服務的"WWW"或目錄服務的"LDAP"。 一般情況下,可以是服務類唯一的任何字符串。 請注意,SPN 語法使用正斜杠 (/) 分隔元素,因此此字符不能出現在服務類名中。
- <host>:運行服務的計算機的名稱。 這可以是完全限定的 DNS 名稱(FQDN)或 NetBIOS 名稱。 請注意,不確保 NetBIOS 名稱在林中是唯一的,因此,包含 NetBIOS 名稱的 SPN 可能不是唯一的。
- <port>:一個可選端口號,用于區分單個主計算機上同一服務類的多個實例。 如果服務使用服務類的默認端口,則省略此組件。
- <service name>:可復制服務SPN中使用的可選名稱,用于標識服務或服務所服務的域提供的數據或服務。 此組件可以具有以下格式之一:
- 服務中對象的可分辨名稱或 objectGUID Active Directory 域,例如 SCP (連接) 。
- 為整個域提供指定服務的服務的域的 DNS 名稱。
- SRV 或 MX 記錄的 DNS 名稱。
基于主機的服務
對于基于主機的服務,將省略"服務名稱"組件,因為服務由服務類和安裝該服務的主機名唯一標識。
<service class>/<host>
僅服務類就足以為客戶端標識服務提供的功能。可以在多臺計算機上安裝服務類的實例,并且每個實例都提供使用其主計算機標識的服務。 FTP 和 Telnet 是基于主機的服務的示例。 如果服務使用非默認端口,或者主機上有多個服務實例,則基于主機的服務實例的 SPN 可以包含端口號。
<service class>/<host>:<port>
如下所示,是系統自動注冊的基于主機服務的SPN。

各個SPN代表的服務如下:
#Host服務HOST/WIN2008 HOST/WIN2008.xie.com #RDP服務TERMSRV/WIN2008TERMSRV/Win2008.xie.com #WSMan/WinRM/PSRemoting服務WSMAN/Win2008WSMAN/Win2008.xie.com #RestrictedKrbHost服務RestrictedKrbHost/WIN2008RestrictedKrbHost/WIN2008.xie.com
可復制的服務
對于可復制服務,可以有一個或多個服務實例 (副本) ,并且客戶端不會區分它們連接到哪個副本,因為每個實例都提供相同的服務。 每個副本的 SPN具有相同的"服務類"和"服務名稱"組件,其中"服務名稱"更明確地標識服務提供的功能。 只有 <host>和可選的 <port>組件因 SPN 而異。
<service class>/<host>:<port>/<service name>
可復制服務的一個示例是提供對指定數據庫的訪問的數據庫服務的實例。 在這種情況下,標識數據庫應用程序,標識特定數據庫。 可以是包含數據庫連接數據的 SCP的可分辨名稱。
MyDBService/host1.example.com/CN=hrdb,OU=mktg,DC=example,DC=comMyDBService/host2.example.com/CN=hrdb,OU=mktg,DC=example,DC=comMyDBService/host3.example.com/CN=hrdb,OU=mktg,DC=example,DC=com
可復制服務的另一個示例是向整個域提供服務。 在這種情況下, <service name>組件是所服務的域的 DNS 名稱。 Kerberos KDC 是此類可復制服務的示例。
請注意,如果計算機的 DNS 名稱發生更改,系統將更新林中該主機的所有已注冊的SPN的元素。
使用SetSPN注冊SPN
在客戶端使用 SPN 對服務實例進行身份驗證之前,必須在服務實例上將用于登錄的用戶或計算機帳戶注冊 SPN。 通常,SPN 注冊由通過域管理員權限運行的服務安裝程序來完成。但是我們也可以手動使用Setspn.exe程序來注冊SPN,setspn.exe是Windows自帶的一個二進制文件,該二進制文件可以用于SPN的查看、添加和刪除。
如圖所示,查看setspn的幫助說明。

我們可以使用 -S 參數來注冊SPN。
- 如果是注冊在域用戶下,還可以使用-U -A參數注冊
- 如果是注冊在機器用戶下,可以使用-C -A參數注冊
SPN注冊權限
只有機器賬號或域管理員賬號有權限注冊SPN,普通域用戶注冊SPN會提示特權不夠,不能執行該操作。而使用機器賬號注冊SPN時,注冊的SPN的必須為當前主機的DNS名稱。使用域管理員賬號注冊SPN無任何限制!
如圖所示,通過切換到本地System權限窗口來使用機器賬號注冊SPN,注冊的SPN的為當前主機的DNS名稱。

如果使用機器賬號注冊SPN,注冊的SPN的不為當前主機的DNS名稱,會提示失敗。如圖所示:

使用普通域用戶執行如下命令注冊SPN,由于權限不足,所以提示失敗!
setspn -S MySQL/win7.xie.com:3306 hack
如圖所示,使用普通域用戶注冊SPN。

如果想讓普通域用戶也擁有注冊SPN權限的話,需要在域控上手動為域賬號賦予“讀取 servicePrincipalName” 和 “寫入serverPrincipalName” 的權限。具體操作如下:
如圖所示,打開ADSI 編輯器(adsiedit.msc),找到要修改的hack用戶,右鍵——>屬性。

找到安全選項卡,點擊高級。如圖所示:

然后點擊添加,如圖所示:

點擊選擇主體,然后輸入SELF。如圖所示:

接著勾選“讀取 servicePrincipalName” 和 “寫入serverPrincipalName” 選項。如圖所示:

然后應用、確定即可。如圖所示:

然后就可以使用普通域用戶注冊SPN了。執行如下命令在hack域賬號下注冊SPN。
setspn -S MySQL/win7.xie.com:3306 hack
如圖所示,可以看到hack用戶成功注冊SPN。

但是即使為域賬號了賦予“Read servicePrincipalName” 和 “Write serverPrincipalName” 的權限,當前賬戶也只能將SPN注冊在當前用戶下,而無法注冊在其他用戶下。
如圖所示,hack用戶將SPN注冊于其它用戶下,提示權限拒絕。

以下我們注冊SPN均是在域管理員administrator身份下進行注冊。
將SPN注冊在域賬號下
運行如下命令使用-S參數或-U -S參數將SPN注冊在域用戶hack下:
setspn -S SQLServer/win7.xie.com:1433/MSSQL hack 或 setspn -U -S SQLServer/win7.xie.com:1443/MSSQL hack #查詢hack用戶注冊的SPNsetspn -L hack
如圖所示,使用不同命令將SPN注冊于hack用戶下。

將SPN注冊在機器賬號下
運行如下命令使用-S參數或-C -S參數將SPN注冊在機器賬號win7下:
setspn -S SQLServer/win7.xie.com:1433/MSSQL win7 或 setspn -C -S SQLServer/win7.xie.com:1443/MSSQL win7 #查詢win7機器注冊的SPNsetspn -L win7
如圖所示,使用不同命令將SPN注冊于機器賬號win7下。

SPN的查詢和發現
由于每臺服務器都需要注冊用于Kerberos身份驗證服務的SPN,因此這為在不進行大規模端口掃描的情況下收集有關內網域環境的信息提供了一個更加隱蔽的方法。
如下使用不同的工具探測域內的SPN:
setspn
可以通過Windows系統自帶的setspn執行如下命令查詢域內的SPN。
#查看當前域內所有的SPNsetspn -Q */* #如果在域林中,則可以使用如下命令查看指定域xie.com內的SPN。如果指定域不存在,則默認切換到查找本域的SPNsetspn -T xie.com -Q */* #查找本域內重復的SPN setspn -X #刪除指定SPN:setspn -D MySQL/win7.xie.com:1433/MSSQL hack #查找指定用戶/主機名注冊的SPNsetspn -L username/hostname
如圖所示,查詢域內所有的SPN。

如圖所示,查詢注冊于hack用戶和win7機器帳戶下的SPN。

impacket
impacket中的GetUserSPNs.py腳本可以在域外查詢指定域的SPN,使用該腳本只需要提供一個有效的域憑據。
使用GetUserSPNs.py腳本執行如下命令查詢域控10.211.55.4所在的域內注冊于用戶下的SPN。
python3 GetUserSPNs.py -dc-ip 10.211.55.4 xie.com/hack:P@ss1234
如圖所示,查詢到注冊域用戶下的SPN兩2個,分別為 MySQL/win7.xie.com:3306和SQLServer/win7.xie.com:1533/MSSQL。

PowerShellery
PowerShellery下有各種各樣針對服務SPN探測的腳本。其中一些只需要PowerShell v2.0的環境,而有一些則需要PowerShell v3.0環境。如下是PowerShellery下不同腳本的使用:
#Powershellery/Stable-ish/Get-SPN/ 下Get-SPN.psm1腳本的使用,需要powershell3.0及以上版本才能使用Import-Module .\Get-SPN.psm1Get-SPN -type service -search "*"Get-SPN -type service -search "*" -List yes | Format-Table #Powershellery/Stable-ish/ADS/ 下Get-DomainSpn.psm1腳本的使用Import-Module .\Get-DomainSpn.psm1Get-DomainSpn
如圖所示,使用Get-SPN.psm1腳本查詢域內所有的SPN。

PowerShell-AD-Recon
該工具包提供了一些發現指定SPN的腳本,例如指定Exchange,Microsoft SQLServer等服務的SPN。但其實對于Kerberoasting攻擊第一步SPN的發現意義不大,因為該腳本并沒過濾出注冊于域用戶下的SPN。
如下是 不同腳本的使用。
#探測域內注冊的SQLServer服務的SPNImport-Module .\Discover-PSMSSQLServers.ps1;Discover-PSMSSQLServers #探測域內注冊的Exchannge服務的SPNImport-Module .\Discover-PSMSExchangeServers.ps1;Discover-PSMSExchangeServers #掃描域中所有的SPN信息Import-Module .\Discover-PSInterestingServices.ps1;Discover-PSInterestingServices
如圖所示,是PowerShell-AD-Recon中不同腳本的使用。

一顆小胡椒
瀟湘信安
安全圈
FreeBuf
FreeBuf
金融電子化
RacentYY
FreeBuf
上官雨寶
007bug
上官雨寶