Files
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

181 lines
6.9 KiB
Python

#!/usr/bin/env python3
"""Threat actor profiling agent using MITRE ATT&CK STIX data and STIX2 library."""
import json
import sys
import os
try:
from stix2 import MemoryStore, Filter
import requests
except ImportError:
print("Install: pip install stix2 requests")
sys.exit(1)
ATTACK_STIX_URL = "https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json"
def load_attack_data(cache_path="/tmp/enterprise-attack.json"):
"""Load MITRE ATT&CK STIX data from cache or download."""
if os.path.exists(cache_path):
with open(cache_path, "r") as f:
data = json.load(f)
else:
resp = requests.get(ATTACK_STIX_URL, timeout=60)
resp.raise_for_status()
data = resp.json()
with open(cache_path, "w") as f:
json.dump(data, f)
return MemoryStore(stix_data=data["objects"])
def list_threat_groups(src):
"""List all threat actor groups in ATT&CK."""
groups = src.query([Filter("type", "=", "intrusion-set")])
result = []
for g in groups:
aliases = getattr(g, "aliases", [])
result.append({
"id": g.id,
"name": g.name,
"aliases": aliases if aliases else [],
"description": (g.description[:200] + "...") if hasattr(g, "description") and g.description else "",
"created": str(g.created),
"modified": str(g.modified),
})
return sorted(result, key=lambda x: x["name"])
def get_group_profile(src, group_name):
"""Build a comprehensive profile for a specific threat actor group."""
groups = src.query([
Filter("type", "=", "intrusion-set"),
Filter("name", "=", group_name),
])
if not groups:
groups = src.query([Filter("type", "=", "intrusion-set")])
groups = [g for g in groups if group_name.lower() in g.name.lower()
or any(group_name.lower() in a.lower() for a in getattr(g, "aliases", []))]
if not groups:
return {"error": f"Group '{group_name}' not found"}
group = groups[0]
profile = {
"name": group.name,
"id": group.id,
"aliases": getattr(group, "aliases", []),
"description": getattr(group, "description", ""),
"created": str(group.created),
"modified": str(group.modified),
"external_references": [],
}
for ref in getattr(group, "external_references", []):
if hasattr(ref, "source_name"):
profile["external_references"].append({
"source": ref.source_name,
"url": getattr(ref, "url", ""),
"external_id": getattr(ref, "external_id", ""),
})
relationships = src.query([
Filter("type", "=", "relationship"),
Filter("source_ref", "=", group.id),
])
profile["techniques"] = []
profile["software"] = []
for rel in relationships:
target = src.get(rel.target_ref)
if target:
if target.type == "attack-pattern":
technique = {
"name": target.name,
"technique_id": "",
"description": rel.description[:200] if hasattr(rel, "description") and rel.description else "",
}
for ref in getattr(target, "external_references", []):
if hasattr(ref, "external_id") and ref.external_id.startswith("T"):
technique["technique_id"] = ref.external_id
profile["techniques"].append(technique)
elif target.type in ("malware", "tool"):
profile["software"].append({
"name": target.name,
"type": target.type,
"description": (target.description[:200] + "...") if hasattr(target, "description") and target.description else "",
})
return profile
def get_group_techniques_by_tactic(src, group_name):
"""Map a group's techniques organized by ATT&CK tactic."""
profile = get_group_profile(src, group_name)
if "error" in profile:
return profile
tactic_map = {}
techniques = src.query([Filter("type", "=", "attack-pattern")])
tech_lookup = {}
for t in techniques:
for ref in getattr(t, "external_references", []):
if hasattr(ref, "external_id") and ref.external_id.startswith("T"):
tech_lookup[t.name] = {
"id": ref.external_id,
"tactics": [p["phase_name"] for p in getattr(t, "kill_chain_phases", [])],
}
for tech in profile["techniques"]:
info = tech_lookup.get(tech["name"], {})
for tactic in info.get("tactics", ["unknown"]):
tactic_map.setdefault(tactic, []).append({
"technique": tech["name"],
"id": info.get("id", tech.get("technique_id", "")),
})
return {"group": group_name, "tactics": tactic_map}
def compare_groups(src, group_names):
"""Compare techniques and tools across multiple threat actor groups."""
profiles = {}
for name in group_names:
p = get_group_profile(src, name)
if "error" not in p:
profiles[name] = p
all_techniques = {}
for name, profile in profiles.items():
for tech in profile["techniques"]:
tech_name = tech["name"]
all_techniques.setdefault(tech_name, set()).add(name)
shared = {t: list(g) for t, g in all_techniques.items() if len(g) > 1}
return {
"groups": list(profiles.keys()),
"shared_techniques": shared,
"technique_counts": {n: len(p["techniques"]) for n, p in profiles.items()},
"software_counts": {n: len(p["software"]) for n, p in profiles.items()},
}
def print_profile(profile):
print(f"Threat Actor Profile: {profile['name']}")
print("=" * 50)
if profile.get("aliases"):
print(f"Aliases: {', '.join(profile['aliases'])}")
print(f"\nDescription:\n{profile.get('description', '')[:500]}")
print(f"\nTechniques ({len(profile.get('techniques', []))}):")
for t in profile.get("techniques", [])[:20]:
print(f" [{t.get('technique_id', 'N/A'):8s}] {t['name']}")
print(f"\nSoftware ({len(profile.get('software', []))}):")
for s in profile.get("software", []):
print(f" [{s['type']:7s}] {s['name']}")
print(f"\nReferences:")
for r in profile.get("external_references", [])[:5]:
print(f" {r['source']}: {r.get('url', r.get('external_id', ''))}")
if __name__ == "__main__":
group_name = sys.argv[1] if len(sys.argv) > 1 else "APT29"
print("Loading MITRE ATT&CK data...")
src = load_attack_data()
profile = get_group_profile(src, group_name)
if "error" in profile:
print(profile["error"])
print("\nAvailable groups:")
for g in list_threat_groups(src)[:20]:
print(f" {g['name']}: {', '.join(g['aliases'][:3])}")
else:
print_profile(profile)