mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 21:54:56 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
179 lines
6.8 KiB
Python
179 lines
6.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for monitoring and managing Microsoft Defender for Cloud security posture."""
|
|
|
|
import subprocess
|
|
import json
|
|
import argparse
|
|
from datetime import datetime
|
|
|
|
|
|
def run_az_command(args_list):
|
|
"""Execute an Azure CLI command and return parsed JSON output."""
|
|
cmd = ["az"] + args_list + ["--output", "json"]
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
|
if result.returncode != 0:
|
|
print(f" [-] Error: {result.stderr.strip()}")
|
|
return None
|
|
return json.loads(result.stdout) if result.stdout.strip() else None
|
|
except (subprocess.TimeoutExpired, json.JSONDecodeError) as e:
|
|
print(f" [-] Command failed: {e}")
|
|
return None
|
|
|
|
|
|
def get_defender_plans():
|
|
"""List all Defender for Cloud pricing plans and their status."""
|
|
print("[*] Checking Defender for Cloud plan status...")
|
|
plans = run_az_command(["security", "pricing", "list"])
|
|
if not plans:
|
|
return []
|
|
enabled = []
|
|
for plan in plans:
|
|
tier = plan.get("pricingTier", "Free")
|
|
name = plan.get("name", "Unknown")
|
|
sub_plan = plan.get("subPlan", "")
|
|
status = "ENABLED" if tier == "Standard" else "FREE"
|
|
indicator = "[+]" if tier == "Standard" else "[-]"
|
|
sub_info = f" ({sub_plan})" if sub_plan else ""
|
|
print(f" {indicator} {name}: {status}{sub_info}")
|
|
if tier == "Standard":
|
|
enabled.append({"name": name, "tier": tier, "subPlan": sub_plan})
|
|
print(f"[*] {len(enabled)} plans enabled out of {len(plans)} total")
|
|
return enabled
|
|
|
|
|
|
def get_secure_score():
|
|
"""Retrieve the current Secure Score across subscriptions."""
|
|
print("\n[*] Fetching Secure Score...")
|
|
scores = run_az_command(["security", "secure-score", "list"])
|
|
if not scores:
|
|
return {}
|
|
for score in scores:
|
|
current = score.get("current", 0)
|
|
maximum = score.get("max", 0)
|
|
pct = round((current / maximum * 100), 1) if maximum > 0 else 0
|
|
print(f" Score: {current}/{maximum} ({pct}%)")
|
|
return scores
|
|
|
|
|
|
def get_security_assessments(severity_filter=None):
|
|
"""List security assessments and their health status."""
|
|
print("\n[*] Fetching security assessments...")
|
|
assessments = run_az_command(["security", "assessment", "list"])
|
|
if not assessments:
|
|
return []
|
|
unhealthy = []
|
|
for a in assessments:
|
|
props = a.get("properties", {})
|
|
status = props.get("status", {}).get("code", "")
|
|
if status == "Unhealthy":
|
|
sev = props.get("metadata", {}).get("severity", "Unknown")
|
|
display = props.get("displayName", "Unknown")
|
|
if severity_filter and sev.lower() != severity_filter.lower():
|
|
continue
|
|
unhealthy.append({"name": display, "severity": sev, "status": status})
|
|
print(f" [{sev.upper()}] {display}")
|
|
print(f"[*] {len(unhealthy)} unhealthy assessments found")
|
|
return unhealthy
|
|
|
|
|
|
def get_security_alerts(days=7):
|
|
"""Retrieve recent security alerts from Defender for Cloud."""
|
|
print(f"\n[*] Fetching security alerts (last {days} days)...")
|
|
alerts = run_az_command(["security", "alert", "list"])
|
|
if not alerts:
|
|
return []
|
|
severity_counts = {"High": 0, "Medium": 0, "Low": 0, "Informational": 0}
|
|
active_alerts = []
|
|
for alert in alerts:
|
|
props = alert.get("properties", {})
|
|
status = props.get("status", "")
|
|
if status in ("Active", "InProgress"):
|
|
sev = props.get("severity", "Unknown")
|
|
severity_counts[sev] = severity_counts.get(sev, 0) + 1
|
|
active_alerts.append({
|
|
"name": props.get("alertDisplayName", "Unknown"),
|
|
"severity": sev,
|
|
"status": status,
|
|
"timestamp": props.get("timeGeneratedUtc", ""),
|
|
})
|
|
for sev, count in severity_counts.items():
|
|
if count > 0:
|
|
print(f" [{sev}] {count} alerts")
|
|
return active_alerts
|
|
|
|
|
|
def check_security_contacts():
|
|
"""Verify security contact configuration for alert notifications."""
|
|
print("\n[*] Checking security contact configuration...")
|
|
contacts = run_az_command(["security", "contact", "list"])
|
|
if not contacts:
|
|
print(" [!] No security contacts configured")
|
|
return False
|
|
for contact in contacts:
|
|
email = contact.get("email", "Not set")
|
|
alerts = contact.get("alertNotifications", "off")
|
|
print(f" Email: {email} | Alert notifications: {alerts}")
|
|
return True
|
|
|
|
|
|
def check_auto_provisioning():
|
|
"""Check auto-provisioning settings for security agents."""
|
|
print("\n[*] Checking auto-provisioning settings...")
|
|
settings = run_az_command(["security", "auto-provisioning-setting", "list"])
|
|
if not settings:
|
|
return []
|
|
for s in settings:
|
|
name = s.get("name", "Unknown")
|
|
auto_prov = s.get("autoProvision", "Off")
|
|
indicator = "[+]" if auto_prov == "On" else "[-]"
|
|
print(f" {indicator} {name}: {auto_prov}")
|
|
return settings
|
|
|
|
|
|
def generate_posture_report(output_path):
|
|
"""Generate a comprehensive security posture report."""
|
|
print("[*] Generating security posture report...")
|
|
report = {
|
|
"report_date": datetime.now().isoformat(),
|
|
"defender_plans": get_defender_plans(),
|
|
"secure_score": get_secure_score(),
|
|
"unhealthy_assessments": get_security_assessments(),
|
|
"active_alerts": get_security_alerts(),
|
|
"contacts_configured": check_security_contacts(),
|
|
"auto_provisioning": check_auto_provisioning(),
|
|
}
|
|
with open(output_path, "w") as f:
|
|
json.dump(report, f, indent=2, default=str)
|
|
print(f"\n[*] Report saved to {output_path}")
|
|
return report
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Microsoft Defender for Cloud Security Agent")
|
|
parser.add_argument("action", choices=["plans", "score", "assessments", "alerts",
|
|
"contacts", "auto-provision", "full-report"])
|
|
parser.add_argument("--severity", choices=["high", "medium", "low"], help="Filter by severity")
|
|
parser.add_argument("--days", type=int, default=7, help="Alert lookback in days")
|
|
parser.add_argument("-o", "--output", default="defender_report.json")
|
|
args = parser.parse_args()
|
|
|
|
if args.action == "plans":
|
|
get_defender_plans()
|
|
elif args.action == "score":
|
|
get_secure_score()
|
|
elif args.action == "assessments":
|
|
get_security_assessments(args.severity)
|
|
elif args.action == "alerts":
|
|
get_security_alerts(args.days)
|
|
elif args.action == "contacts":
|
|
check_security_contacts()
|
|
elif args.action == "auto-provision":
|
|
check_auto_provisioning()
|
|
elif args.action == "full-report":
|
|
generate_posture_report(args.output)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|