mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-10 21:24:56 +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
161 lines
6.4 KiB
Python
161 lines
6.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for auditing and managing BitLocker disk encryption across endpoints."""
|
|
|
|
import json
|
|
import argparse
|
|
import subprocess
|
|
import re
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
|
|
def get_bitlocker_status():
|
|
"""Get BitLocker status on local machine via manage-bde."""
|
|
try:
|
|
result = subprocess.run(
|
|
["manage-bde", "-status"], capture_output=True, text=True, timeout=30)
|
|
volumes = []
|
|
current = {}
|
|
for line in result.stdout.splitlines():
|
|
line = line.strip()
|
|
if line.startswith("Volume"):
|
|
if current:
|
|
volumes.append(current)
|
|
current = {"volume": line}
|
|
elif ":" in line:
|
|
key, _, value = line.partition(":")
|
|
current[key.strip()] = value.strip()
|
|
if current:
|
|
volumes.append(current)
|
|
return volumes
|
|
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
return []
|
|
|
|
|
|
def parse_bitlocker_report(report_path):
|
|
"""Parse BitLocker compliance report (CSV or JSON)."""
|
|
entries = []
|
|
if report_path.endswith(".json"):
|
|
with open(report_path) as f:
|
|
entries = json.load(f)
|
|
else:
|
|
import csv
|
|
with open(report_path, newline="", encoding="utf-8-sig") as f:
|
|
entries = list(csv.DictReader(f))
|
|
return entries
|
|
|
|
|
|
def audit_bitlocker_compliance(devices):
|
|
"""Audit BitLocker compliance across fleet."""
|
|
findings = []
|
|
for device in devices:
|
|
hostname = device.get("hostname", device.get("ComputerName", ""))
|
|
protection = device.get("protection_status", device.get("ProtectionStatus", ""))
|
|
encryption = device.get("encryption_method", device.get("EncryptionMethod", ""))
|
|
key_protector = device.get("key_protector", device.get("KeyProtector", ""))
|
|
recovery_key = device.get("recovery_key_escrowed",
|
|
device.get("RecoveryKeyEscrowed", ""))
|
|
if "off" in str(protection).lower() or protection == "0":
|
|
findings.append({
|
|
"hostname": hostname, "issue": "bitlocker_disabled",
|
|
"severity": "CRITICAL",
|
|
})
|
|
if encryption and "aes" not in str(encryption).lower():
|
|
findings.append({
|
|
"hostname": hostname, "issue": "weak_encryption_method",
|
|
"value": encryption, "severity": "HIGH",
|
|
})
|
|
if "128" in str(encryption):
|
|
findings.append({
|
|
"hostname": hostname, "issue": "aes_128_not_256",
|
|
"severity": "MEDIUM",
|
|
"recommendation": "Upgrade to AES-256",
|
|
})
|
|
if not key_protector or "tpm" not in str(key_protector).lower():
|
|
findings.append({
|
|
"hostname": hostname, "issue": "no_tpm_protector",
|
|
"severity": "HIGH",
|
|
})
|
|
if str(recovery_key).lower() in ("no", "false", "0", ""):
|
|
findings.append({
|
|
"hostname": hostname, "issue": "recovery_key_not_escrowed",
|
|
"severity": "HIGH",
|
|
"recommendation": "Escrow recovery key to Active Directory",
|
|
})
|
|
return findings
|
|
|
|
|
|
def generate_gpo_recommendations():
|
|
"""Generate Group Policy recommendations for BitLocker."""
|
|
return {
|
|
"Computer Configuration": {
|
|
"path": "Administrative Templates > Windows Components > BitLocker Drive Encryption",
|
|
"settings": [
|
|
{"name": "Choose drive encryption method (OS)",
|
|
"value": "AES-256", "policy": "Enabled"},
|
|
{"name": "Require additional authentication at startup",
|
|
"value": "Allow BitLocker without compatible TPM: Disabled",
|
|
"policy": "Enabled"},
|
|
{"name": "Choose how BitLocker-protected OS drives can be recovered",
|
|
"value": "Save to AD DS, Do not enable until stored",
|
|
"policy": "Enabled"},
|
|
{"name": "Enforce drive encryption type on OS drives",
|
|
"value": "Full encryption", "policy": "Enabled"},
|
|
],
|
|
},
|
|
}
|
|
|
|
|
|
def calculate_compliance_metrics(devices, findings):
|
|
"""Calculate fleet encryption compliance metrics."""
|
|
total = len(devices)
|
|
encrypted = total - sum(1 for f in findings if f["issue"] == "bitlocker_disabled")
|
|
strong_enc = encrypted - sum(1 for f in findings if f["issue"] in
|
|
("weak_encryption_method", "aes_128_not_256"))
|
|
escrowed = total - sum(1 for f in findings if f["issue"] == "recovery_key_not_escrowed")
|
|
return {
|
|
"total_devices": total,
|
|
"encrypted": encrypted,
|
|
"encryption_rate": round(encrypted / total * 100, 1) if total else 0,
|
|
"strong_encryption": strong_enc,
|
|
"recovery_keys_escrowed": escrowed,
|
|
"escrow_rate": round(escrowed / total * 100, 1) if total else 0,
|
|
}
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="BitLocker Disk Encryption Agent")
|
|
parser.add_argument("--report", help="BitLocker report CSV/JSON")
|
|
parser.add_argument("--local", action="store_true", help="Check local machine")
|
|
parser.add_argument("--output", default="bitlocker_audit_report.json")
|
|
parser.add_argument("--action", choices=["audit", "local", "gpo", "full"], default="full")
|
|
args = parser.parse_args()
|
|
|
|
report = {"generated_at": datetime.utcnow().isoformat(), "findings": {}}
|
|
|
|
if args.action in ("local", "full") and args.local:
|
|
status = get_bitlocker_status()
|
|
report["findings"]["local_status"] = status
|
|
print(f"[+] Local volumes: {len(status)}")
|
|
|
|
if args.action in ("audit", "full") and args.report:
|
|
devices = parse_bitlocker_report(args.report)
|
|
findings = audit_bitlocker_compliance(devices)
|
|
metrics = calculate_compliance_metrics(devices, findings)
|
|
report["findings"]["compliance_audit"] = findings
|
|
report["findings"]["metrics"] = metrics
|
|
print(f"[+] Devices: {metrics['total_devices']}, Encrypted: {metrics['encryption_rate']}%")
|
|
|
|
if args.action in ("gpo", "full"):
|
|
gpo = generate_gpo_recommendations()
|
|
report["findings"]["gpo_recommendations"] = gpo
|
|
print("[+] GPO recommendations generated")
|
|
|
|
with open(args.output, "w") as f:
|
|
json.dump(report, f, indent=2, default=str)
|
|
print(f"[+] Report saved to {args.output}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|