Files
mukul975 c21af3347e Complete folder anatomy for all 649 cybersecurity skills + update LICENSE to Mahipal
- Add scripts/agent.py and references/api-reference.md to all remaining skills
- Update all 648 LICENSE files: copyright now reads 'Mahipal'
- Add implementing-security-monitoring-with-datadog (new skill with full anatomy)
- All 649 skills now have: SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
2026-03-11 00:22:12 +01:00

123 lines
4.6 KiB
Python

#!/usr/bin/env python3
"""Agent for detecting and testing AD CS ESC1 misconfiguration (enrollee supplies SAN)."""
import argparse
import json
import subprocess
import sys
from datetime import datetime, timezone
def enumerate_certificate_templates():
"""Enumerate AD CS certificate templates via certutil or Certipy."""
templates = []
try:
result = subprocess.check_output(
["certutil", "-v", "-template"],
text=True, errors="replace", timeout=30
)
current = {}
for line in result.splitlines():
line = line.strip()
if line.startswith("Template["):
if current:
templates.append(current)
current = {"raw_lines": []}
if ":" in line:
key, _, val = line.partition(":")
current[key.strip()] = val.strip()
if current:
current["raw_lines"].append(line)
if current:
templates.append(current)
except (subprocess.SubprocessError, FileNotFoundError):
pass
return templates
def check_esc1_vulnerable(template):
"""Check if a certificate template is vulnerable to ESC1."""
indicators = []
raw = "\n".join(template.get("raw_lines", []))
if "CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT" in raw or "ENROLLEE_SUPPLIES_SUBJECT" in raw:
indicators.append("Enrollee can supply Subject Alternative Name (SAN)")
if "Client Authentication" in raw or "1.3.6.1.5.5.7.3.2" in raw:
indicators.append("Template allows Client Authentication EKU")
if "Domain Users" in raw or "Authenticated Users" in raw:
indicators.append("Low-privileged users can enroll")
if "Manager approval" not in raw and "manager approval" not in raw.lower():
indicators.append("No manager approval required")
return indicators
def run_certipy_find(domain, username, password, dc_ip):
"""Run Certipy to find vulnerable certificate templates."""
findings = []
try:
result = subprocess.check_output(
["certipy", "find", "-u", f"{username}@{domain}",
"-p", password, "-dc-ip", dc_ip, "-vulnerable", "-json"],
text=True, errors="replace", timeout=60
)
data = json.loads(result)
for tmpl in data.get("Certificate Templates", []):
if "ESC1" in str(tmpl.get("Vulnerabilities", [])):
findings.append({
"template": tmpl.get("Template Name", ""),
"vulnerability": "ESC1",
"enrollable_by": tmpl.get("Enrollment Rights", []),
})
except (subprocess.SubprocessError, json.JSONDecodeError, FileNotFoundError):
pass
return findings
def main():
parser = argparse.ArgumentParser(
description="Detect AD CS ESC1 vulnerability (authorized pentesting only)"
)
parser.add_argument("--certutil", action="store_true", help="Use certutil enumeration")
parser.add_argument("--certipy", action="store_true", help="Use Certipy tool")
parser.add_argument("--domain", help="AD domain name")
parser.add_argument("--username", help="Domain username")
parser.add_argument("--password", help="Domain password")
parser.add_argument("--dc-ip", help="Domain controller IP")
parser.add_argument("--output", "-o", help="Output JSON report")
args = parser.parse_args()
print("[*] AD CS ESC1 Vulnerability Detection Agent")
print("[!] For authorized security testing only")
report = {"timestamp": datetime.now(timezone.utc).isoformat(), "findings": []}
if args.certutil:
templates = enumerate_certificate_templates()
for tmpl in templates:
vulns = check_esc1_vulnerable(tmpl)
if vulns:
report["findings"].append({
"template": tmpl.get("Template", "Unknown"),
"esc1_indicators": vulns,
"indicator_count": len(vulns),
})
print(f"[*] Templates analyzed: {len(templates)}, ESC1 vulnerable: {len(report['findings'])}")
if args.certipy and args.domain:
certipy_results = run_certipy_find(
args.domain, args.username or "", args.password or "", args.dc_ip or ""
)
report["findings"].extend(certipy_results)
print(f"[*] Certipy findings: {len(certipy_results)}")
report["risk_level"] = "CRITICAL" if report["findings"] else "LOW"
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(f"[*] Report saved to {args.output}")
else:
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()