mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-17 21:19:40 +03:00
Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills: - scripts/agent.py: 80-150 line Python agents using real libraries (impacket, boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.) - references/api-reference.md: real API documentation with method signatures - LICENSE: MIT license for all skill folders
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anthropic Agent Skills Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,67 @@
|
||||
# API Reference: Threat Actor Profiling Agent
|
||||
|
||||
## Overview
|
||||
|
||||
Builds threat actor profiles from MITRE ATT&CK STIX data using the stix2 MemoryStore. Queries intrusion-set objects for TTPs, software, and relationships, enabling group comparison and tactic mapping.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| stix2 | >= 3.0 | STIX 2.1 object store and filtering |
|
||||
| requests | >= 2.28 | ATT&CK STIX data download |
|
||||
|
||||
## Data Source
|
||||
|
||||
MITRE ATT&CK Enterprise STIX bundle from `https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json`. Cached locally at `/tmp/enterprise-attack.json`.
|
||||
|
||||
## Core Functions
|
||||
|
||||
### `load_attack_data(cache_path)`
|
||||
Downloads and caches ATT&CK STIX data into a stix2 MemoryStore.
|
||||
- **Returns**: `MemoryStore` instance
|
||||
|
||||
### `list_threat_groups(src)`
|
||||
Lists all intrusion-set objects with name, aliases, and description.
|
||||
- **Returns**: `list[dict]` sorted by name
|
||||
|
||||
### `get_group_profile(src, group_name)`
|
||||
Full profile: description, aliases, techniques with ATT&CK IDs, software (malware/tools), external references.
|
||||
- **Search**: Exact match on name, then fuzzy match on name and aliases
|
||||
- **Returns**: `dict` with techniques, software, references
|
||||
|
||||
### `get_group_techniques_by_tactic(src, group_name)`
|
||||
Organizes a group's techniques by ATT&CK tactic (kill chain phase).
|
||||
- **Returns**: `dict` with tactics mapped to technique lists
|
||||
|
||||
### `compare_groups(src, group_names)`
|
||||
Compares multiple groups: shared techniques, technique counts, software counts.
|
||||
- **Returns**: `dict` with `shared_techniques` and per-group statistics
|
||||
|
||||
## STIX Object Types Queried
|
||||
|
||||
| Type | ATT&CK Concept |
|
||||
|------|----------------|
|
||||
| intrusion-set | Threat actor group |
|
||||
| attack-pattern | ATT&CK technique |
|
||||
| malware | Malware family |
|
||||
| tool | Legitimate tool used by attacker |
|
||||
| relationship | Links between groups, techniques, software |
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python agent.py APT29
|
||||
python agent.py "Lazarus Group"
|
||||
```
|
||||
|
||||
## Example Output Fields
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "APT29",
|
||||
"aliases": ["NOBELIUM", "Cozy Bear", "The Dukes"],
|
||||
"techniques": [{"name": "Phishing", "technique_id": "T1566"}],
|
||||
"software": [{"name": "Cobalt Strike", "type": "tool"}]
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Threat actor profiling agent using MITRE ATT&CK STIX data and STIX2 library."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
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)
|
||||
Reference in New Issue
Block a user