发布于12小时前12小时 背景 在域内授权渗透中,AD CS 往往是容易被忽略的权限边界。典型问题不是 CA 服务本身存在漏洞,而是证书模板同时满足“低权限主体可注册、申请者可指定身份、证书可用于域认证”等条件,导致普通域用户具备申请其他身份认证证书的可能。 本文以 ESC1 类模板配置为例,重点讨论如何在不冒充高权限账号、不实际建立持久化的前提下完成验证,并给出日志取证和修复闭环。所有操作应在书面授权范围内进行,生产环境优先采用 LDAP 配置审计,而不是直接申请高权限身份的证书。 问题定位:什么情况下才构成有效风险 不能只看到“申请者提供主题”就直接判定漏洞。一个可利用的模板通常需要同时满足以下条件: 模板已发布到至少一台企业 CA,而不只是存在于配置分区。 低权限主体拥有 Enroll 权限,或者通过嵌套组继承到该权限。 msPKI-Certificate-Name-Flag 包含 0x1,即 CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT。 证书允许客户端认证,例如 Client Authentication、Smart Card Logon、PKINIT Client Authentication 或 Any Purpose。 msPKI-Enrollment-Flag 未启用 PEND_ALL_REQUESTS,或者审批流程形同虚设。 msPKI-RA-Signature 为 0,不要求授权签名。 模板 ACL 不允许普通用户修改模板、DACL 或所有者,否则风险可能高于单纯的 ESC1。 检查项关键属性或标识风险判断 申请者提供身份msPKI-Certificate-Name-Flag & 0x1允许在请求中提交 Subject 或 SAN 客户端认证用途1.3.6.1.5.5.7.3.2Client Authentication 智能卡登录1.3.6.1.4.1.311.20.2.2可用于域登录场景 PKINIT1.3.6.1.5.2.3.4可用于 Kerberos 初始认证 任意用途2.5.29.37.0用途边界过宽 人工审批msPKI-Enrollment-Flag & 0x2置位表示请求进入待审批 授权签名msPKI-RA-Signature值为 0 表示不要求 RA 签名 操作步骤一:确认 CA 和已发布模板 先在域成员机上使用系统自带工具确认企业 CA 是否可达,以及模板是否真正发布。仅凭 BloodHound、离线 LDAP 快照或历史扫描结果不能证明当前仍可利用。 certutil -config - -ping certutil -CATemplates certutil -v -template certutil -CATemplates 的输出用于确认 CA 当前发布的模板;certutil -v -template 用于核对模板标志、EKU 和有效期。测试账号如果无法访问 CA,也应区分是网络 ACL、RPC/DCOM 限制、Web Enrollment 未部署,还是模板本身不存在。 操作步骤二:通过 LDAP 筛选候选模板 下面的 PowerShell 只读取 AD 配置分区,不发起证书请求。执行环境需要 ActiveDirectory 模块,建议使用普通域用户运行,以便结果更接近真实权限边界。 Import-Module ActiveDirectory $root = Get-ADRootDSE $configNC = $root.configurationNamingContext $templateBase = 'CN=Certificate Templates,CN=Public Key Services,CN=Services,' + $configNC $caBase = 'CN=Enrollment Services,CN=Public Key Services,CN=Services,' + $configNC $published = Get-ADObject -SearchBase $caBase ` -LDAPFilter '(objectClass=pKIEnrollmentService)' ` -Properties dNSHostName,certificateTemplates $published | Select-Object Name,dNSHostName,certificateTemplates $authEku = @( '1.3.6.1.5.5.7.3.2', '1.3.6.1.4.1.311.20.2.2', '1.3.6.1.5.2.3.4', '2.5.29.37.0' ) $templates = Get-ADObject -SearchBase $templateBase ` -LDAPFilter '(objectClass=pKICertificateTemplate)' ` -Properties displayName,pKIExtendedKeyUsage,msPKI-Certificate-Name-Flag,msPKI-Enrollment-Flag,msPKI-RA-Signature $templates | ForEach-Object { $nameFlags = [int]$_.'msPKI-Certificate-Name-Flag' $enrollFlags = [int]$_.'msPKI-Enrollment-Flag' $raCount = [int]$_.'msPKI-RA-Signature' $eku = @($_.pKIExtendedKeyUsage) $supplySubject = (($nameFlags -band 0x1) -ne 0) $pending = (($enrollFlags -band 0x2) -ne 0) $clientAuth = (@($eku | Where-Object { $authEku -contains $_ }).Count -gt 0) $isPublished = (@($published.certificateTemplates) -contains $_.Name) if ($supplySubject -and $clientAuth -and (-not $pending) -and ($raCount -eq 0) -and $isPublished) { [pscustomobject]@{ Template = $_.Name DisplayName = $_.displayName Published = $isPublished SupplySubject = $supplySubject ClientAuthentication = $clientAuth ManagerApproval = $pending RASignatures = $raCount EKU = ($eku -join ',') } } } | Format-List 该脚本输出的是“配置候选项”,不是最终漏洞结论。还需要检查模板 ACL、组嵌套、CA 策略模块以及域控对证书映射的处理。新版域控启用强证书映射后,部分历史利用路径可能失败,但不应把系统加固措施当作模板错误配置的替代修复。 操作步骤三:核对 Enroll 权限和模板控制权 证书注册权限属于扩展权限。Certificate-Enrollment 的 rightsGuid 为 0e10c968-78fb-11d2-90d4-00c04f79dc55。除直接的 Enroll 权限外,还要关注 GenericAll、GenericWrite、WriteDacl、WriteOwner 等能够间接改变模板安全属性的权限。 $enrollGuid = [Guid]'0e10c968-78fb-11d2-90d4-00c04f79dc55' $templates | ForEach-Object { $template = $_ $acl = Get-Acl ('AD:\' + $template.DistinguishedName) $acl.Access | Where-Object { ($_.ActiveDirectoryRights.ToString() -match 'GenericAll|GenericWrite|WriteDacl|WriteOwner') -or (($_.ActiveDirectoryRights.ToString() -match 'ExtendedRight') -and (($_.ObjectType -eq $enrollGuid) -or ($_.ObjectType -eq [Guid]::Empty))) } | ForEach-Object { [pscustomobject]@{ Template = $template.Name Identity = $_.IdentityReference Rights = $_.ActiveDirectoryRights ObjectType = $_.ObjectType Inherited = $_.IsInherited Access = $_.AccessControlType } } } | Format-Table -AutoSize 看到 Domain Users、Authenticated Users 或某个业务组时,不要立即下结论。应使用实际测试账号核对 tokenGroups 或递归组成员关系,尤其注意跨域通用组、嵌套组以及历史遗留 SID。拒绝 ACE 与允许 ACE 并存时,也不能只靠字符串匹配判断最终访问结果。 单个模板还可以使用 dsacls 复核原始 ACL: dsacls "CN=模板名称,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=example,DC=local" 低影响漏洞验证原则 生产环境不建议直接为 Domain Admins、域控账户或现有管理员 UPN 申请证书。较稳妥的验证分为三级: 一级:只做 LDAP 与 CA 发布状态审计,证明危险条件同时成立。 二级:使用专用低权限测试账号申请其自身身份的证书,确认 Enroll 权限、CA 策略和模板可用性。该步骤不能单独证明身份替换成立。 三级:确有必要验证 Subject Alternative Name 行为时,使用经过审批的非特权诱饵账号,并限制证书有效期、保存请求号、序列号和指纹。测试后立即吊销证书并发布 CRL。 不要以真实管理员身份完成认证来“增强证明力度”。模板属性、ACL、CA 发布状态和受控诱饵账号结果已经足以支撑风险结论。直接获取高权限 TGT 或建立证书持久化会明显扩大测试影响。 日志留痕与事件关联 AD CS 验证不能只保留终端截图。至少应关联 CA、域控和目录服务三侧日志,并以请求号、证书序列号、调用账号和时间窗口作为主线。 日志位置事件 ID关注内容 CA 安全日志4886收到证书申请,记录请求者和请求属性 CA 安全日志4887证书已签发,记录模板、请求号和序列号 CA 安全日志4888证书请求被拒绝 CA 安全日志4898、4899、4900模板加载、模板更新或模板安全设置变化 域控安全日志4768证书登录触发的 TGT 请求,部分版本包含证书信息 目录服务日志5136证书模板对象或 CA 发布配置被修改 域控 System 日志Kdcsvc 39、40、41证书强映射、不受支持映射或 SID 不匹配问题 $start = (Get-Date).AddHours(-4) Get-WinEvent -FilterHashtable @{ LogName = 'Security' Id = 4886,4887,4888,4898,4899,4900 StartTime = $start } | Select-Object TimeCreated,Id,MachineName,Message Get-WinEvent -FilterHashtable @{ LogName = 'Security' Id = 4768,5136 StartTime = $start } | Select-Object TimeCreated,Id,MachineName,Message Get-WinEvent -FilterHashtable @{ LogName = 'System' Id = 39,40,41 StartTime = $start } | Select-Object TimeCreated,Id,ProviderName,Message 如果查询不到 4886 至 4900,不代表没有申请行为。应先确认 CA 上“审核证书服务”高级审核策略是否启用,以及安全日志容量是否足够。事件采集平台还应保留 Message 原文,避免只入库事件 ID 后丢失请求号、模板名称和序列号。 风险判断中的常见误区 模板存在但未发布:通常不能直接通过企业 CA 注册,应标记为潜在配置风险,而不是已验证漏洞。 只检查 EKU:模板允许客户端认证并不代表低权限用户可注册,也不代表可以指定其他身份。 只检查 Domain Users:风险权限可能来自业务组、嵌套组或模板对象上的 GenericAll。 把 KDC 强映射当作永久修复:域控策略升级可能阻断部分认证,但危险模板仍可能被其他认证服务使用。 修复后只删除本地证书:已签发证书仍可能在有效期内使用,需要吊销并确认 CRL 可访问。 修复建议 对于用户或计算机认证模板,取消“在请求中提供”Subject/SAN,改由 AD 属性构造身份。 从模板 ACL 中移除 Authenticated Users、Domain Users 等宽泛主体的 Enroll 权限,仅保留明确业务组。 清理普通运维组对模板的 GenericWrite、WriteDacl、WriteOwner 和 GenericAll 权限。 不再使用的模板应从 CA 取消发布,而不是只修改显示名称或停止客户端自动注册。 高敏感模板可启用经理审批或授权签名,但审批不能替代最小权限 ACL。 核查历史签发记录,对异常模板签发的证书按序列号吊销,并发布新的 CRL;必要时同时清理缓存和相关账号映射。 在域控侧评估并启用强证书映射要求,持续监控 Kdcsvc 39、40、41,但上线前应验证旧智能卡和业务证书兼容性。 为证书模板对象开启目录服务变更审计,重点监控 msPKI-Certificate-Name-Flag、pKIExtendedKeyUsage、模板 ACL 和 CA 的 certificateTemplates 属性。 复测与总结 复测时应重新完成三项检查:危险模板是否仍由 CA 发布、低权限测试账号是否仍具备 Enroll 或模板修改权限、CA 是否还会接受由申请者提供身份的请求。不要只以控制台界面显示正常作为修复依据,最终应回到 LDAP 属性、有效 ACL 和 CA 审计日志进行确认。 AD CS 类问题的核心是权限边界组合,而不是某一个孤立开关。授权渗透中采用“配置筛选、有效权限核对、受控验证、日志关联、证书吊销”的流程,既能形成可信证据,也能避免为了证明风险而实际获取高权限身份。 网络请求、日志与边界流量分析示意 工具配置、参数调优与结果校验示意
11小时前11小时 建议把 ESC1 验证拆成“配置成立、权限可达、证书签发、身份映射”四层。只看到模板允许自定义 SAN 还不能直接判定可利用,尤其现在强证书映射策略会影响最终结果。 1. 先做只读确认,判断条件是否同时成立 msPKI-Certificate-Name-Flag 包含 0x1,即 ENROLLEE_SUPPLIES_SUBJECT。 EKU 包含客户端身份用途,例如 Client Authentication 1.3.6.1.5.5.7.3.2、PKINIT Client Authentication 1.3.6.1.5.2.3.4 或 Any Purpose。 msPKI-RA-Signature=0,且未设置人工审批 PEND_ALL_REQUESTS。 低权限主体对模板具有有效 Enroll 权限,不只是 ACL 中存在某条允许 ACE,还要考虑继承、拒绝 ACE 和组嵌套。 模板确实发布在目标 CA 上,并且申请主体同时有 CA 的 Request Certificates 权限。 $root = Get-ADRootDSE $base = "CN=Certificate Templates,CN=Public Key Services,CN=Services,$($root.configurationNamingContext)" $t = Get-ADObject -SearchBase $base ` -LDAPFilter "(&(objectClass=pKICertificateTemplate)(cn=TemplateName))" ` -Properties displayName,msPKI-Certificate-Name-Flag,msPKI-Enrollment-Flag, msPKI-RA-Signature,pKIExtendedKeyUsage $t | Select-Object DistinguishedName,DisplayName, @{n='NameFlag';e={'0x{0:X8}' -f $_.'msPKI-Certificate-Name-Flag'}}, @{n='EnrollmentFlag';e={'0x{0:X8}' -f $_.'msPKI-Enrollment-Flag'}}, msPKI-RA-Signature,pKIExtendedKeyUsage $enrollGuid = [guid]'0e10c968-78fb-11d2-90d4-00c04f79dc55' (Get-Acl "AD:$($t.DistinguishedName)").Access | Where-Object { $_.ObjectType -eq $enrollGuid -or $_.ActiveDirectoryRights -match 'GenericAll|WriteDacl|WriteOwner' } | Select-Object IdentityReference,AccessControlType,ActiveDirectoryRights, ObjectType,IsInherited CA 侧可以再确认模板发布情况及全局 SAN 策略,避免把 ESC6 误判成 ESC1: certutil -config "CA主机\CA名称" -catemplates certutil -v -template "TemplateName" certutil -config "CA主机\CA名称" -getreg policy\EditFlags 如果 EditFlags 含有 EDITF_ATTRIBUTESUBJECTALTNAME2,CA 允许从请求属性接收 SAN,这属于另一条边界,报告中最好与模板自身的 ENROLLEE_SUPPLIES_SUBJECT 分开记录。 2. 低影响签发验证不要使用管理员、DC、krbtgt 等真实高价值身份 可以准备两个无组权限、无 SPN 的临时账号:一个作为申请者,另一个作为目标身份。这样能证明“申请者可指定其他主体”,但不会触碰生产管理员身份。仅做配置验证时,到 CSR 生成和检查为止;必须验证 CA 行为时再提交。 [Version] Signature="$Windows NT$" [NewRequest] Subject = "CN=esc1-target" KeyLength = 2048 HashAlgorithm = sha256 KeyAlgorithm = RSA ProviderName = "Microsoft Software Key Storage Provider" MachineKeySet = FALSE Exportable = FALSE RequestType = PKCS10 [Extensions] 2.5.29.17 = "{text}" _continue_ = "[email protected]" [RequestAttributes] CertificateTemplate = TemplateName certreq -new esc1.inf esc1.req certutil -dump esc1.req certreq -submit -config "CA主机\CA名称" esc1.req esc1.cer certutil -dump esc1.cer 建议不执行 certreq -accept,也不直接发起 PKINIT。只要返回的证书中包含指定的目标 UPN、预期 EKU 和有效签名,已经足以证明签发边界存在。私钥生成建议放在一次性测试配置文件或隔离虚拟机内,结束后销毁环境,避免残留不可见的用户密钥容器。 3. 身份映射要单独判定 安装了相关更新的域中,KDC 的强证书绑定可能优先使用证书 SID 扩展,而不是按 SAN UPN 映射。此时证书虽然带有目标 UPN,最终仍可能映射回申请者,不能直接写成“可冒充任意用户”。需要同时检查: 证书是否包含 SID 安全扩展 1.3.6.1.4.1.311.25.2。 模板 msPKI-Enrollment-Flag 是否包含 0x00080000(不包含安全扩展)。 域控上的 StrongCertificateBindingEnforcement 实际策略。 reg query HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v StrongCertificateBindingEnforcement certutil -dump esc1.cer 如果要做端到端认证,仍建议只在两个低权限测试账号之间进行,并把结论表述为“签发边界成立、当前映射策略下认证成功/失败”,不要只凭模板配置推断。 4. 日志闭环 CA 上应提前启用 Certification Services 审计。该操作会修改 CA 配置并需要重启服务,应放在变更窗口执行: auditpol /set /subcategory:"Certification Services" /success:enable /failure:enable certutil -setreg CA\AuditFilter 127 net stop certsvc net start certsvc 重点关联以下记录: CA 安全日志:4886 收到申请、4887 批准并签发、4888 拒绝、4889 进入待审批。 模板变更:4898、4899、4900,以及域控目录服务变更事件 5136。 如执行证书认证:域控 4768,关注证书颁发者、序列号、指纹以及最终映射到的账号。 CA 数据库中的 RequestID 是闭环主键,建议记录申请时间、RequesterName、模板、序列号和处置状态: certutil -view -restrict "RequestID=请求编号" ^ -out "RequestID,RequesterName,CertificateTemplate,Disposition,SerialNumber,NotBefore,NotAfter" 测试结束后不要删除 CA 数据库记录。应撤销测试证书、发布新 CRL,并保留 RequestID、序列号及对应日志作为证据: certutil -revoke 证书序列号 1 certutil -crl 这样最终结论可以明确区分:模板配置风险、申请权限是否可达、CA 是否实际签发、当前域控映射策略下是否能完成认证,避免把“疑似 ESC1”直接等同于“可接管高权限账号”。
创建帐户或登录后发表意见