前言
作为一个脚本小子,当我们在进行内网渗透的过程中,要去抓取内网机器的账号密码、还有一堆hash值、还有什么黄金票据、白银票据,搞到这些东西以后就是一顿无脑梭哈,就能拿到机器了。现在!我不想再做一个脚本小子了!为什么呢?为什么就能抓到机器的明文账号密码了呢?抓了一堆的hash值干嘛的呢?什么是黄金票据什么是白银票据?为什么用这些票据就能拿到机器的权限?本章节带你来解答这些问题。
NTLM协议
先来介绍一下,在windows中进行身份认证使用的NTLM协议。
NTLM Hash算法
NTLM Hash算法是微软为了在提高安全性的同时保证兼容性而设计的散列加密算法,他是基于MD4加密算法进行加密的。
具体的NTLM Hash算法这里就不详细演示了,直接使用一行python代码进行NTLM加密:
1 | import binascii |
运行结果如下:

Windows系统存储的NTLM Hash
前面介绍了NTLM Hash算法,这个NTLM Hash算法加密的结果就是我们在进行内网渗透的过程中,抓取的Hash值。这些Hash值是干什么的呢?用于比对进行身份验证用的。
用户在Windows登录过程中,用户的密码经过NTLM Hash加密后存储在C:\Windows\system32\config\SAM文件中。

在用户输入密码进行本地认证的过程中,所有操作都是在本地进行的。系统将用户输入的密码转换为NTLM Hash,然后与SAM文件中的NTLM Hash进行比较,如果相同,说明密码正确,反之则错误。
当用户注销、重启、锁屏后,操作系统会让winlogon.exe显示登录界面,也就是输入框。当winlogon.exe接收输入后,将密码交给lsass.exe进程,lsass.exe进程中会存一份明文密码,将明文密码加密成NTLM Hash,与SAM数据库进行比较和认证。
我们使用mimikatz就是从lsass.exe进程中抓取明文密码或Hash密码。

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 v2。NTLM v1与NTLM v2最显著的区别是Challenge值与加密算法不同,共同之处就是都使用NTLM Hash进行加密。
工作组环境下的NTLM认证
工作组下的NTLM认证流程如下:

(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 Hash对Challenge值进行一系列加密运算,得到自己计算的Net-NTLM Hash,并比较自己计算出的Net-NTLM Hash和客户端发送的Net-NTLM Hash是否相等。如果相等,则证明客户端输入的密码正确,从而认证成功,反之则认证失败。
以上是完整的整个流程,可以看到认证的成功的关键就是**Net-NTLM Hash比对的成功**。而Net-NTLM Hash的值是由NTLM Hash和服务器生成的Challenge值进行一系列加密运算得到的,所以这里的NTLM Hash和Challege非常关键。
域环境下的NTLM认证
域环境下的NTLM认证流程如下:

(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(密钥发行中心)的服务账户,其密码是系统随机生成的,无法正常登录主机。

Kerberos是一种基于票据(Ticket)的认证方式。客户端想要访问服务端的某个服务,首先需要购买服务端认可的ST(Service Ticket,服务票据)。也就是说,客户端在访问服务之前需要先买好票,等待服务验票之后才能访问。但是这张票并不能直接购买,需要一张TGT(Ticket Granting Ticket,认购权证)。也就是说,客户端在买票之前必须先获得一张TGT,TGT和ST均是由KDC发放的,因为KDC运行在域控上,所以说TGT和ST均是由域控发放的。
Kerberos协议有两个基础认证模块——AS_REQ & AS_REP 和TGS_REQ & TGS_REP,以及微软扩展的两个认证模块S4U和PAC。SU4是微软为了实现委派而扩展的模块,分为S4u2Self和S4u2Proxy。在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 | 使用 test.mydomain/bob 账户/密码 请求 bob.test.mydomain 的 cifs 服务的 ST(Service Ticket) |
结果如下:

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

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

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

PAC
在分析AS_REQ & AS_REP和TGS_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的部分。

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

客户端是如何获得TGT的?TGT是由KDC的AS(Authentication Service,认证服务)发放的。下面具体分析AS-REQ & AS-REP请求过程中的数据包细节。
1、AS-REQ包分析
当域内某个用户想要访问域内某个服务时,输入用户名和密码,本机就会向KDC的AS发送一个AS-REQ(认证请求)。该请求的内容如AS-REQ & AS-REP图片左侧内容一样,时间的包内容如下:


下面就来详细的介绍一下各个字段:
- 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。

- 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来加密时间戳的。

下面就是对使用Wireshark抓取的PA-DATA pA-ENC-TIMESTAMP字段中的cipher进行解密了,解密是使用test.mydomain/bob的密钥来进行解密。
Wireshark自带有解密的功能,要导入解密的keytab文件。生成解密的keytab文件,如下
1 | 启动 ktutil |
导入keytab可以注意到解密后的数据,patimestamp和pausec显示的是解密后的值。

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

下面对AS-REP包中部分字段进行解释,具体如下:
- **ticket:**认购权证据票。
- enc-part(ticket中的):TGT中的加密部分,这部分是用
krbtgt的密码Hash加密的。因此,如果我们拥有krbtgt的Hash,就可以自己制作一个ticket,这就造成了黄金票据传递攻击⚠️⚠️⚠️。 - enc-part(最外层的):
Logon Session Key,这部分是用请求的用户密码Hash加密的,作为下一阶段的认证密钥。
AS-REP包中最重要的就是TGT和加密的Logon Session Key。TGT中加密部分是使用krbtgt密钥加密的,而Logon Session Key是使用请求的用户密钥加密的。下面通过解密Wireshark来看看TGT和Logon Session Key中包含哪些内容。
(1)TGT
AS-REP包中的ticket便是TGT了。TGT中包含一些明文显示的信息,如版本号tkt-vno、域名realm、请求的服务名sname,但最重要的还是加密部分。加密部分是使用krbtgt账户密钥加密的,主要包含Logon Session Key、请求的用户名cname、域名crealm、认证时间authtime、认证到期时间endtime、authorization-data等信息。其中authorization-data部分包含客户端的身份权限等信息,这些信息包含在PAC中。
先去解密加密的部分,使用mimikatz抓取krbtgt账户的Hash用于去生成解密的keytab。抓取Hash的命令如下:
1 | 将整个 mimikitz 会话输出到文件 |
获取到对应的Hash值如下:
1 | aes256_hash = "bc61d540e046302787e8bbdab97d6801deebaaf38d4753deda056f6165eb71ae" |
生成keytab文件。
1 | ktutil |
将生成的keytab文件导入到wireshark中去解密流量。解密后的流量如下,这里就是TGT:

中间部分:

最后的部分:

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

KDC生成PAC的过程如下:
KDC在收到客户端发来的AS-REQ后,从请求中取出cname字段,然后查询活动目录数据库,找到sAMAccountName属性为cname字段的值的用户,用该用户的身份生成一个对应的PAC。
(2)Logon Session Key
AS-REP包最外层的那部分便是加密的Logon Session Key,用于确保客户端和KDC下一阶段的通信安全,它使用请求的用户密钥加密。
我们对最外层的enc-part部分进行解密,如下图,可以看到使用的是普通域用户bob的密钥对其进行解密的。

后半部分。

解密结果如下:主要包含认证时间authtime、认证到期时间endtime、域名srealm、请求的服务名sname、协商标志flags等信息。需要说明的是,在TGT中也包含Logon Session Key。
TGS-REQ & TGS-REP
下面就看一看抓取的TGS-REQ & TGS-REP数据包。

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

下面具体分析TGS-REQ & TGS-REP过程中的数据包细节。
客户端在收到KDC的AS-REP后,使用用户密钥解密enc_Logon Session Key(也就是最外层的enc-part),得到Logon Session Key,并且也获得了TGT。之后,他会在本地缓存此TGT和Lofon Session Key。现在客户端需要凭借这张TGT向KDC购买相应的ST。ST是KDC的另一个服务TGS(Ticket Granting Service)授予服务发放的。在这个阶段,微软引入了两个扩展自协议S4u2Self和S4u2Proxy(委派时才用到,后面会介绍)。
1、TGS-REQ包分析
客户端用上一步获得的TGT发起TGS-REQ,向KDC购买针对指定服务的ST,请求的内容如TGS-REQ & TGS-REP图片中的A。下面就是wireshark抓取的TGS-REQ包的详细内容。

后半部分:

下面对部分字段内容进行详细的解释。
- 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_OPTIONS。S4u2Proxy必须扩展PA-PAC-OPTIONS结构,如果是基于资源的约束性委派,就需要指定Resource-based Constrained Delegation位。
- ap-req:
这个是TGS_REQ必须携带的部分。
- ticket:
AS-REP回复包中返回的TGT
- authenticator:
原始Logon Session Key加密的时间戳,用于保证会话安全。
这里着重讲一下ap-req中的authenticator字段,该字段主要用于下一阶段的会话安全认证,为了保证下一阶段的会话安全,TGS-REQ的ap-req中的authenticator字段的值使用的是上一步AS-REP中返回的Logon Session Key加密的时间戳,如下图:

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

2、TGS-REP包分析
KDC的TGS服务接收到TGS_REQ之后会进行如下操作。首先,使用krbtgt秘钥解密TGT中的加密部分,得到Logon Session Key和PAC等信息,解密成功则说明该TGT是KDC颁发的;然后,验证PAC的签名,签名正确证明PAC未经过篡改;最后,使用Logon Session Key解密authenticator得到时间戳等信息,如果能解密成功,并且票据时间在有效的范围内,则验证了会话的安全性。
在完成上述的检测后,KDC的TGS就完成了对客户端的认证,TGS发送回复包给客户端。该回复包中主要包括的信息。
⚠️注意:TGS-REP中KDC并不会验证客户端是否有权限访问服务端。因此,不管用户有没有访问服务的权限,只要TGT正确,均会返回ST。
TGS-REP包的详细内容如下:

对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便是ST,ST中包含明文显示的信息,如版本号tkt-vno、域名realm、请求的服务名sname,但最重要的还是加密部分。加密部分是使用服务秘钥加密的,主要包含Server Session Key、请求的用户名cname、域名crealm、认证时间authtime、认证到期时间endtime、authorization-data等信息。其中authorization-data部分包含客户端的身份权限等信息,这些信息包含在PAC中。
首先是想办法去解密ticket中的enc-part,获取服务秘钥Hash,即这里就是域控中机器账户BOB$的Hash。
1 | mimikatz.exe |
如下图:
利用服务秘钥Hash去生成keytab。
1 | ktutil |
wireshark导入keytab,然后可以解密ticket的enc-part部分,获取相关的信息。
如下图所示,就是解密后的ST:

ST中authorization-data字段下代表用户身份权限的是PAC。下面我们只查看PAC的凭证信息部分PAC_LOGON_INFO。
如下图,主要通过User RID和Group RID来辨别用户权限。通过对比发现,ST中的PAC和TGT中的PAC是一致的。在正常的非S4u2Self请求的TGS过程中,KDC在ST中的PAC直接复制了TGT中的PAC。

(2)Sevice Session Key
TGS-REP包最外层的部分便是Service Session Key,用于确保客户端和KDC下一阶段的通信安全,它使用Logon Session Key加密。
如下图,对最外层的enc-part进行解密,它主要包含认证时间authtime、认证到期时间endtime、域名srealm、请求的服务名sname、协商标志flags等信息。需要说明的是ST中也包含Sevice Session Key。

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

注意⚠️:通过Impacket远程连接服务,默认不需要验证提供服务的服务端,因此这里没有AP-REP。
下图是一个简要的AP-REQ & AP-REP过程图,便于直观的了解请求过程。

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

下面对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 | # 场景A |
对于"对目标计算机有写权限"和"可以设置 msDS-AllowedToActOnBehalfOfOtherIdentity 属性"。如下场景B(打别人,获取别人服务器的管理员权限,一般是进行横向移动使用的):
1 | # 场景B |
下面演示的内容,就是场景A,主要目的是学习基于资源的约束委派,那就基于场景A去进行尝试。
这个是在域控机器上进行尝试的,抓取基于资源的约束委派kerberos协议的流量,看一下和普通的kerberos流量有何不同。
在域控中执行以下命令:
1 | # 1. 删除已存在的机器账户(如果存在) |
在Kali中执行以下命令,进行基于资源的约束委派攻击(Resource-Based Constrained Delegation,RBCD)。
1 | 11. 执行约束委派攻击 |
生成票据成功。

成功执行命令。

下面就是使用wireshark进行抓包,分析这时的kerberos数据包的情况。
1、S4u2Self
和正常的TGS-REQ包相比,S4u2Self协议的TGS-REQ包会多一个PA-DATA pA-FOR-USER,name为要模拟的用户,并且sname也是请求的服务自身。
场景A请求的数据包,如下图:

2、S4u2Proxy
和正常的TGS-REQ包相比,S4u2Proxy协议的TGS-REQ包会增加一个additional-tickets字段,该字段的内容就是上一步利用S4u2Self请求的ST。
首先是建立场景B的环境。
第一步我们先查看域控上有哪些账户,使用命令Get-ADUser -Filter *,结果如下:
1 | DistinguishedName : CN=Administrator,CN=Users,DC=test,DC=mydomain |
我想使用普通的域用户alice对bob对象进行资源委派。
上述列表中 SamAccountName 是 alice(普通用户格式)。关键前提: 为了进行 S4U (Service for User) 操作,alice 必须拥有 SPN (Service Principal Name)。普通的机器账户(如 computer$)默认有 SPN,但普通用户 alice 默认没有。
在域控上为alice用户注册一个spn,命令如下:
1 | # spn |

现在是有了spn,还差alice对bob对象的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: 指定具体的属性名称。

ok,我们现在写的权限也有了。
整个场景B的情况如下,该有的条件都满足了。
1 | 用户: alice (假设已获取该账户控制权,且该账户已被配置 SPN) |
目前alice普通域账户的spn已经注册,为final/test且alice对bob对象的msDS-AllowedToActOnBehalfOfOtherIdentity属性也有写的权限了。
接下来就是完成**“写属性 -> S4U2Self -> S4U2Proxy”**这一整套攻击流程。
阶段0:基础环境配置(至关重要)
Kerberos协议对时间和域名解析非常敏感。
1、配置DNS解析,Kali必须能解析域名。
1 | sudo vim /etc/hosts |
2、同步时间:Kerberos票据的时间戳误差不超过5min
1 | sudo ntpdate dc.test.mydomain |
阶段1:配置资源约束委派(写属性)
将 alice 添加到 bob 的 msDS-AllowedToActOnBehalfOfOtherIdentity 属性中。
这里我为了方便,直接在域控中执行下面的命令:
1 | # 1. 准确获取 用户 Alice 的对象 (避免获取成计算机) |
阶段 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' |
成功获取票据。

导入票据并执行命令:
1 | export KRB5CCNAME=Administrator@cifs_bob.test.mydomain@TEST.MYDOMAIN.ccache |

再回头去看,我们的目的是了解使用了S4u2Proxy的基于资源的约束委派和普通的Kerberos协议的流量的区别。
这里在生成票据的过程中,使用wireshark进行抓包,然后查看数据包。
这里的additional-tickets就是增加的字段。

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

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]上了。