使用只读域控制器攻击Kerberos密钥列表
2021-11-19
来源:嘶吼专业版
因此,这个想法很简单,你可以登录到你的混合 Azure AD 加入的 Windows 10 设备并自动访问云和本地资源。FIDO2 安全密钥成为进入云和本地资源的途径。
Microsoft 之前仅针对加入 Azure AD 的设备发布了相同的功能,但现在范围已扩展到混合环境。
一个新的证书收集攻击向量涉及只读域控制器服务器,让我们看看从研究新功能到实现对Impacket的新攻击的所有方法。
Azure 中的无密码体验
如上所述,Microsoft 通过 Azure Active Directory 将无密码体验扩展到本地资源。既然我们谈论的是本地资源的 SSO 功能,那就要先了解一下 Kerberos。
Kerberos 是主要的身份验证协议,用于验证 Windows 域中的安全对象(用户或主机)的身份。它基于对称密码学(共享秘钥)并使用票据的概念来验证这些身份。粗略地说,Kerberos 发出两种票据,一种是验证对象身份的票据授予票据 (TGT),另一种是对象用于对域中的其他服务进行身份验证的服务票据。
假设我想访问在服务器 A 中运行的服务 1。身份验证流程如下:
Kerberos 身份验证
很清楚、很简单。现在让我们把事情弄得更复杂一点。让我们将这种情况转移到混合环境。使用安全密钥的身份验证流程如下:
无密码身份验证
可以看到部分 TGT 交换完整的TGT,以及在云中复制的 Kerberos 服务器密钥。这是怎么回事?让我们开始深入研究这个问题。到目前为止,只有位于域控制器上的密钥发布中心 (KDC) 服务有权发布 TGT。但是,这种新的无密码体验的引入使事情发生了一些变化:正如我们在之前的流程中看到的那样,Azure AD 现在可以为一个或多个域发出 Kerberos TGT!这让我想到了另一个问题,krbtgt 帐户呢?
KDC 在任何域中使用的安全对象是 krbtgt 帐户。这是一个无法删除,也无法更改名称的特殊帐户,其密码用于派生密钥,用于加密 KDC 发布的 TGT。出于显而易见的原因,此帐户不会离开 AD 服务器。那么,Azure AD 如何在没有这个特殊帐户的情况下发布 TGT?以下是 Azure AD Kerberos 服务器对象图出现的位置。
Kerberos 服务器对象属性
Azure AD Kerberos 服务器是在本地 AD 中创建的对象,它在Azure AD中复制,不与任何物理服务器相关联(它是虚拟的)。它由遵循命名格式“krbtgt_######”的禁用用户帐户对象和关联的计算机帐户“AzureADKerberos”组成。
Azure AD 使用此对象为域生成部分 TGT。这样,用户帐户拥有 Azure AD Kerberos 服务器 TGT 加密密钥。这是在身份验证流程的第二步中用于加密部分票据的 Kerberos 服务器密钥。
但问题只解决了一半,我们域名的 krbtgt 密钥不需要发布到云端,而是使用这个新的 krbtgt_###### 帐户的密钥。因此,Azure 现在可以发行票据,但是服务票据和授权呢?
服务票据和授权继续由本地 AD 域控制器控制。Azure AD 没有将特权属性证书 (PAC) 包含到票据中所需的所有信息,这就是为什么它只签发部分票据的原因。
流量如何继续?一旦我们获得了部分票据,就必须将它(针对本地 AD)换成包含所有所需授权信息的完整票据,最后,使用它来请求不同的服务票据以访问本地资源。至此,我们获得了 Kerberos SSO 功能,并完成了无密码体验。
至此,只剩下一个问题,这个 Kerberos Server 对象到底是什么?为什么我们的本地 AD 信任它的密钥?只需查看与对象相关的设备帐户的属性,就很容易获得答案:
计算机属性
我们谈论的是只读域控制器 (RODC)。Microsoft 重用 RODC 的概念来实现 Kerberos 的“云”版本,允许 Azure AD 提供 SSO 功能。
还记得只读域控制器吗?
在继续之前,需要回顾一些关于 RODC 的基本概念。如果想了解更多信息,请点此了解。
简而言之,RODC 是一种域控制器,它承载 Active Directory 数据库的只读分区。除帐户密码外,它保存可写域控制器保存的所有 AD 对象和属性。但是,无法对存储在 RODC 上的数据库进行更改。它主要被设计用于部署在远程或分支机构环境中,这些环境通常具有相对较少的用户、较差的物理安全性或到中心站点的网络带宽较差。
我想回顾的主要概念是凭据缓存,它将非常有用。正如我之前提到的,默认情况下,帐户密码不会保存到RODC中(出于安全目的),因此分支站点中的身份验证过程略有不同:
1.用户向其站点的 RODC 发送 一个TGT 请求;
2.RODC 服务器检查用户凭据是否已缓存:
2.1如果没有,RODC 将请求转发到可写 DC;
2.3如果凭据已缓存,则身份验证由 RODC 解析;
3.可写 DC 对用户进行身份验证,签署 TGT,并将响应发送回 RODC;
4.RODC 将检查用户是否允许缓存其凭据:
4.1如果用户包含在 Allowed RODC Password Replication中,则他们的凭据存储在服务器中,并且 RODC 的 msDS-RevealedList 属性填充有用户名。后续的身份验证请求将由 RODC 管理;
4.2如果用户包含在Denied RODC Password Replication中,则不会存储他们的凭据,后续的身份验证请求将转发到可写 DC。
5.RODC 将 TGT 转发给用户,用户可以使用它来请求服务票据。
因此,当可写DC不可访问且RODC无法将请求转发给它时,缓存对于确保用户和计算机可以向RODC进行身份验证非常有用。然而,这可能是一把双刃剑。没有缓存凭据的原因是为了防止当RODC服务器被破坏时整个域处于危险之中。正如上所述,这些分支站点的安全性级别较低。因此,凭据缓存背后的主要思想只是保持在站点上操作所需的最少密码数量。
回到无密码场景,我们看到了 Microsoft 如何使用 Kerberos 在混合环境中支持 SSO 到本地资源。但是,对使用 NTLM 等旧协议的资源的访问发生了什么?
分析这种情况的简单方法是检查 Wireshark 捕获的无密码身份验证。我们最感兴趣分析的身份验证部分是图 2 的第 4 步和第 5 步,即部分票据和完整票据之间的交换。
完整的TGT是通过向KDC (krbtgt服务)发送一个TGS-REQ(packet n°577)获得的:
TGS-REQ 包括两个预认证数据 (PA-DATA)。带有部分 TGT 和未知 PA-DATA 类型编号 161 的 PA-TGS-REQ。
未知类型是一个明显的迹象,表明那里正在发生某些事情。如果 Wireshark 没有定义该数据类型,那是因为该数据相对较新。因此,首先要做的是查看 [MS-KILE]:Kerberos 协议扩展,并检查此 PA-DATA 类型。第一个结果是一种新型的 TGS-REQ:
3.3.5.7.8 密钥列表请求
当密钥发布中心 (KDC) 收到包含 aKERB-KEY-LIST-REQ[161] padata 类型的 krbtgt 服务名称 (sname) 的 TGS-REQ 消息时,KDC应该包括长期秘钥的客户端请求的加密类型?KERB-KEY-LIST-REP?[162]响应消息,并将其插入到 EncKDCRepPart 结构的加密数据中,如 [RFC6806] 中所定义:
2.2.11 KERB-KEY-LIST-REQ
KERB-KEY-LIST-REQ 结构用于请求 KDC 可以提供给客户端的密钥类型列表,以支持旧协议中的单点登录功能。它的结构是使用 ASN.1 符号定义的。语法如下:
KERB-KEY-LIST-REQ ::= SEQUENCE OF Int32 — encryption type —
KERB-KEY-LIST-REQ 的结构用于支持旧协议的 SSO 功能。只需检查请求的加密类型以及响应。捕获的内容如下:
PA-DATA 的内容是编码值 3003020117,代表加密类型 23 或 RC4-HMAC。这代表我们正在请求用户的 NT 哈希!
确认后,我开始查看响应(packet n°583):
在 TGS-REP 的加密部分(用会话密钥解密)中,我们可以找到 PA-DATA 类型 162,即 KERB-KEY-LIST-REP:
回到MS-KILE,我检查了结构的编码以解码数据并获取密钥:
2.2.12 KERB-KEY-LIST-REP
KERB-KEY-LIST-REP 结构包含 KDC 提供给客户端的密钥类型列表,以支持旧协议中的单点登录功能。它的结构是使用 ASN.1 符号定义的。语法如下:
?KERB-KEY-LIST-REP ::= SEQUENCE OF EncryptionKey
编码后的 PA-DATA 被解码为:
用户现在可以使用其 NT-Hash 与 NTLM 进行身份验证。
密钥列表攻击
现在,我们发现了 Windows 使用旧协议实现 SSO 的方式。在检查之后,反应是立竿见影的,我们还发现了一种新的潜在方法来转储要求较低的凭据!
这种新技术背后的想法很简单。如果我们能够用新的 PA-DATA 重现之前的 TGS-REQ,我们将拥有用户所有长期秘钥的列表。
因此,第一次尝试是将 TGS-REQ 复制到 krbtgt 服务,并使用普通用户添加 KERB-KEY-LIST-REQ 结构。这意味着包含的 TGT 是由 KDC 颁发给该普通用户的,无需知道 krbtgt 凭据即可轻松获取。响应是正常的 TGS-REP,没有新数据(不包括 KERB-KEY-LIST-REP)。第二次尝试是管理员用户的新 TGS-REQ。同样的过程,同样的结果,答案中没有关键字。这个想法并不是那么简单。
如果该过程适用于 RODC,让我们尝试将由此服务器签名的部分 TGT 包含到 TGS-REQ 中。复制由 RODC 签名并颁发给特定用户的部分 TGT,将其包含到 TGS-REQ 中,解密响应并获取密钥,可以对我们想要的任何用户重复。
经过几次尝试,漏洞开始显现:KDC_ERR_TGT_REVOKED(TGT 已被撤销)。为什么?这些用户包含在拒绝 RODC 密码复制组中,因此,此新 Kerberos 功能受到限制。默认情况下,拒绝管理员等用户复制其密码。
不过,我们可以攻击物理 RODC 服务器和虚拟服务器(Azure AD Kerberos 服务器对象包含在我们的攻击面中!)。同样重要的是,目标用户不需要缓存在 RODC 中!这是以前针对这类域控制器的攻击所需要的。
总而言之:
我们必须知道RODC (-rodcKey)的krbtgt凭据,因为我们需要创建带有一些特殊条件的部分票据和TGS-REQ。我们有几种获取凭据的方法,例如,如果我们获得RODC的本地管理员权限,就可以用Mimikatz转储SAM数据库。如果我们讨论的是虚拟RODC,可以针对Azure AD连接服务器;
我们必须有RODC的krbtgt帐户的ID (-rodcNo);
我们必须针对在拒绝组中未明确详细说明的用户;
有了这些要求,我打开了一个PR,其中包含一个新的示例脚本(keylistattack.py)和secretsdump.py中的一个新选项(-use-keylist),以演示这种攻击。
基本上,攻击有两个主要部分:用户列表和票据请求:
首先,我们需要知道我们的目标是什么,可以通过参数(LIST 选项)定义目标用户名(-t 标志)或定义具有目标用户名列表(-tf 标志)的文件,或者我们可以进行枚举(例如,SAMR 用户枚举) )。对于最后一个选项,我们需要一个低凭据用户,我们有两个选项。默认选项,过滤包含在拒绝组中的域用户,以及完整的一个(-full 标志)。
一旦我们知道要攻击谁,我们就会请求票据、处理响应并获取密钥!
keylistattack.py 使用没有过滤的 SAMR 用户枚举(-full 标志)
keylistattack.py 使用 SAMR 用户枚举和过滤(默认攻击)
keylistattack.py 定义目标用户名(-t 标志)
使用 Kerberos 密钥列表攻击选项 (-use-keylist) 的 secretsdump.py
如何检测?
提出了新的攻击,我们如何检测它?由于攻击实施了有效的密钥列表请求,该请求可能出现在启用了无密码的环境的正常操作中,因此选项并不多:
1.审计枚举操作:
SAMR 枚举:事件 4661——请求对象句柄(对象类型:SAM_DOMAIN、SAM_ALIAS、SAM_GROUP);
LDAP 枚举;
2.审核 Kerberos 服务票据操作:
成功请求:事件 4769——请求了 Kerberos 服务票据(票据选项:0x10000 ——可代理);
TGT 撤销:事件 4769——请求了 Kerberos 服务票据(失败代码:0x14 – KDC_ERR_TGT_REVOKED)
如何缓解这种攻击?
物理 RODC:
1.不要将“经过身份验证的用户”或“域用户”添加到“允许的 RODC 密码复制组”中。如果需要,应以与可写 DC(第 0 层)类似的级别保护这些 RODC;
2.将所有特权帐户和组添加到“拒绝 RODC 密码复制组”;
3.不要将常规用户帐户设置为 RODC 管理员,这些类型的帐户通常不如知名帐户安全,并且它们的泄露可能导致本地帐户(包括 RODC 的 krbtgt 帐户)的凭据转储。
虚拟 RODC(Azure AD Kerberos 服务器/无密码方案):
1.请确保只将具有无密码能力的用户添加到“允许的RODC密码复制组”;
2.Azure AD Connect服务器包含关键的身份数据,应该被视为第 0 层;
总结
1.物理和虚拟 RODC 都可能受到攻击;
2.由于需要复制权限,虚拟 RODC 中的攻击面更加广泛;
3.要攻击的帐户不需要缓存在 RODC 上;
4.不需要管理员凭据,如果你有用户列表,甚至不需要凭据;
5.该攻击要求至少有一台DC服务器使用Windows 2016/2019的更新版本(分别为kb4534307和kb4534321补丁);