Certighost(CVE-2026-54121)"

admin 2026-10-20 02:09:11 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

cover_image

Certighost(CVE-2026-54121)

h0j3n
h0j3n

securitainment

2026年7月24日 22:58
广东

在小说阅读器读本章

去阅读

原文链接 作者
https://gist.github.com/H0j3n/a5ef2609b5f2944ac2390a191a534c26 @h0j3n, @aniqfakhrul

Certighost 是一个 Active Directory 证书服务(AD CS)漏洞,在受测的 AD CS 配置下,允许低权限域用户冒充域控制器并实现域控接管。该问题已在 2026 年 7 月的安全更新中修复。

漏洞路径是 AD CS 注册过程中一种称为 chase(追踪)的回退机制,发生在目录对象解析期间。通过在请求中提供 cdc等请求属性,攻击者可以诱导证书颁发机构(CA)向攻击者控制的主机请求属于域控制器的身份数据。随后,CA 在签发证书时使用了这些数据。

本文将解释 chase 路径的工作原理、为何会被滥用,以及更新中做了哪些改变。

Active Directory 证书服务简介

如果您已经在使用 AD CS,可以直接跳过本节。对于本文的后续内容,您只需将证书理解为一种经过签名的身份证明。如同 Kerberos 票据一样,证书可以在身份验证过程中出示,以表明用户或计算机的身份。

AD CS 是微软的公钥基础设施实现。它与 Active Directory 集成,签发 X.509 证书,用于加密、签名、安全通信和身份验证等用途。

证书将一个主体与公钥绑定。私钥由请求者保管,而证书包含公钥和由证书颁发机构签名的身份信息。信任 CA 的服务可以使用该签名来信任证书中的身份。

证书模板控制注册流程。模板决定谁可以请求证书、证书的用途、必须包含哪些身份信息,以及 CA 是否可以接受请求中提供的身份信息。

此处相关的概念是基于证书的客户端身份验证。客户端从企业 CA 请求证书,随后将其提交给密钥分发中心(KDC)以获取 Kerberos 凭据。

PKINIT 与证书映射

为便于理解,假设有一个名为 ABC.LOCAL的小型实验域并安装了 AD CS。低权限账户可以从其有权注册的模板请求证书,然后使用该证书向 KDC 进行身份验证。

在证书身份验证期间,KDC 将证书中的身份映射到 Active Directory 账户,映射成功后签发 Kerberos TGT。

背景:chase 回退机制

在讨论漏洞之前,我们需要了解一种注册行为。在某些跨域控制器的注册场景中,CA 可能会执行第二次目录查询,此处称为 chase(追踪)。

两个请求属性影响该查询:

  • cdc

(Client DC,客户端域控),标识 CA 应联系的主机
* rmd

(Remote Domain,远程域),标识 CA 应查询的主体

当两个属性同时存在时,CA 通过 SMB 和 LDAP 联系 cdc指定的主机,然后搜索 rmd指定的主体。请求处理路径读取这些值并将其传递到远程目录查询中。

Wireshark 抓包显示 CA 跟随请求者控制的 cdc目标,通过 SMB/LSA 和 LDAP 连接到攻击者主机。

漏洞:Certighost

CA 接受了请求者提供的 chase 目标,而未先证明该目标确实是其声称的域控制器。这使得攻击者可以在自己控制的主机上运行 LDAP 和 LSA 服务,将 CA 引导到该主机,并返回针对所选目标主体的目录数据。

在存在漏洞的流程中,攻击者在证书请求中提供 cdc和 rmd。CA 向 cdc中的地址发起 SMB 和 LDAP 连接,对 rmd中的主体执行 chase 查询,并使用返回的身份数据构建证书。

问题不仅在于出站连接。CA 将该主机的响应当作请求的目录数据使用。在测试链中,攻击者可以返回域控制器的 objectSid和 dNSHostName。这些值影响了 CA 签发的证书身份数据,包括身份验证期间使用的强映射 SID 和 DNS 身份字段。

通过默认 ms-DS-MachineAccountQuota设置创建的计算机账户是有效的域主体。这使得攻击者控制的 chase 端点能够满足 CA 继续处理所需的身份验证检查,即使它并非被冒充的域控制器。

存在漏洞的 chase 流程:CA 跟随请求者控制的 cdc,接受攻击者提供的目录数据,并签发目标 DC 的证书身份数据。

图示展示了存在漏洞的 chase 中涉及的三方:攻击者准备有效的计算机账户和流氓服务,CA 跟随请求者控制的 cdc目标并信任返回的身份数据,随后域控制器通过基于证书的身份验证和复制访问被冒充。

概念验证演练

实验环境

我们的测试环境包含:

  • Windows Server 2016 或更高功能级别的 AD 林
  • 域控制器:WDC01.abc.local(192.168.8.128)
  • 企业 CA:WCA01.abc.local(192.168.8.129)上的 abc-WCA01-CA
  • 默认的 ms-DS-MachineAccountQuota值为 10
  • 默认的 Machine证书模板及其默认访问控制列表
  • 攻击者主机位于 192.168.8.134
  • 一个低权限 Domain Users 账户:normaluser

步骤 1:安装依赖

概念验证是一个自包含的 Python 脚本。它需要 impacket、cryptography、pyasn1、asn1crypto 和 dnspython。

sudo pip install --break-system-packages git+https://github.com/fortra/impacket.git cryptography pyasn1 asn1crypto pycryptodome dnspython

步骤 2:运行概念验证并观察结果

sudo python3 certighost.py \\
  -d abc.local \\
  -u normaluser -p '[PASSWORD]' \\
  --dc-ip 192.168.8.128

脚本会发现 CA 和目标域控制器,创建计算机账户,启动本地 LDAP 和 LSA 服务,提交精心构造的注册请求,并产生如下终端输出。

成功运行 Certighost 的终端输出

此时,攻击者已获得一张由 CA 签名的证书,该证书在受测配置下可作为目标域控制器进行身份验证,并获得了该账户的 Kerberos 凭据缓存。

步骤 3:DCSync

域控制器账户具有目录复制权限。利用获得的Kerberos 凭据,攻击者可以请求账户机密信息,包括 krbtgt机密。

成功执行 DCSync 的输出,显示 krbtgt账户

概念验证的工作原理

脚本在一个进程中完成完整攻击链:

  1. 使用提供的低权限账户连接到 LDAP,发现 CA、域控制器、域 SID 和域 GUID。
  2. 通过 ms-DS-MachineAccountQuota创建计算机账户,并注册所需的服务主体名称。
  3. 启动本地 LSA 和 LDAP 服务。这些服务将 CA 的身份验证质询中继到真实域控制器,使 chase 端点被接受为有效的域主体。
  4. 提交包含 cdc和 rmd属性的证书请求。
  5. 接收携带目标域控制器身份数据的证书,包括身份验证流程使用的 SID 和 DNS 名称数据。
  6. 使用证书作为目标域控制器进行身份验证,并写入生成的凭据缓存。

更新后的行为

2026 年 7 月的更新改变了 CA 端的请求处理路径。在继续 chase 之前,CA 会根据 Active Directory 验证提供的 cdc目标。

更新在主体加载路径中增加了验证步骤。当验证门控处于活动状态时,CA 会检查 cdc中提供的主机名是否在真实目录中解析为合法的域控制器计算机对象,然后才继续 chase。验证失败会将请求引导至错误路径,而非继续 chase。

组件 更新前 更新后
Chase 目标 CA 跟随请求者提供的目标 CA 根据真实目录验证提供的 cdc主机名
主体查询 远程响应被视为权威 目标必须解析为合法的域控制器计算机对象
证书身份数据 返回的 SID 和主机名可能受攻击者控制 解析仅在目标验证和后续 SID 比较通过后进行
证书请求结果 伪造的 chase 响应可能导致证书签发 验证失败或 SID 不匹配会进入错误路径

修复解决了使 Certighost 成为可能的信任边界:chase 端点不再仅因其作为域主体响应而被接受。7 月的二进制文件包含围绕新验证的门控,因此该保护在该门控及其验证路径处于活动状态时生效。

下图总结了 7 月更新后的路径。它展示了 CA 在继续 chase 之前必须通过哪些检查,以及哪些检查会在此前阻止请求。

7 月更新流程:CA 在允许追踪 chase 继续之前,根据 AD 验证 chase 目标。

从上到下阅读该图:请求进入验证路径,每个检查回答一个是非问题,请求必须在 chase 继续之前通过每个检查。未通过的检查会在此前停止请求。每个检查背后的具体条件——长度和字符检查、域控制器计算机对象要求,以及解析后的 SID 比较——在下文段落中描述。

验证函数拒绝过长和 IP 字面量的目标,在构造 LDAP 查询之前阻止过滤字符集,并要求唯一的计算机对象且其 userAccountControl包含 SERVER_TRUST_ACCOUNT(8192)。如果第一次目录搜索没有匹配结果,代码会使用提取的基准 DN 重试。加载器仅在验证成功返回后才到达引用续接路径;它还包含一个后续的解析 SID 比较。这些控制流观察已与哈希匹配的 7 月 DLL 进行了核对。

详细的补丁后流程:

1. User submits cert enrollment request with cdc=\"attacker.example.com\"

2. _LoadPrincipalObject() calls _GetDSObject() -> fails (referral needed)

3. polGetRequestAttribute(\"cdc\", &bstrString) -> reads attacker's hostname

4. NEW: Feature_3185813818 check (servicing flag)
   - DISABLED -> old behavior (backward compat)
   - ENABLED -> _ValidateChaseTargetIsDC(bstrString)
      - Reject if empty
      - Reject if > 260 chars
      - Reject if IPv4 address (RtlIpv4StringToAddressW)
      - Reject if IPv6 address (RtlIpv6StringToAddressW)
      - Reject if contains LDAP injection chars: ( ) * [ \\ ]
      - LDAP search: (&(objectCategory=computer)(dNSHostName=<target>)
                       (userAccountControl:1.2.840.113556.1.4.803:=8192))
         - 8192 = SERVER_TRUST_ACCOUNT = must be a real DC
         - If 0 results -> try with extracted base DN (_ExtractBaseDNForDCSearch)
         - If still 0 -> REJECT

5. Only if validation passes -> _GetDSObject(a2, 1, bstrString) -> connect to verified DC

6. NEW: _GetObjectSID() -> verify resolved object's SID matches requester's SID
   - If SID mismatch -> REJECT (prevents object substitution)

代码分析

概念验证展示了影响,而代码路径解释了根本原因。相关逻辑位于 certpdef.dll中,这是由 certsrv.exe加载的 AD CS 证书策略企业模块。存在漏洞的行为位于请求主体加载路径中,该路径在解析请求者身份时使用请求中提供的属性。

我们对比 6 月和 7 月的构建版本,因为 6 月是存在漏洞的基线版本,7 月是微软的补丁版本。这使得 7 月新增的函数成为定位修复的有用标记。

请求路径中涉及的关键函数如下:

构建版本 函数 重要性说明
6 月 / 存在漏洞 CRequestInstance::_LoadPrincipalObject 存在漏洞的集成点;读取请求者控制的 chase 目标。
6 月 / 存在漏洞 CRequestInstance::_GetDSObject 目录查询/chase 汇点,使用未受信任的 cdc主机到达。
6 月 / 存在漏洞 CRequestInstance::_GetObjectSID 7 月身份验证更改之前的原始 SID 获取路径。
7 月 / 已修补 CRequestInstance::_ExtractBaseDNForDCSearch DC 验证 LDAP 搜索使用的辅助函数。
7 月 / 已修补 CRequestInstance::_ValidateChaseTargetIsDC 验证 cdc解析为真实的域控制器。
7 月 / 已修补 CRequestInstance::_LoadPrincipalObject 已修补的集成点;在 chase 之前调用验证。
7 月 / 已修补 CRequestInstance::_GetDSObject 相同的逻辑汇点,现仅在受保护路径活动时经验证后才到达。
7 月 / 已修补 CRequestInstance::_GetObjectSID 对象解析后更新的身份/SID 验证路径。
7 月 / 已修补 Feature_3185813818 围绕更新行为的服务功能门控。

7 月新增的关键部分是 CRequestInstance::_ValidateChaseTargetIsDC、CRequestInstance::_ExtractBaseDNForDCSearch和 Feature_3185813818门控。

6 月存在漏洞版本的流程

在 6 月存在漏洞的构建版本中,CRequestInstance::_LoadPrincipalObject读取 cdc请求属性,并直接将其传入启用了 chase 的 _GetDSObject。

// decompiled shape from CRequestInstance::_LoadPrincipalObject
polGetRequestAttribute(policy, L\"cdc\", &bstrString);

CRequestInstance::_GetDSObject(this, policy, 1, bstrString);
//                                           ^ chase enabled
//                                              ^ requester-controlled host

请求到目录的路径为:

certificate request attribute -> cdc BSTR -> _GetDSObject(..., chase = 1, cdc)

换言之,请求者控制的路由数据在 CA 尚未检查目标是否为域控制器之前,就已经到达了目录权威决策。

7 月修补版本的流程

7 月修补版本为相同的 chase 增加了功能门控验证调用,随后执行额外的 SID 验证路径。

// decompiled shape from CRequestInstance::_LoadPrincipalObject
polGetRequestAttribute(policy, L\"cdc\", &bstrString);

if (Feature_3185813818::IsEnabled()) {
    CRequestInstance::_ValidateChaseTargetIsDC(this, bstrString);

    CRequestInstance::_GetDSObject(this, policy, 1, bstrString);

    CRequestInstance::_GetObjectSID(this, &resolved_sid, mode);
}

在修补后的控制流中仍可见一个遗留行为分支:

CRequestInstance::_GetDSObject(this, policy, 1, bstrString);

该分支在服务功能门控未启用时到达。对于实验室验证,功能状态很重要,因为受保护路径是有条件的。

代码分析:_ValidateChaseTargetIsDC

CRequestInstance::_ValidateChaseTargetIsDC是主要的新增防护。它接收请求者提供的 cdc值,在 _GetDSObject执行 chase 之前检查其是否为域控制器主机名。

验证分为两层。

首先,拒绝非安全 DC 主机名的值:

// 1. Strip leading backslashes, then reject empty input
while (*target == L'\\\\')
    target++;
if (*target == L'\\0')
    reject;

// 2. Reject oversized hostnames
if (wcslen(target) > 0x104)
    reject;

// 3. Reject IPv4 and IPv6 literals
if (RtlIpv4StringToAddressW(target, TRUE, &end, &ipv4) == STATUS_SUCCESS && *end == 0)
    reject;

if (RtlIpv6StringToAddressW(target, &end, &ipv6) == STATUS_SUCCESS && *end == 0)
    reject;

// 4. Reject LDAP filter metacharacters
for (p = target; *p; p++) {
    if ((*p - 0x28) <= 2 || (*p - 0x5b) <= 2)
        reject;
}

IP 检查阻止了如 192.0.2.10或 ::1的原始地址 chase 目标。元字符检查确保主机名保持在 LDAP 过滤器槽位内。

字符串检查之后,函数向 Active Directory 查询该目标是否为 DC:

(&(objectCategory=computer)(dNSHostName=%s)(userAccountControl:1.2.840.113556.1.4.803:=8192))

8192即 SERVER_TRUST_ACCOUNT,域控制器计算机账户使用的 userAccountControl位。更新后的代码搜索恰好一个设置了该位且 dNSHostName匹配所提供 cdc值的计算机对象。

搜索路径大致如下:

ldap_search_ext_sW(ldap, NULL, LDAP_SCOPE_SUBTREE,
                   filter, NULL, TRUE, NULL, NULL,
                   &timeout, 1, &result);

count = ldap_count_entries(ldap, result);

if (count == 0) {
    base_dn = CRequestInstance::_ExtractBaseDNForDCSearch(this);
    ldap_search_ext_sW(ldap, base_dn, LDAP_SCOPE_SUBTREE,
                       filter, NULL, TRUE, NULL, NULL,
                       &timeout, 1, &result);
    count = ldap_count_entries(ldap, result);
}

if (count != 1)
    reject;

缺失的检查简单却关键:chase 目标必须是 AD 中注册的域控制器,而不仅仅是证书请求中的主机名字符串。

更新为何能修复漏洞

更新前,存在漏洞的链为:

attacker request -> cdc=\"attacker host\" -> CA LDAP chase -> attacker response -> issued identity

更新后,预期链为:

attacker request -> cdc=\"some host\"
        |
        v
validate hostname shape
        |
        v
query AD for dNSHostName=<host> AND SERVER_TRUST_ACCOUNT
        |
        v
require exactly one real DC object
        |
        v
only then call _GetDSObject(..., chase = 1, cdc)
        |
        v
verify resolved SID / identity

更新改变了两点:

  1. 目标真实性:

chase 目标必须是 AD 中注册的域控制器,而非任意的请求者控制主机。
2. 对象真实性:

通过 chase 解析的对象必须与预期身份匹配,即使查询路径不寻常也能防止对象替换。

关注的函数

对于追踪请求路径的安全研究人员,从以下函数开始:

June vulnerable build
  CRequestInstance::_LoadPrincipalObject
  CRequestInstance::_GetDSObject
  CRequestInstance::_GetObjectSID

July patched build
  Feature_3185813818
  CRequestInstance::_ExtractBaseDNForDCSearch
  CRequestInstance::_ValidateChaseTargetIsDC
  CRequestInstance::_LoadPrincipalObject
  CRequestInstance::_GetDSObject
  CRequestInstance::_GetObjectSID

文章的优质代码参考点:

  1. 6 月 _LoadPrincipalObject展示 cdc流入 _GetDSObject。
  2. 7 月 _LoadPrincipalObject展示在 _GetDSObject之前调用 _ValidateChaseTargetIsDC。
  3. 7 月 _ValidateChaseTargetIsDC展示 IP 拒绝和 LDAP 过滤器构造。
  4. 7 月 _ValidateChaseTargetIsDC展示 userAccountControl:1.2.840.113556.1.4.803:=8192DC 查询。
  5. 7 月 _GetObjectSID或其调用点展示新增的 SID 验证路径。

不安装更新的临时修复:禁用 chase 回退

如果无法立即安装 7 月更新,可以通过策略标志完全关闭存在漏洞的代码路径,因为 cdcchase 是一项可选的回退功能,并非在每个请求上运行的代码:

certutil -setreg policy\\EditFlags -EDITF_ENABLECHASECLIENTDC
Restart-Service CertSvc -Force

这是缓解措施,而非补丁。如果在未修补的 CA 上由管理员、镜像或组策略重新启用 EDITF_ENABLECHASECLIENTDC,漏洞将再次可被利用。

注意:此热修复仅在受控实验室环境中验证,未在生产 CA 上验证。在生产环境中应用之前,请在镜像您环境的暂存 CA 上进行测试,并确认没有合法的注册依赖于 chase 回退——一旦清除该标志,这些请求将会失败。7 月更新仍然是推荐的补救措施。

时间线

  • 2026 年 5 月 14 日:

向微软安全响应中心报告漏洞
* 2026 年 5 月 14 日:

案件分配
* 2026 年 5 月 22 日:

案件调查并确认
* 2026 年 7 月 14 日:

微软发布补丁,编号 CVE-2026-54121
* 2026 年 7 月 24 日:

公开披露

参考资料

  • certighost.py PoC 脚本
  • Certipy AD CS 工具包
  • 微软安全更新指南:CVE-2026-54121
  • MS-WCCE:Windows 客户端证书注册协议

致谢

作者感谢微软安全响应中心的确认。


免责声明:本博客文章仅用于教育和研究目的。提供的所有技术和代码示例旨在帮助防御者理解攻击手法并提高安全态势。请勿使用此信息访问或干扰您不拥有或没有明确测试权限的系统。未经授权的使用可能违反法律和道德准则。作者对因应用所讨论概念而导致的任何误用或损害不承担任何责任。


Certighost(CVE-2026-54121)" 网络安全文章

Certighost(CVE-2026-54121)"

Certighost是ADCS漏洞,允许低权限域用户冒充域控制器并实现域控接管。攻击者利用chase回退机制,通过提供cdc和rmd属性诱导CA向攻击者控制的主机请求域控制器身份数据,从而签发错误证书。2026年7月更新通过验证cdc目标是否为真实域控制器修复此问题。建议立即应用安全更新并审查ADCS配置。
G.O.S.S.I.P特别推荐2026-07-24“千里码”安全漏洞" 网络安全文章

G.O.S.S.I.P特别推荐2026-07-24“千里码”安全漏洞"

华东师大与上交大团队发现公交二维码密码学漏洞千里码,攻击者仅需分析一次问题码即可伪造签名并持续冒用他人电子公交卡盗刷。该漏洞影响国内部分城市,已负责任披露并修复。建议用户除乘车外切勿在社交平台分享公交码防范风险,企业可联系研究者获取检测工具排查。
威胁情报|从“合规邮件”到远程控制:一起Web3钱包钓鱼攻击调查" 网络安全文章

威胁情报|从“合规邮件”到远程控制:一起Web3钱包钓鱼攻击调查"

慢雾安全团队披露一起针对Web3钱包用户的钓鱼攻击。攻击者冒充Keystone和OneKey等品牌,以合规更新为由发送钓鱼邮件,诱导用户下载伪造的DocuSign桌面程序。实际载荷为VBS、BAT或EXE文件,用于静默安装ScreenConnect远程控制客户端,实现无人值守远控。攻击者还注册了多个仿冒域名和GitHub仓库分发恶意软件。建议用户警惕要求下载陌生程序的请求,企业应检查终端异常服务并更换凭据。
每周蓝军技术推送(2026.7.18-7.24)" 网络安全文章

每周蓝军技术推送(2026.7.18-7.24)"

该文档是2026年7月18日至24日的每周蓝军技术推送周报,由天元实验室发布。核心内容涵盖内网渗透、终端对抗、漏洞相关及人工智能安全四大领域。关键发现包括多个高危漏洞(如CVE-2026-63030WordPressSQL注入、CVE-2026-25243Redis双重释放RCE)及AI自主发现0day漏洞的案例。可操作建议是安全团队应关注并修补相关漏洞,加强内网与终端防护。
评论:0   参与:  0