mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 05:34:55 +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
147 lines
5.8 KiB
Python
147 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Breach and Attack Simulation (BAS) agent for continuous security validation using MITRE ATT&CK."""
|
|
|
|
import argparse
|
|
import json
|
|
import logging
|
|
import os
|
|
import sys
|
|
from datetime import datetime
|
|
from typing import List
|
|
|
|
try:
|
|
import requests
|
|
except ImportError:
|
|
sys.exit("requests required: pip install requests")
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
|
logger = logging.getLogger(__name__)
|
|
|
|
ATTACK_TECHNIQUES = [
|
|
{"id": "T1566.001", "name": "Spearphishing Attachment", "tactic": "Initial Access",
|
|
"test_type": "email", "payload": "eicar_test_attachment"},
|
|
{"id": "T1059.001", "name": "PowerShell", "tactic": "Execution",
|
|
"test_type": "endpoint", "payload": "benign_ps_download_cradle"},
|
|
{"id": "T1003.001", "name": "LSASS Memory", "tactic": "Credential Access",
|
|
"test_type": "endpoint", "payload": "procdump_lsass_simulation"},
|
|
{"id": "T1021.002", "name": "SMB/Windows Admin Shares", "tactic": "Lateral Movement",
|
|
"test_type": "network", "payload": "smb_admin_share_access"},
|
|
{"id": "T1486", "name": "Data Encrypted for Impact", "tactic": "Impact",
|
|
"test_type": "endpoint", "payload": "benign_file_encryption"},
|
|
{"id": "T1071.001", "name": "Web Protocols", "tactic": "Command and Control",
|
|
"test_type": "network", "payload": "http_c2_beacon_simulation"},
|
|
{"id": "T1048.003", "name": "Exfiltration Over Unencrypted Protocol", "tactic": "Exfiltration",
|
|
"test_type": "network", "payload": "dns_exfil_simulation"},
|
|
]
|
|
|
|
|
|
def simulate_technique(technique: dict, target: str) -> dict:
|
|
"""Simulate a single ATT&CK technique and record detection status."""
|
|
start_time = datetime.utcnow().isoformat()
|
|
detected = False
|
|
blocked = False
|
|
alert_id = ""
|
|
try:
|
|
if technique["test_type"] == "network":
|
|
resp = requests.get(f"http://{target}/health", timeout=5)
|
|
detected = resp.status_code != 200
|
|
elif technique["test_type"] == "email":
|
|
detected = False
|
|
elif technique["test_type"] == "endpoint":
|
|
detected = False
|
|
except requests.RequestException:
|
|
blocked = True
|
|
detected = True
|
|
return {
|
|
"technique_id": technique["id"],
|
|
"technique_name": technique["name"],
|
|
"tactic": technique["tactic"],
|
|
"test_type": technique["test_type"],
|
|
"start_time": start_time,
|
|
"detected": detected,
|
|
"blocked": blocked,
|
|
"alert_generated": alert_id,
|
|
}
|
|
|
|
|
|
def check_siem_detection(siem_url: str, api_key: str, technique_id: str,
|
|
time_window_minutes: int = 15) -> dict:
|
|
"""Check if SIEM generated an alert for the simulated technique."""
|
|
try:
|
|
resp = requests.get(
|
|
f"{siem_url}/api/alerts",
|
|
headers={"Authorization": f"Bearer {api_key}"},
|
|
params={"technique": technique_id, "minutes": time_window_minutes},
|
|
timeout=15)
|
|
if resp.status_code == 200:
|
|
alerts = resp.json().get("alerts", [])
|
|
return {"detected": len(alerts) > 0, "alert_count": len(alerts)}
|
|
except requests.RequestException:
|
|
pass
|
|
return {"detected": False, "alert_count": 0}
|
|
|
|
|
|
def compute_detection_coverage(results: List[dict]) -> dict:
|
|
"""Compute detection coverage across tested techniques."""
|
|
total = len(results)
|
|
detected = sum(1 for r in results if r["detected"])
|
|
blocked = sum(1 for r in results if r["blocked"])
|
|
by_tactic = {}
|
|
for r in results:
|
|
tactic = r["tactic"]
|
|
if tactic not in by_tactic:
|
|
by_tactic[tactic] = {"total": 0, "detected": 0}
|
|
by_tactic[tactic]["total"] += 1
|
|
if r["detected"]:
|
|
by_tactic[tactic]["detected"] += 1
|
|
return {
|
|
"total_tests": total,
|
|
"detected": detected,
|
|
"blocked": blocked,
|
|
"missed": total - detected,
|
|
"detection_rate_pct": round(detected / total * 100, 1) if total else 0,
|
|
"by_tactic": by_tactic,
|
|
}
|
|
|
|
|
|
def generate_report(target: str, siem_url: str = "", siem_key: str = "") -> dict:
|
|
"""Run BAS simulation campaign and generate detection gap report."""
|
|
report = {"analysis_date": datetime.utcnow().isoformat(), "target": target, "results": []}
|
|
for technique in ATTACK_TECHNIQUES:
|
|
result = simulate_technique(technique, target)
|
|
if siem_url and siem_key:
|
|
siem_check = check_siem_detection(siem_url, siem_key, technique["id"])
|
|
result["siem_detection"] = siem_check
|
|
if siem_check["detected"]:
|
|
result["detected"] = True
|
|
report["results"].append(result)
|
|
report["coverage"] = compute_detection_coverage(report["results"])
|
|
report["gaps"] = [r for r in report["results"] if not r["detected"]]
|
|
report["recommendations"] = []
|
|
for gap in report["gaps"]:
|
|
report["recommendations"].append(
|
|
f"Create detection rule for {gap['technique_id']} ({gap['technique_name']})")
|
|
return report
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Breach and Attack Simulation Agent")
|
|
parser.add_argument("--target", required=True, help="Target host for simulation")
|
|
parser.add_argument("--siem-url", default="", help="SIEM API URL for detection validation")
|
|
parser.add_argument("--siem-key", default="", help="SIEM API key")
|
|
parser.add_argument("--output-dir", default=".")
|
|
parser.add_argument("--output", default="bas_report.json")
|
|
args = parser.parse_args()
|
|
|
|
os.makedirs(args.output_dir, exist_ok=True)
|
|
report = generate_report(args.target, args.siem_url, args.siem_key)
|
|
out_path = os.path.join(args.output_dir, args.output)
|
|
with open(out_path, "w") as f:
|
|
json.dump(report, f, indent=2)
|
|
logger.info("Report saved to %s", out_path)
|
|
print(json.dumps(report["coverage"], indent=2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|