mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-13 22:54:53 +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
174 lines
5.6 KiB
Python
174 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Threat intelligence collection agent using MISP/PyMISP.
|
|
|
|
Connects to MISP instances to collect, filter, and export threat intelligence
|
|
including events, attributes, and feeds via the PyMISP REST API client.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import datetime
|
|
|
|
try:
|
|
from pymisp import PyMISP
|
|
HAS_PYMISP = True
|
|
except ImportError:
|
|
HAS_PYMISP = False
|
|
|
|
|
|
def init_misp(url=None, key=None):
|
|
"""Initialize PyMISP client."""
|
|
url = url or os.environ.get("MISP_URL", "https://misp.example.org")
|
|
key = key or os.environ.get("MISP_API_KEY", "")
|
|
if not HAS_PYMISP:
|
|
return None
|
|
return PyMISP(url, key, ssl=True)
|
|
|
|
|
|
def search_events(misp, tags=None, date_from=None, published=True, limit=50):
|
|
"""Search MISP events by tags and date."""
|
|
if not misp:
|
|
return {"error": "PyMISP not available"}
|
|
kwargs = {"limit": limit, "published": published, "pythonify": True}
|
|
if tags:
|
|
kwargs["tags"] = tags
|
|
if date_from:
|
|
kwargs["date_from"] = date_from
|
|
try:
|
|
events = misp.search("events", **kwargs)
|
|
return [
|
|
{
|
|
"id": e.id,
|
|
"uuid": e.uuid,
|
|
"info": e.info,
|
|
"date": str(e.date),
|
|
"threat_level": {1: "High", 2: "Medium", 3: "Low", 4: "Undefined"}.get(e.threat_level_id, "?"),
|
|
"analysis": {0: "Initial", 1: "Ongoing", 2: "Complete"}.get(e.analysis, "?"),
|
|
"attribute_count": e.attribute_count,
|
|
"org": e.Orgc.name if hasattr(e, "Orgc") and e.Orgc else "",
|
|
"tags": [t.name for t in (e.tags or [])],
|
|
}
|
|
for e in events
|
|
]
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
|
|
def extract_attributes(misp, event_id, attr_type=None):
|
|
"""Extract attributes from a MISP event."""
|
|
if not misp:
|
|
return {"error": "PyMISP not available"}
|
|
try:
|
|
kwargs = {"eventid": event_id, "pythonify": True}
|
|
if attr_type:
|
|
kwargs["type_attribute"] = attr_type
|
|
attrs = misp.search("attributes", **kwargs)
|
|
return [
|
|
{
|
|
"type": a.type,
|
|
"value": a.value,
|
|
"category": a.category,
|
|
"to_ids": a.to_ids,
|
|
"comment": a.comment or "",
|
|
"timestamp": str(datetime.datetime.fromtimestamp(int(a.timestamp))),
|
|
}
|
|
for a in attrs
|
|
]
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
|
|
def collect_iocs_by_type(misp, ioc_types, date_from=None, limit=500):
|
|
"""Collect IOCs filtered by attribute type."""
|
|
if not misp:
|
|
return {"error": "PyMISP not available"}
|
|
results = {}
|
|
for ioc_type in ioc_types:
|
|
try:
|
|
kwargs = {"type_attribute": ioc_type, "to_ids": True, "pythonify": True, "limit": limit}
|
|
if date_from:
|
|
kwargs["date_from"] = date_from
|
|
attrs = misp.search("attributes", **kwargs)
|
|
results[ioc_type] = [
|
|
{"value": a.value, "event_id": a.event_id, "comment": a.comment or ""}
|
|
for a in attrs
|
|
]
|
|
except Exception as e:
|
|
results[ioc_type] = {"error": str(e)}
|
|
return results
|
|
|
|
|
|
def list_feeds(misp):
|
|
"""List configured MISP feeds."""
|
|
if not misp:
|
|
return {"error": "PyMISP not available"}
|
|
try:
|
|
feeds = misp.feeds()
|
|
return [
|
|
{
|
|
"id": f["Feed"]["id"],
|
|
"name": f["Feed"]["name"],
|
|
"provider": f["Feed"]["provider"],
|
|
"url": f["Feed"]["url"],
|
|
"enabled": f["Feed"]["enabled"],
|
|
"source_format": f["Feed"]["source_format"],
|
|
}
|
|
for f in feeds
|
|
]
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
|
|
def export_stix2(misp, event_id):
|
|
"""Export MISP event as STIX 2.1 bundle."""
|
|
if not misp:
|
|
return {"error": "PyMISP not available"}
|
|
try:
|
|
stix_data = misp.get_stix_event(event_id)
|
|
return stix_data
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
|
|
COMMON_IOC_TYPES = [
|
|
"ip-dst", "ip-src", "domain", "hostname", "url",
|
|
"md5", "sha1", "sha256", "email-src", "filename",
|
|
]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("=" * 60)
|
|
print("Threat Intelligence Collection with MISP")
|
|
print("PyMISP REST client, event search, attribute extraction, feeds")
|
|
print("=" * 60)
|
|
print(" PyMISP available: {}".format(HAS_PYMISP))
|
|
|
|
misp = init_misp() if HAS_PYMISP else None
|
|
|
|
if not misp:
|
|
print("\n[DEMO] No MISP connection. Showing IOC types and feed structure.")
|
|
print("\n--- Common IOC Types ---")
|
|
for t in COMMON_IOC_TYPES:
|
|
print(" - {}".format(t))
|
|
print("\n--- Usage ---")
|
|
print(" Set MISP_URL and MISP_API_KEY environment variables")
|
|
print(" python agent.py")
|
|
else:
|
|
print("\n[*] Searching recent events...")
|
|
events = search_events(misp, date_from="7d")
|
|
if isinstance(events, list):
|
|
print(" Found {} events".format(len(events)))
|
|
for e in events[:5]:
|
|
print(" [{}] {} ({} attrs)".format(e["id"], e["info"][:60], e["attribute_count"]))
|
|
else:
|
|
print(" Error: {}".format(events))
|
|
|
|
feeds = list_feeds(misp)
|
|
if isinstance(feeds, list):
|
|
print("\n--- Feeds ({}) ---".format(len(feeds)))
|
|
for f in feeds[:10]:
|
|
status = "enabled" if f["enabled"] else "disabled"
|
|
print(" [{}] {} ({})".format(f["id"], f["name"], status))
|
|
|
|
print("\n" + json.dumps({"pymisp_available": HAS_PYMISP}, indent=2))
|