Files
Anthropic-Cybersecurity-Skills/skills/executing-red-team-exercise/scripts/agent.py
T
mukul975 c47eed6a64 Production hardening: security fixes, code quality, 724 skills complete
- 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
2026-03-19 13:26:49 +01:00

172 lines
6.3 KiB
Python

#!/usr/bin/env python3
# For authorized testing in lab/CTF environments only
"""Red team exercise planning and ATT&CK technique tracking agent."""
import argparse
import json
import logging
from datetime import datetime
from dataclasses import dataclass, field, asdict
from typing import List
try:
import requests
except ImportError:
import sys; sys.exit("requests is required: pip install requests")
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
MITRE_ATTACK_URL = "https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json"
@dataclass
class TechniqueExecution:
technique_id: str
technique_name: str
tactic: str
timestamp: str = ""
status: str = "planned"
detected: bool = False
detection_time: str = ""
notes: str = ""
@dataclass
class RedTeamOperation:
operation_name: str
target_org: str
emulated_actor: str
start_date: str
objectives: List[str] = field(default_factory=list)
techniques: List[TechniqueExecution] = field(default_factory=list)
def load_attack_techniques(cache_file: str = "attack_enterprise.json") -> dict:
"""Load MITRE ATT&CK Enterprise techniques from local cache or upstream."""
import os
if os.path.exists(cache_file):
with open(cache_file) as f:
return json.load(f)
logger.info("Downloading ATT&CK Enterprise data...")
resp = requests.get(MITRE_ATTACK_URL, timeout=60)
resp.raise_for_status()
data = resp.json()
with open(cache_file, "w") as f:
json.dump(data, f)
return data
def get_actor_techniques(attack_data: dict, actor_name: str) -> List[dict]:
"""Extract techniques used by a specific threat actor from ATT&CK data."""
actor_id = None
for obj in attack_data.get("objects", []):
if obj.get("type") == "intrusion-set" and actor_name.lower() in obj.get("name", "").lower():
actor_id = obj["id"]
break
if not actor_id:
logger.warning("Actor '%s' not found in ATT&CK data", actor_name)
return []
technique_refs = set()
for obj in attack_data.get("objects", []):
if obj.get("type") == "relationship" and obj.get("source_ref") == actor_id:
if obj.get("relationship_type") == "uses":
technique_refs.add(obj["target_ref"])
techniques = []
for obj in attack_data.get("objects", []):
if obj.get("id") in technique_refs and obj.get("type") == "attack-pattern":
ext_refs = obj.get("external_references", [])
tech_id = next((r["external_id"] for r in ext_refs if r.get("source_name") == "mitre-attack"), "")
kill_chain = obj.get("kill_chain_phases", [{}])
tactic = kill_chain[0].get("phase_name", "") if kill_chain else ""
techniques.append({"id": tech_id, "name": obj["name"], "tactic": tactic})
logger.info("Found %d techniques for actor '%s'", len(techniques), actor_name)
return techniques
def build_operation_plan(actor_name: str, target: str, objectives: List[str],
attack_data: dict) -> RedTeamOperation:
"""Create a red team operation plan based on emulated threat actor TTPs."""
techniques = get_actor_techniques(attack_data, actor_name)
executions = [
TechniqueExecution(
technique_id=t["id"], technique_name=t["name"],
tactic=t["tactic"], status="planned",
)
for t in techniques
]
return RedTeamOperation(
operation_name=f"{actor_name} Emulation - {target}",
target_org=target, emulated_actor=actor_name,
start_date=datetime.utcnow().isoformat(),
objectives=objectives, techniques=executions,
)
def log_technique_execution(op: RedTeamOperation, technique_id: str,
detected: bool = False, notes: str = "") -> None:
"""Mark a technique as executed and record detection status."""
for tech in op.techniques:
if tech.technique_id == technique_id:
tech.status = "executed"
tech.timestamp = datetime.utcnow().isoformat()
tech.detected = detected
if detected:
tech.detection_time = datetime.utcnow().isoformat()
tech.notes = notes
logger.info("Technique %s executed (detected=%s)", technique_id, detected)
return
logger.warning("Technique %s not found in operation plan", technique_id)
def generate_detection_gap_report(op: RedTeamOperation) -> dict:
"""Produce a detection gap analysis comparing executed vs detected techniques."""
executed = [t for t in op.techniques if t.status == "executed"]
detected = [t for t in executed if t.detected]
missed = [t for t in executed if not t.detected]
return {
"operation": op.operation_name,
"emulated_actor": op.emulated_actor,
"total_techniques_planned": len(op.techniques),
"techniques_executed": len(executed),
"techniques_detected": len(detected),
"techniques_missed": len(missed),
"detection_rate": f"{len(detected)/len(executed)*100:.1f}%" if executed else "N/A",
"detected_list": [asdict(t) for t in detected],
"missed_list": [asdict(t) for t in missed],
"recommendations": [
f"Improve detection for {t.technique_id} ({t.technique_name})"
for t in missed
],
}
def main():
parser = argparse.ArgumentParser(description="Red Team Exercise Agent")
parser.add_argument("--actor", required=True, help="Threat actor to emulate (e.g., APT29)")
parser.add_argument("--target", required=True, help="Target organization name")
parser.add_argument("--objectives", nargs="+", default=["Demonstrate domain compromise"])
parser.add_argument("--output", default="redteam_plan.json")
args = parser.parse_args()
attack_data = load_attack_techniques()
op = build_operation_plan(args.actor, args.target, args.objectives, attack_data)
report = {
"operation": asdict(op),
"technique_count": len(op.techniques),
"tactics_covered": list(set(t.tactic for t in op.techniques if t.tactic)),
}
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
logger.info("Operation plan saved to %s", args.output)
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()