mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-19 05:59:40 +03:00
c21af3347e
- 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
131 lines
4.7 KiB
Python
131 lines
4.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for detecting noPac (CVE-2021-42278/42287) AD privilege escalation vulnerability."""
|
|
|
|
import argparse
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
|
|
|
|
def check_nopac_impacket(domain, username, password, dc_ip):
|
|
"""Check for noPac vulnerability using Impacket noPac.py."""
|
|
cmd = [
|
|
"noPac.py", f"{domain}/{username}:{password}",
|
|
"-dc-ip", dc_ip, "--scan",
|
|
]
|
|
try:
|
|
result = subprocess.check_output(
|
|
cmd, text=True, errors="replace", timeout=30
|
|
)
|
|
return {
|
|
"method": "noPac.py",
|
|
"vulnerable": "VULNERABLE" in result.upper() or "success" in result.lower(),
|
|
"output": result[:1000],
|
|
}
|
|
except (subprocess.SubprocessError, FileNotFoundError):
|
|
return {"method": "noPac.py", "status": "tool not available"}
|
|
|
|
|
|
def check_machineaccountquota(domain, username, password, dc_ip):
|
|
"""Check the MachineAccountQuota via LDAP — needed for noPac."""
|
|
ps_cmd = (
|
|
"([ADSI]'LDAP://DC='+($env:USERDNSDOMAIN -replace '\\.',',DC=')).'ms-DS-MachineAccountQuota'"
|
|
)
|
|
try:
|
|
result = subprocess.check_output(
|
|
["powershell", "-NoProfile", "-Command", ps_cmd],
|
|
text=True, errors="replace", timeout=10
|
|
)
|
|
quota = int(result.strip()) if result.strip().isdigit() else -1
|
|
return {
|
|
"machine_account_quota": quota,
|
|
"exploitable": quota > 0,
|
|
"note": "Quota > 0 means any domain user can create machine accounts",
|
|
}
|
|
except (subprocess.SubprocessError, ValueError):
|
|
return {"machine_account_quota": "unknown"}
|
|
|
|
|
|
def check_patch_status():
|
|
"""Check if KB5008380 (noPac patch) is installed."""
|
|
if sys.platform != "win32":
|
|
return {"status": "non-windows"}
|
|
try:
|
|
result = subprocess.check_output(
|
|
["wmic", "qfe", "list", "brief"],
|
|
text=True, errors="replace", timeout=15
|
|
)
|
|
patched = any(kb in result for kb in ["KB5008380", "KB5008602", "KB5008207"])
|
|
return {
|
|
"patched": patched,
|
|
"relevant_kbs": ["KB5008380", "KB5008602", "KB5008207"],
|
|
}
|
|
except subprocess.SubprocessError:
|
|
return {"status": "check_failed"}
|
|
|
|
|
|
def enumerate_sam_name_impersonation():
|
|
"""Check for sAMAccountName impersonation conditions."""
|
|
ps_cmd = (
|
|
"Get-ADComputer -Filter * -Properties sAMAccountName | "
|
|
"Where-Object {$_.sAMAccountName -notmatch '\\$$'} | "
|
|
"Select-Object Name,sAMAccountName | ConvertTo-Json"
|
|
)
|
|
try:
|
|
result = subprocess.check_output(
|
|
["powershell", "-NoProfile", "-Command", ps_cmd],
|
|
text=True, errors="replace", timeout=15
|
|
)
|
|
data = json.loads(result) if result.strip() else []
|
|
return data if isinstance(data, list) else [data]
|
|
except (subprocess.SubprocessError, json.JSONDecodeError):
|
|
return []
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Detect noPac CVE-2021-42278/42287 vulnerability (authorized testing only)"
|
|
)
|
|
parser.add_argument("--domain", help="AD domain")
|
|
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("--check-patch", action="store_true")
|
|
parser.add_argument("--output", "-o", help="Output JSON report")
|
|
args = parser.parse_args()
|
|
|
|
print("[*] noPac (CVE-2021-42278/42287) Detection Agent")
|
|
print("[!] For authorized security testing only")
|
|
report = {"timestamp": datetime.now(timezone.utc).isoformat(), "findings": {}}
|
|
|
|
if args.domain and args.username:
|
|
nopac = check_nopac_impacket(
|
|
args.domain, args.username, args.password or "", args.dc_ip or ""
|
|
)
|
|
report["findings"]["nopac_scan"] = nopac
|
|
print(f"[*] noPac scan: {nopac.get('vulnerable', 'unknown')}")
|
|
|
|
quota = check_machineaccountquota(args.domain, args.username, args.password or "", args.dc_ip or "")
|
|
report["findings"]["machine_quota"] = quota
|
|
|
|
if args.check_patch:
|
|
patch = check_patch_status()
|
|
report["findings"]["patch_status"] = patch
|
|
print(f"[*] Patched: {patch.get('patched', 'unknown')}")
|
|
|
|
report["risk_level"] = "CRITICAL" if any(
|
|
v.get("vulnerable") or v.get("exploitable") for v in report["findings"].values() if isinstance(v, dict)
|
|
) 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()
|