npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
Overview
MISP (Malware Information Sharing Platform) is an open-source threat intelligence platform for gathering, sharing, storing, and correlating Indicators of Compromise (IOCs) of targeted attacks, threat intelligence, financial fraud information, vulnerability information, or counter-terrorism information. This skill covers deploying MISP, configuring threat feeds, using the PyMISP API for programmatic access, and building automated collection pipelines that aggregate IOCs from multiple community and commercial sources.
When to Use
- When managing security operations that require collecting threat intelligence with misp
- When improving security program maturity and operational processes
- When establishing standardized procedures for security team workflows
- When integrating threat intelligence or vulnerability data into operations
Prerequisites
- Python 3.9+ with
pymisplibrary installed - Docker and Docker Compose for MISP deployment
- Understanding of STIX 2.1 and TAXII 2.1 protocols
- Familiarity with IOC types: hashes, IP addresses, domains, URLs, email addresses
- Network access to MISP community feeds (circl.lu, botvrij.eu)
Key Concepts
MISP Architecture
MISP operates on an event-based model where threat intelligence is organized into events containing attributes (IOCs), objects (structured groupings of attributes), galaxies (threat actor/malware clusters linked to MITRE ATT&CK), and tags for classification. Synchronization between MISP instances uses a pull/push model over HTTPS with API key authentication.
Feed Types
- MISP Feeds: Native JSON/CSV feeds from MISP community (CIRCL OSINT, botvrij.eu)
- Freetext Feeds: Unstructured text feeds parsed for IOCs (abuse.ch, Feodo Tracker)
- TAXII Feeds: STIX/TAXII 2.1 compatible feeds from commercial and government sources
- CSV Feeds: Structured CSV feeds with configurable column mapping
PyMISP API
PyMISP is the official Python library to access MISP platforms via their REST API. It supports fetching events, adding/updating events and attributes, uploading samples, and searching across the entire MISP dataset. Authentication uses an API key passed in the Authorization header.
Workflow
Step 1: Deploy MISP with Docker
git clone https://github.com/MISP/misp-docker.git
cd misp-docker
cp template.env .env
# Edit .env to set MISP_BASEURL, MISP_ADMIN_EMAIL, MISP_ADMIN_PASSPHRASE
docker compose up -dStep 2: Configure Default Feeds
Enable built-in MISP feeds via the web UI or API:
from pymisp import PyMISP
misp = PyMISP('https://misp.local', 'YOUR_API_KEY', ssl=False)
# List available feeds
feeds = misp.feeds()
for feed in feeds:
print(f"{feed['Feed']['id']}: {feed['Feed']['name']} - Enabled: {feed['Feed']['enabled']}")
# Enable CIRCL OSINT Feed
misp.enable_feed(feed_id=1)
misp.cache_feed(feed_id=1)
misp.fetch_feed(feed_id=1)Step 3: Add Custom Threat Feeds
# Add abuse.ch URLhaus feed
feed_data = {
'name': 'URLhaus Recent URLs',
'provider': 'abuse.ch',
'url': 'https://urlhaus.abuse.ch/downloads/csv_recent/',
'source_format': 'csv',
'input_source': 'network',
'publish': False,
'enabled': True,
'headers': '',
'distribution': 0,
'sharing_group_id': 0,
'tag_id': 0,
'default': False,
'lookup_visible': True
}
result = misp.add_feed(feed_data)
print(f"Feed added: {result}")Step 4: Programmatic Event Search and Retrieval
from pymisp import PyMISP, MISPEvent
from datetime import datetime, timedelta
misp = PyMISP('https://misp.local', 'YOUR_API_KEY', ssl=False)
# Search for events from the last 7 days
result = misp.search(
controller='events',
date_from=(datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d'),
type_attribute='ip-dst',
to_ids=True,
pythonify=True
)
for event in result:
print(f"Event {event.id}: {event.info}")
for attr in event.attributes:
if attr.type == 'ip-dst' and attr.to_ids:
print(f" IOC: {attr.value} (category: {attr.category})")Step 5: Export IOCs for Downstream Tools
# Export as STIX 2.1 bundle
stix_output = misp.search(
controller='events',
return_format='stix2',
tags=['tlp:white'],
published=True
)
# Export IDS-flagged attributes as Suricata rules
suricata_rules = misp.search(
controller='attributes',
return_format='suricata',
to_ids=True,
type_attribute=['ip-dst', 'domain', 'url']
)
# Export as CSV for SIEM ingestion
csv_output = misp.search(
controller='attributes',
return_format='csv',
type_attribute='ip-dst',
to_ids=True
)Validation Criteria
- MISP instance is deployed and accessible via HTTPS
- At least 3 community feeds are enabled and fetching data successfully
- PyMISP script can authenticate, search events, and retrieve IOCs
- Events contain properly tagged and categorized attributes
- Export to STIX 2.1 produces valid STIX bundles
- Automated feed fetch runs on schedule (cron or MISP scheduler)
References
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md1.8 KB
API Reference: Collecting Threat Intelligence with MISP
PyMISP Installation
pip install pymispClient Initialization
from pymisp import PyMISP
misp = PyMISP(
url="https://misp.example.org",
key=os.environ["MISP_API_KEY"],
ssl=True
)Event Search
# By tags
events = misp.search("events", tags=["tlp:white", "type:OSINT"], pythonify=True)
# By date range
events = misp.search("events", date_from="2025-01-01", date_to="2025-01-31", pythonify=True)
# Published only
events = misp.search("events", published=True, limit=100, pythonify=True)Attribute Search
# By type
attrs = misp.search("attributes", type_attribute="ip-dst", to_ids=True, pythonify=True)
# By event
attrs = misp.search("attributes", eventid=42, pythonify=True)
# By value
attrs = misp.search("attributes", value="198.51.100.42", pythonify=True)REST API (curl)
# Search events
curl -X POST "https://misp/events/restSearch" \
-H "Authorization: $KEY" \
-H "Content-Type: application/json" \
-d '{"tags":["tlp:white"],"limit":50}'
# Get event
curl -H "Authorization: $KEY" "https://misp/events/view/42"
# STIX 2 export
curl -H "Authorization: $KEY" "https://misp/events/restSearch/stix2"Common Attribute Types
| Type | Category | Example |
|---|---|---|
| ip-dst | Network activity | 198.51.100.42 |
| domain | Network activity | evil.example.com |
| url | Network activity | https://evil.com/mal |
| sha256 | Payload delivery | a1b2c3... |
| md5 | Payload delivery | d41d8c... |
| email-src | Payload delivery | attacker@evil.com |
| filename | Payload delivery | malware.exe |
Feed Management
# List feeds
feeds = misp.feeds()
# Enable feed
misp.enable_feed(feed_id=1)
# Fetch and cache
misp.fetch_feed(feed_id=1)
misp.cache_feeds()standards.md2.3 KB
Standards and Frameworks Reference
MISP Standards
MISP Core Format
- MISP JSON Format: Native event format used for synchronization between instances
- MISP Galaxy: Cluster-based knowledge base linked to MITRE ATT&CK, threat actors, tools
- MISP Taxonomies: Machine-readable tagging schemes (TLP, PAP, admiralty-scale, OSINT)
- MISP Warninglists: Lists of well-known indicators to reduce false positives (Alexa Top 1M, Office 365 IPs)
STIX 2.1 (Structured Threat Information Expression)
- Standard language for representing cyber threat intelligence
- MISP supports import/export of STIX 2.1 bundles
- Object types: Indicator, Malware, Threat Actor, Attack Pattern, Campaign, Observed Data
- Relationship types: uses, targets, attributed-to, indicates, mitigates
TAXII 2.1 (Trusted Automated Exchange of Intelligence Information)
- Transport protocol for sharing CTI over HTTPS
- MISP can consume TAXII feeds and serve as a TAXII server
- Collection-based model: discovery, API root, collections, objects
- Supports pagination and filtering by added_after, type, version
MITRE ATT&CK Integration
- MISP Galaxy clusters map directly to ATT&CK techniques (T-codes)
- Events can be tagged with ATT&CK tactics: Initial Access, Execution, Persistence, etc.
- ATT&CK Navigator integration for visualizing technique coverage
- Sub-technique support (e.g., T1566.001 - Spearphishing Attachment)
Traffic Light Protocol (TLP)
- TLP:CLEAR (formerly TLP:WHITE): Unlimited disclosure
- TLP:GREEN: Limited disclosure within community
- TLP:AMBER: Limited disclosure within organization
- TLP:AMBER+STRICT: Restricted to organization only
- TLP:RED: Restricted to specific recipients only
Permissible Actions Protocol (PAP)
- PAP:RED: Only passive actions (no external lookups)
- PAP:AMBER: Active actions allowed but not against infrastructure
- PAP:GREEN: Active actions allowed
- PAP:CLEAR: Unlimited use
References
workflows.md4.8 KB
MISP Threat Intelligence Collection Workflows
Workflow 1: Automated Feed Collection Pipeline
[Community Feeds] --> [MISP Feed Manager] --> [Event Creation] --> [Correlation Engine]
| | | |
v v v v
- CIRCL OSINT - Schedule fetch - Auto-tag with - Deduplicate
- Botvrij.eu - Parse formats TLP/PAP - Cross-reference
- abuse.ch - Validate IOCs - Set distribution - Cluster similar
- PhishTank - Filter warninglists - Publish/unpublish eventsSteps:
- Feed Registration: Add feeds via UI or PyMISP API with source_format, URL, and headers
- Scheduled Fetch: Configure cron job or MISP scheduler to pull feeds at intervals
- Parsing and Validation: MISP parses feed content, validates IOC formats, checks against warninglists
- Event Generation: Each feed pull creates or updates events with parsed attributes
- Correlation: MISP correlates new attributes against existing data, identifying overlaps
- Distribution: Events are distributed based on TLP and sharing group configurations
Workflow 2: Manual Intelligence Collection
[Analyst Report] --> [Manual Event Creation] --> [Attribute Addition] --> [Enrichment]
|
v
[Galaxy Tagging]
|
v
[Publication]Steps:
- Event Creation: Create event with descriptive info, date, distribution, TLP tag
- IOC Entry: Add attributes (IP, domain, hash, URL) with correct category and type
- Object Construction: Group related attributes into MISP objects (file, domain-ip, email)
- Galaxy Linking: Link event to MITRE ATT&CK techniques, threat actor clusters, malware families
- Enrichment: Use MISP modules (VirusTotal, Shodan, CIRCL PassiveDNS) to enrich attributes
- Review and Publish: Analyst reviews, sets to_ids flags, publishes for community sharing
Workflow 3: TAXII Feed Integration
[TAXII Server] --> [TAXII Client] --> [STIX Parser] --> [MISP Import] --> [Correlation]Steps:
- Discovery: Query TAXII server discovery endpoint for available API roots
- Collection Enumeration: List available collections and their metadata
- Object Retrieval: Fetch STIX 2.1 objects from collections with pagination
- STIX-to-MISP Mapping: Map STIX Indicator, Malware, Threat Actor to MISP event/attributes
- Import: Create MISP events from STIX bundles
- Correlation: Run correlation against existing MISP data
Workflow 4: Instance Synchronization
[MISP Instance A] <--sync--> [MISP Instance B] <--sync--> [MISP Instance C]
| | |
v v v
[Org A Events] [Shared Events] [Org C Events]Steps:
- Server Registration: Register remote MISP instance with URL, API key, organization
- Sync Configuration: Set sync direction (push/pull), filter rules, preview mode
- Pull Sync: Pull events from remote instance matching filter criteria
- Push Sync: Push local events to remote instance based on distribution level
- Conflict Resolution: Handle attribute conflicts with priority rules
- Audit Logging: Log all sync activities for compliance and troubleshooting
Workflow 5: IOC Export for Defensive Tools
[MISP Events] --> [Export Module] --> [Format Conversion] --> [Defensive Tool]
|
+--------+--------+
| | |
v v v
[Suricata] [Bro/Zeek] [SIEM]
Rules Intel CSV/JSONSteps:
- Filter Selection: Select events by tag, date range, threat level, to_ids flag
- Format Selection: Choose output format (Suricata, Snort, Bro/Zeek, CSV, STIX, OpenIOC)
- Rule Generation: Generate IDS/IPS rules from network IOCs
- SIEM Export: Export to CSV/JSON for SIEM ingestion (Splunk, Elastic, QRadar)
- Automation: Set up ZMQ/Kafka publishing for real-time IOC distribution
- Feedback Loop: Track hit counts on exported IOCs, feed back to MISP for scoring
Scripts 2
agent.py5.6 KB
#!/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))
process.py11.9 KB
#!/usr/bin/env python3
"""
MISP Threat Intelligence Collection Script
Automates IOC collection from MISP instance including:
- Feed management and scheduled fetching
- Event search and attribute extraction
- IOC export in multiple formats (STIX, CSV, Suricata)
- Warninglist filtering to reduce false positives
- Correlation summary generation
Requirements:
pip install pymisp requests stix2
Usage:
python process.py --url https://misp.local --key YOUR_API_KEY --action collect
python process.py --url https://misp.local --key YOUR_API_KEY --action export --format stix2
python process.py --url https://misp.local --key YOUR_API_KEY --action feeds --enable-defaults
"""
import argparse
import json
import csv
import sys
import os
from datetime import datetime, timedelta
from typing import Optional
try:
from pymisp import PyMISP, MISPEvent, MISPAttribute
except ImportError:
print("ERROR: pymisp not installed. Run: pip install pymisp")
sys.exit(1)
class MISPCollector:
"""Automated threat intelligence collector for MISP."""
def __init__(self, url: str, api_key: str, ssl_verify: bool = True):
self.misp = PyMISP(url, api_key, ssl=ssl_verify)
self.url = url
self.stats = {
"events_processed": 0,
"attributes_collected": 0,
"iocs_exported": 0,
"feeds_enabled": 0,
"warninglist_filtered": 0,
}
def enable_default_feeds(self) -> dict:
"""Enable and fetch default MISP community feeds."""
default_feeds = [
"CIRCL OSINT Feed",
"Botvrij.eu",
"abuse.ch URLhaus",
"The Botnet Channel",
"Phishtank online valid phishing",
]
feeds = self.misp.feeds()
enabled = []
for feed in feeds:
feed_name = feed.get("Feed", {}).get("name", "")
feed_id = feed.get("Feed", {}).get("id")
if any(default in feed_name for default in default_feeds):
try:
self.misp.enable_feed(feed_id)
self.misp.fetch_feed(feed_id)
enabled.append(feed_name)
self.stats["feeds_enabled"] += 1
print(f"[+] Enabled feed: {feed_name}")
except Exception as e:
print(f"[-] Failed to enable {feed_name}: {e}")
return {"enabled_feeds": enabled, "count": len(enabled)}
def add_custom_feed(self, name: str, url: str, provider: str,
source_format: str = "csv") -> dict:
"""Add a custom threat intelligence feed."""
feed_config = {
"name": name,
"provider": provider,
"url": url,
"source_format": source_format,
"input_source": "network",
"publish": False,
"enabled": True,
"distribution": 0,
"default": False,
"lookup_visible": True,
}
result = self.misp.add_feed(feed_config)
print(f"[+] Added custom feed: {name} from {provider}")
return result
def collect_recent_iocs(self, days: int = 7,
ioc_types: Optional[list] = None) -> list:
"""Collect IOCs from recent events."""
if ioc_types is None:
ioc_types = [
"ip-dst", "ip-src", "domain", "hostname",
"url", "md5", "sha1", "sha256", "email-src",
]
date_from = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
all_iocs = []
for ioc_type in ioc_types:
try:
results = self.misp.search(
controller="attributes",
type_attribute=ioc_type,
date_from=date_from,
to_ids=True,
pythonify=True,
)
for attr in results:
ioc_entry = {
"type": attr.type,
"value": attr.value,
"category": attr.category,
"event_id": attr.event_id,
"timestamp": str(attr.timestamp),
"to_ids": attr.to_ids,
"comment": attr.comment or "",
}
all_iocs.append(ioc_entry)
self.stats["attributes_collected"] += 1
print(f"[+] Collected {len(results)} {ioc_type} IOCs")
except Exception as e:
print(f"[-] Error collecting {ioc_type}: {e}")
return all_iocs
def collect_events_by_tag(self, tags: list, limit: int = 100) -> list:
"""Collect events matching specific tags."""
events = self.misp.search(
controller="events",
tags=tags,
limit=limit,
pythonify=True,
)
collected = []
for event in events:
event_data = {
"id": event.id,
"info": event.info,
"date": str(event.date),
"threat_level": event.threat_level_id,
"analysis": event.analysis,
"attribute_count": len(event.attributes),
"tags": [tag.name for tag in event.tags] if event.tags else [],
"attributes": [],
}
for attr in event.attributes:
event_data["attributes"].append({
"type": attr.type,
"value": attr.value,
"category": attr.category,
"to_ids": attr.to_ids,
})
collected.append(event_data)
self.stats["events_processed"] += 1
print(f"[+] Collected {len(collected)} events with tags: {tags}")
return collected
def filter_warninglists(self, iocs: list) -> list:
"""Filter IOCs against MISP warninglists to remove known-good indicators."""
filtered = []
for ioc in iocs:
result = self.misp.values_in_warninglist([ioc["value"]])
if not result or not result.get(ioc["value"]):
filtered.append(ioc)
else:
self.stats["warninglist_filtered"] += 1
print(f"[!] Filtered (warninglist): {ioc['value']}")
print(f"[+] Filtered {self.stats['warninglist_filtered']} IOCs via warninglists")
return filtered
def export_stix2(self, event_ids: Optional[list] = None,
tags: Optional[list] = None) -> dict:
"""Export events as STIX 2.1 bundles."""
search_params = {
"controller": "events",
"return_format": "stix2",
}
if event_ids:
search_params["eventid"] = event_ids
if tags:
search_params["tags"] = tags
stix_bundle = self.misp.search(**search_params)
self.stats["iocs_exported"] += len(
stix_bundle.get("objects", []) if isinstance(stix_bundle, dict) else []
)
print(f"[+] Exported STIX 2.1 bundle")
return stix_bundle
def export_csv(self, iocs: list, output_path: str) -> str:
"""Export IOCs to CSV file."""
if not iocs:
print("[-] No IOCs to export")
return ""
fieldnames = ["type", "value", "category", "event_id", "timestamp",
"to_ids", "comment"]
with open(output_path, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for ioc in iocs:
writer.writerow({k: ioc.get(k, "") for k in fieldnames})
self.stats["iocs_exported"] = len(iocs)
print(f"[+] Exported {len(iocs)} IOCs to {output_path}")
return output_path
def export_suricata(self, days: int = 7) -> str:
"""Export network IOCs as Suricata rules."""
rules = self.misp.search(
controller="attributes",
return_format="suricata",
to_ids=True,
type_attribute=["ip-dst", "ip-src", "domain", "url"],
date_from=(datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d"),
)
print(f"[+] Generated Suricata rules")
return rules
def get_correlation_summary(self, event_id: int) -> dict:
"""Get correlation summary for a specific event."""
event = self.misp.get_event(event_id, pythonify=True)
correlations = {}
for attr in event.attributes:
if hasattr(attr, "RelatedAttribute") and attr.RelatedAttribute:
correlations[attr.value] = {
"type": attr.type,
"related_events": [
rel["Event"]["id"] for rel in attr.RelatedAttribute
],
}
return {
"event_id": event_id,
"event_info": event.info,
"total_attributes": len(event.attributes),
"correlated_attributes": len(correlations),
"correlations": correlations,
}
def print_stats(self):
"""Print collection statistics."""
print("\n=== MISP Collection Statistics ===")
for key, value in self.stats.items():
print(f" {key.replace('_', ' ').title()}: {value}")
print("=================================\n")
def main():
parser = argparse.ArgumentParser(
description="MISP Threat Intelligence Collection Tool"
)
parser.add_argument("--url", required=True, help="MISP instance URL")
parser.add_argument("--key", required=True, help="MISP API key")
parser.add_argument("--no-ssl", action="store_true", help="Disable SSL verification")
parser.add_argument(
"--action",
choices=["collect", "export", "feeds", "correlate"],
required=True,
help="Action to perform",
)
parser.add_argument("--days", type=int, default=7, help="Lookback period in days")
parser.add_argument(
"--format",
choices=["csv", "stix2", "suricata"],
default="csv",
help="Export format",
)
parser.add_argument("--output", default="misp_iocs_export.csv", help="Output file path")
parser.add_argument("--tags", nargs="+", help="Filter by tags")
parser.add_argument(
"--enable-defaults",
action="store_true",
help="Enable default community feeds",
)
parser.add_argument("--event-id", type=int, help="Event ID for correlation")
args = parser.parse_args()
collector = MISPCollector(args.url, args.key, ssl_verify=not args.no_ssl)
if args.action == "feeds":
if args.enable_defaults:
result = collector.enable_default_feeds()
print(json.dumps(result, indent=2))
elif args.action == "collect":
iocs = collector.collect_recent_iocs(days=args.days)
if args.tags:
events = collector.collect_events_by_tag(args.tags)
print(json.dumps(events[:5], indent=2, default=str))
filtered = collector.filter_warninglists(iocs)
collector.export_csv(filtered, args.output)
elif args.action == "export":
if args.format == "stix2":
bundle = collector.export_stix2(tags=args.tags)
with open(args.output.replace(".csv", ".json"), "w") as f:
json.dump(bundle, f, indent=2, default=str)
elif args.format == "suricata":
rules = collector.export_suricata(days=args.days)
with open(args.output.replace(".csv", ".rules"), "w") as f:
f.write(str(rules))
else:
iocs = collector.collect_recent_iocs(days=args.days)
collector.export_csv(iocs, args.output)
elif args.action == "correlate":
if args.event_id:
summary = collector.get_correlation_summary(args.event_id)
print(json.dumps(summary, indent=2, default=str))
else:
print("[-] --event-id required for correlation action")
collector.print_stats()
if __name__ == "__main__":
main()