npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
Overview
MISP (Malware Information Sharing Platform) is an open-source threat intelligence platform designed for collecting, storing, distributing, and sharing cybersecurity indicators and threat information. PyMISP is the official Python library for interacting with MISP instances via the REST API, enabling programmatic event creation, attribute management, tag assignment, galaxy cluster attachment, and feed synchronization. This skill covers using PyMISP to create events with structured IOCs (IP addresses, domains, file hashes, URLs), enrich events with MITRE ATT&CK tags, manage sharing groups and distribution levels, search for existing intelligence, and export in STIX 2.1 format for interoperability with other platforms.
When to Use
- When conducting security assessments that involve performing threat intelligence sharing with misp
- When following incident response procedures for related security events
- When performing scheduled security testing or auditing activities
- When validating security controls through hands-on testing
Prerequisites
- MISP instance (v2.4+) with API access enabled
- Python 3.9+ with
pymisp(pip install pymisp) - MISP API key (Settings > Auth Keys)
- Understanding of MISP data model (Events, Attributes, Objects, Tags, Galaxies)
- Knowledge of TLP marking and sharing protocols
Steps
- Install PyMISP:
pip install pymisp - Initialize
ExpandedPyMISP(url, key, ssl=True)connection - Create a
MISPEventwith info, distribution level, threat level, and analysis status - Add attributes via
event.add_attribute(type, value)for IPs, domains, hashes - Apply TLP tags and MITRE ATT&CK technique tags
- Publish the event with
misp.publish(event) - Search existing events with
misp.search(controller='events', value=..., type_attribute=...) - Enable and configure threat feeds for automatic IOC ingestion
- Export events in STIX 2.1 format for cross-platform sharing
- Validate sharing group configuration and sync server settings
Expected Output
A JSON report summarizing events created, attributes added, tags applied, feed sync status, and any correlation hits against existing intelligence, with event IDs and distribution metadata.
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.7 KB
MISP / PyMISP API Reference
Installation
pip install pymispConnection Setup
from pymisp import PyMISP, MISPEvent, MISPAttribute
misp = PyMISP(
url="https://misp.example.com",
key="YOUR_API_KEY",
ssl=True
)Core PyMISP Methods
| Method | Description |
|---|---|
misp.add_event(event) |
Create new event |
misp.update_event(event) |
Update existing event |
misp.publish(event) |
Publish event for sharing |
misp.delete_event(event_id) |
Delete an event |
misp.search(controller, value, type_attribute) |
Search events/attributes |
misp.get_event(event_id) |
Retrieve single event |
misp.add_tag(event, tag) |
Add tag to event |
misp.search_index(published=True) |
Search event index |
Creating Events
event = MISPEvent()
event.info = "APT Campaign - Phishing IOCs"
event.distribution = 1 # 0=Org, 1=Community, 2=Connected, 3=All
event.threat_level_id = 2 # 1=High, 2=Medium, 3=Low, 4=Undefined
event.analysis = 0 # 0=Initial, 1=Ongoing, 2=Complete
event.add_attribute("ip-dst", "203.0.113.50", to_ids=True, comment="C2 server")
event.add_attribute("domain", "evil.example.com", to_ids=True)
event.add_attribute("sha256", "a1b2c3d4...", category="Payload delivery")
event.add_tag("tlp:amber")
event.add_tag("mitre-attack-pattern:T1566 - Phishing")
result = misp.add_event(event)Searching Intelligence
# Search by attribute value
results = misp.search(controller="attributes", value="203.0.113.50", type_attribute="ip-dst")
# Search events by date range
results = misp.search(controller="events", date_from="2025-01-01", date_to="2025-12-31")
# Search with tags
results = misp.search(controller="events", tags=["tlp:white", "ransomware"])MISP Attribute Types
| Type | Example | Category |
|---|---|---|
ip-dst |
203.0.113.50 |
Network activity |
domain |
evil.example.com |
Network activity |
url |
https://evil.com/payload |
Network activity |
sha256 |
a1b2c3... |
Payload delivery |
md5 |
d41d8c... |
Payload delivery |
email-src |
attacker@evil.com |
Payload delivery |
filename |
malware.exe |
Payload delivery |
regkey |
HKLM\...\Run\evil |
Persistence mechanism |
Distribution Levels
0- Your organisation only1- This community only2- Connected communities3- All communities4- Sharing group
CLI Usage
python agent.py --input events.json --output report.json
python agent.py --input events.json --misp-url https://misp.example.com --api-key KEYReferences
- PyMISP Docs: https://pymisp.readthedocs.io/
- PyMISP GitHub: https://github.com/MISP/PyMISP
- MISP REST API: https://www.circl.lu/doc/misp/automation/
Scripts 1
agent.py7.8 KB
#!/usr/bin/env python3
"""MISP Threat Intelligence Sharing agent - creates events, manages attributes, searches IOCs, and validates sharing configuration via PyMISP"""
import argparse
import json
from collections import Counter
from datetime import datetime
from pathlib import Path
try:
from pymisp import PyMISP, MISPEvent
HAS_PYMISP = True
except ImportError:
HAS_PYMISP = False
MISP_ATTRIBUTE_TYPES = {
"ip-dst", "ip-src", "domain", "hostname", "url", "md5", "sha1",
"sha256", "filename", "email-src", "email-dst", "mutex", "regkey",
"user-agent", "vulnerability", "link", "text", "comment",
}
TLP_TAGS = {
"white": "tlp:white",
"green": "tlp:green",
"amber": "tlp:amber",
"amber+strict": "tlp:amber+strict",
"red": "tlp:red",
}
def load_data(path):
return json.loads(Path(path).read_text(encoding="utf-8"))
def connect_misp(url, api_key, ssl=True):
"""Initialize PyMISP connection."""
if not HAS_PYMISP:
return None, "pymisp not installed (pip install pymisp)"
misp = PyMISP(url, api_key, ssl=ssl)
return misp, "connected"
def create_event_from_data(misp, event_data):
"""Create a MISP event with attributes and tags."""
event = MISPEvent()
event.info = event_data.get("info", "Untitled Event")
event.distribution = event_data.get("distribution", 1) # 0=org, 1=community, 2=connected, 3=all
event.threat_level_id = event_data.get("threat_level", 2) # 1=high, 2=medium, 3=low, 4=undefined
event.analysis = event_data.get("analysis", 0) # 0=initial, 1=ongoing, 2=complete
for attr in event_data.get("attributes", []):
attr_type = attr.get("type", "text")
value = attr.get("value", "")
category = attr.get("category", "")
to_ids = attr.get("to_ids", True)
comment = attr.get("comment", "")
if attr_type in MISP_ATTRIBUTE_TYPES and value:
event.add_attribute(type=attr_type, value=value, category=category,
to_ids=to_ids, comment=comment)
for tag_name in event_data.get("tags", []):
event.add_tag(tag_name)
tlp = event_data.get("tlp", "").lower()
if tlp in TLP_TAGS:
event.add_tag(TLP_TAGS[tlp])
if misp:
result = misp.add_event(event)
return result
return event.to_dict()
def validate_event_quality(event_data):
"""Validate event data quality for sharing readiness."""
findings = []
eid = event_data.get("id", event_data.get("info", "unknown"))
if not event_data.get("info"):
findings.append({
"type": "missing_event_info",
"severity": "high",
"resource": str(eid),
"detail": "Event lacks descriptive info/title",
})
attrs = event_data.get("attributes", event_data.get("Attribute", []))
if not attrs:
findings.append({
"type": "no_attributes",
"severity": "high",
"resource": str(eid),
"detail": "Event has no IOC attributes",
})
attr_types = Counter(a.get("type", "unknown") for a in attrs)
if len(attr_types) == 1 and len(attrs) > 1:
findings.append({
"type": "single_attribute_type",
"severity": "low",
"resource": str(eid),
"detail": f"All {len(attrs)} attributes are type '{list(attr_types.keys())[0]}' - consider enriching",
})
tags = event_data.get("tags", event_data.get("Tag", []))
tag_names = [t.get("name", t) if isinstance(t, dict) else t for t in tags]
has_tlp = any("tlp:" in t.lower() for t in tag_names)
if not has_tlp:
findings.append({
"type": "missing_tlp_tag",
"severity": "high",
"resource": str(eid),
"detail": "Event lacks TLP classification tag",
})
has_mitre = any("mitre-attack" in t.lower() or "attack-pattern" in t.lower() for t in tag_names)
if not has_mitre and len(attrs) > 0:
findings.append({
"type": "missing_mitre_mapping",
"severity": "medium",
"resource": str(eid),
"detail": "Event lacks MITRE ATT&CK technique mapping",
})
dist = event_data.get("distribution", -1)
if dist == 3:
findings.append({
"type": "unrestricted_distribution",
"severity": "medium",
"resource": str(eid),
"detail": "Event set to 'All communities' distribution - verify this is intentional",
})
for attr in attrs:
val = attr.get("value", "")
atype = attr.get("type", "")
if atype in ("ip-dst", "ip-src") and val in ("127.0.0.1", "0.0.0.0", "10.0.0.1", "192.168.1.1"):
findings.append({
"type": "private_ip_ioc",
"severity": "high",
"resource": str(eid),
"detail": f"Private/localhost IP '{val}' used as IOC - will generate false positives",
})
if atype in ("md5", "sha1", "sha256") and len(val) < 32:
findings.append({
"type": "invalid_hash_length",
"severity": "high",
"resource": str(eid),
"detail": f"Hash attribute '{val}' is too short for type {atype}",
})
return findings
def validate_sharing_config(config):
"""Validate MISP sharing and feed configuration."""
findings = []
servers = config.get("sync_servers", [])
if not servers:
findings.append({
"type": "no_sync_servers",
"severity": "medium",
"resource": "misp_config",
"detail": "No synchronization servers configured for intelligence sharing",
})
for srv in servers:
if not srv.get("pull", False) and not srv.get("push", False):
findings.append({
"type": "inactive_sync_server",
"severity": "medium",
"resource": srv.get("name", srv.get("url", "")),
"detail": "Sync server has neither pull nor push enabled",
})
feeds = config.get("feeds", [])
enabled_feeds = [f for f in feeds if f.get("enabled", False)]
if not enabled_feeds:
findings.append({
"type": "no_active_feeds",
"severity": "medium",
"resource": "misp_config",
"detail": "No active threat intelligence feeds configured",
})
return findings
def analyze(data):
findings = []
events = data.get("events", [data] if "info" in data or "Attribute" in data else [])
if isinstance(data, list):
events = data
for evt in events:
findings.extend(validate_event_quality(evt))
if "sync_servers" in data or "feeds" in data:
findings.extend(validate_sharing_config(data))
return findings
def generate_report(input_path):
data = load_data(input_path)
findings = analyze(data)
sev = Counter(f["severity"] for f in findings)
cats = Counter(f["type"] for f in findings)
return {
"report": "misp_threat_intelligence_sharing",
"generated_at": datetime.utcnow().isoformat() + "Z",
"total_findings": len(findings),
"severity_summary": dict(sev),
"finding_categories": dict(cats),
"findings": findings,
}
def main():
ap = argparse.ArgumentParser(description="MISP Threat Intelligence Sharing Agent")
ap.add_argument("--input", required=True, help="Input JSON with MISP events or config")
ap.add_argument("--output", help="Output JSON report path")
ap.add_argument("--misp-url", help="MISP instance URL for live operations")
ap.add_argument("--api-key", help="MISP API key")
args = ap.parse_args()
report = generate_report(args.input)
out = json.dumps(report, indent=2)
if args.output:
Path(args.output).write_text(out, encoding="utf-8")
print(f"Report written to {args.output}")
else:
print(out)
if __name__ == "__main__":
main()