Skip to main content
COSMICBYTEZLABS
NewsSecurityHOWTOsToolsStudyTraining
ProjectsChecklistsAI RankingsNewsletterStatusTagsAbout
Subscribe

Press Enter to search or Esc to close

News
Security
HOWTOs
Tools
Study
Training
Projects
Checklists
AI Rankings
Newsletter
Status
Tags
About
RSS Feed
Reading List
Subscribe

Stay in the Loop

Get the latest security alerts, tutorials, and tech insights delivered to your inbox.

Subscribe NowFree forever. No spam.
COSMICBYTEZLABS

Your trusted source for IT intelligence, cybersecurity insights, and hands-on technical guides.

731+ Articles
120+ Guides

CONTENT

  • Latest News
  • Security Alerts
  • HOWTOs
  • Projects
  • Exam Prep

RESOURCES

  • Search
  • Browse Tags
  • Newsletter Archive
  • Reading List
  • RSS Feed

COMPANY

  • About Us
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CosmicBytez Labs. All rights reserved.

System Status: Operational
  1. Home
  2. Projects
  3. MISP Threat Intelligence Platform: Self-Hosted IOC Sharing and Analysis
MISP Threat Intelligence Platform: Self-Hosted IOC Sharing and Analysis
PROJECTIntermediate

MISP Threat Intelligence Platform: Self-Hosted IOC Sharing and Analysis

Deploy MISP — the open-source Malware Information Sharing Platform — to centralize IOC management, consume live threat feeds, and wire intelligence into your SIEM and IDS with PyMISP and STIX/TAXII exports.

Dylan H.

Projects

April 15, 2026
15 min read
3-5 hours

Tools & Technologies

DockerDocker ComposeMISPPyMISPcurlPython 3

MISP Threat Intelligence Platform: Self-Hosted IOC Sharing and Analysis

When a suspicious IP appears in your firewall logs, the first question your team asks is: has anyone else seen this? Your SIEM can correlate events, your IDS can match signatures, but neither one has an answer for "is this indicator known malicious, and what campaign is it tied to?" That answer lives in a threat intelligence platform.

MISP (Malware Information Sharing Platform and Threat Sharing) is the industry-standard open-source TIP. Developed by CIRCL (Computer Incident Response Center Luxembourg) and trusted by national CERTs, financial institutions, and MSSPs worldwide, it provides a structured data model for indicators of compromise (IOCs), attribution context, and bidirectional sharing via STIX/TAXII. Unlike commercial TIPs that cost thousands per year, MISP runs on a single VM or Docker host and connects to a global ecosystem of free threat feeds out of the box.

By the end of this project you will have a production-grade MISP instance running in Docker, five live threat feeds ingesting automatically, IOC events you can query and export, and a Python script that enriches any indicator in seconds.


Project Overview

What We're Building

┌─────────────────────────────────────────────────────────────────────┐
│                    MISP Threat Intelligence Stack                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  External Feeds ──► MISP Core (PHP/Apache) ──► Analyst Web UI       │
│  (CIRCL, AlienVault,            │                                   │
│   Botvrij, etc.)                │                                   │
│                         ┌───────┴────────┐                          │
│                         ▼                ▼                          │
│                     MariaDB           Redis                         │
│                  (event storage)   (background jobs)                │
│                         │                                           │
│                   MISP Modules                                      │
│               (enrichment, export)                                  │
│                         │                                           │
│         ┌───────────────┼───────────────┐                           │
│         ▼               ▼               ▼                           │
│      STIX export    PyMISP API      Wazuh/SIEM                      │
│    (threat sharing)  (automation)   (IOC enrichment)                │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

What You'll Be Able to Do

  • Ingest live feeds: Pull IOCs from CIRCL, AlienVault OTX, Botvrij, and 30+ other MISP-format feeds automatically
  • Correlate indicators: Find every event that shares an IP, domain, or hash across all imported intelligence
  • Enrich alerts: Query MISP from Python to check if any indicator in a security alert is known malicious
  • Export to standards: Generate STIX 2.1 bundles and TAXII 2.1 collections for tool integration
  • Build a sharing community: Create organizations and sharing groups to exchange intelligence with partners

Prerequisites

  • Docker 24+ and Docker Compose v2 on a Linux host
  • 4 GB RAM minimum (8 GB recommended for active feeds)
  • 20 GB free disk for events and feed data
  • A hostname or static IP for the MISP server
  • Outbound HTTPS access for feed downloads
  • Python 3.10+ on your analyst workstation

Part 1: Deploy MISP with Docker

Step 1: Clone the Official MISP Docker Repository

The MISP project maintains the canonical Docker setup at MISP/misp-docker. It uses a template.env approach so you can pull updates cleanly without overwriting your configuration.

git clone https://github.com/MISP/misp-docker.git
cd misp-docker
 
# Copy the template — never commit your .env
cp template.env .env

Step 2: Configure Your Environment

Open .env and set these critical values:

# .env — key variables to customize
 
# Base URL — must match how you'll access MISP (no trailing slash)
MISP_BASEURL=https://misp.lab.internal
 
# Database credentials
MYSQL_ROOT_PASSWORD=changeme_root_password
MYSQL_PASSWORD=changeme_misp_password
 
# Admin account
MISP_ADMIN_EMAIL=admin@lab.internal
MISP_ADMIN_PASSPHRASE=changeme_admin_password
 
# Optional: set timezone
PHP_TIMEZONE=America/Edmonton
 
# MISP image tag (use latest stable)
MISP_TAG=latest

Security note: Use long random passwords here. MISP stores sensitive IOC data — a weak admin password is a significant risk.

Step 3: Review the Docker Compose File

The official docker-compose.yml wires together MISP core, MariaDB, and Redis. Inspect the defaults:

cat docker-compose.yml

Key services you'll see:

ServiceImageRole
mispghcr.io/misp/misp-docker/misp-corePHP application + Apache
misp-modulesghcr.io/misp/misp-docker/misp-modulesEnrichment and export modules
dbmysql:8.0Event and attribute storage
redisredis:7-alpineBackground job queue, caching

If you're running behind a reverse proxy like Traefik or Nginx, comment out the port mapping for 443 and set MISP_BASEURL to your proxy's DNS name. Otherwise, expose ports 80 and 443 directly.

Step 4: Start MISP

docker compose pull
docker compose up -d

First boot takes 3–7 minutes. MISP bootstraps the database schema, loads default taxonomies, galaxy clusters, and warning lists. Watch the initialization:

# Follow the MISP container logs
docker compose logs -f misp
 
# Wait until you see this line:
# "MISP is ready. Login: admin@admin.test / admin"

Check that all containers are healthy:

docker compose ps

Expected output:

NAME             STATUS          PORTS
misp             Up (healthy)    0.0.0.0:443->443/tcp
misp-modules     Up (healthy)
db               Up (healthy)
redis            Up (healthy)

Part 2: Initial Configuration

Step 5: First Login and Admin Setup

Open https://misp.lab.internal (or your configured URL) in a browser. Accept the self-signed certificate warning for now.

Default credentials: admin@admin.test / admin

You'll be forced to change the password on first login. Use the password you set in .env.

Next, update your organization details:

  1. Navigate to Administration → My Organization
  2. Set your Organisation Name (e.g., CosmicBytez Lab)
  3. Set a UUID — click Generate UUID if blank
  4. Save

Then harden the admin email to match your .env:

  1. Administration → List Users → click the admin user
  2. Change Email to your configured admin email
  3. Save

Step 6: Generate an API Key

Every automation script and integration uses an API key, not your password.

  1. Click your username in the top-right → My Profile
  2. Scroll to Auth keys → click Add authentication key
  3. Set a comment like PyMISP-lab and click Submit
  4. Copy the key now — it will not be shown again

Save it somewhere secure:

export MISP_KEY="your_api_key_here"
export MISP_URL="https://misp.lab.internal"

Step 7: Configure Server Settings

Navigate to Administration → Server Settings & Maintenance:

  • MISP.baseurl → confirm it matches your .env value
  • MISP.live → set to true (enables feed fetching and background workers)
  • Plugin.Enrichment_services_enable → true (enables MISP modules)

Click Diagnostics from the same menu to verify all workers are running green. If Redis workers show errors, restart the stack:

docker compose restart misp

Part 3: Threat Feeds

Step 8: Load Default Feed Metadata

MISP ships with metadata for 30+ well-known public feeds but does not enable them by default — you choose which to pull.

  1. Navigate to Sync Actions → List Feeds
  2. Click Load default feed metadata at the top of the page
  3. You'll see feeds appear in the table

Enable and fetch the highest-value free feeds:

Feed NameFormatSource
CIRCL OSINT FeedMISPCIRCL
Botvrij.eu IDS Rule FeedMISPBotvrij
ESET ExportMISPESET
CyberCure.ai FeedCSVCyberCure
abuse.ch URLhausCSVabuse.ch

For each feed you want to enable:

  1. Click the toggle in the Enabled column to turn it on
  2. Click the fetch icon (cloud/download arrow) to pull it now

The initial fetch for CIRCL can take several minutes as it downloads historical events.

Step 9: Schedule Automatic Feed Updates

Manual fetching is fine for testing but production deployments need automation. MISP's built-in scheduler handles this:

  1. Administration → Scheduled Tasks
  2. Find fetchFeeds in the list
  3. Set Timer to 3600 (every hour) or 86400 (daily, appropriate for most feeds)
  4. Enable the task

Confirm feeds are caching locally:

# Check feed storage inside the container
docker exec misp-docker-misp-1 ls /var/www/MISP/app/files/feeds/

Part 4: Working with Events and IOCs

Step 10: Create Your First Threat Event

A MISP Event is the core data object — it represents a threat cluster, campaign, or incident, with attributes (IOCs) attached.

  1. Navigate to Add Event
  2. Fill in the metadata:
    • Distribution: Your Organisation Only (keeps it private for now)
    • Threat Level: High
    • Analysis: Initial
    • Event Info: Cobalt Strike C2 Infrastructure — April 2026
  3. Click Add Event

You'll land on the event detail page. Add IOCs as attributes:

  1. Click Add Attribute
  2. Add the following:
CategoryTypeValueIDS Flag
Network activityip-dst198.51.100.42✓
Network activitydomainc2update.example.net✓
Payload deliverymd5d41d8cd98f00b204e9800998ecf8427e✓
External analysisurlhttps://c2update.example.net/beacon✓

Enable the IDS flag on each — this marks the attribute for export to IDS/firewall blocklists.

  1. Click Publish Event (lightning bolt icon) to make it visible to other MISP users in your org

Step 11: Add Contextual Intelligence with Galaxies

Raw IOCs without context are incomplete intelligence. MISP Galaxies let you tag events with MITRE ATT&CK techniques, threat actor profiles, malware families, and sectors.

On the event detail page:

  1. Click Add Tag → select Galaxies tab
  2. Search for cobalt strike → select MITRE ATT&CK: Cobalt Strike from the malware galaxy
  3. Add T1071.001 (Application Layer Protocol: Web Protocols) from the ATT&CK technique galaxy
  4. Click Submit

Your event now carries machine-readable ATT&CK context that downstream tools can act on.


Part 5: PyMISP API Integration

Step 12: Install and Configure PyMISP

PyMISP is the official Python client for MISP. Install it in a virtual environment:

python3 -m venv misp-env
source misp-env/bin/activate
pip install pymisp

Create a config file:

# keys.py — DO NOT commit to git
misp_url = "https://misp.lab.internal"
misp_key = "your_api_key_here"
misp_verifycert = False  # Set True in production with valid cert

Step 13: Query MISP for Known IOCs

The most common use case: given an indicator from an alert, check whether MISP has intelligence on it.

#!/usr/bin/env python3
# check_ioc.py — Query MISP for a specific indicator
 
from pymisp import PyMISP
import keys
 
def check_indicator(value: str) -> None:
    misp = PyMISP(keys.misp_url, keys.misp_key, keys.misp_verifycert)
 
    # Search for the value across all attribute types
    result = misp.search(value=value, pythonify=True)
 
    if not result:
        print(f"[CLEAN] {value} — no MISP hits")
        return
 
    print(f"[ALERT] {value} found in {len(result)} event(s):")
    for event in result:
        print(f"  Event ID  : {event.id}")
        print(f"  Info      : {event.info}")
        print(f"  Threat Lvl: {event.threat_level_id}")
        print(f"  Date      : {event.date}")
        print()
 
if __name__ == "__main__":
    import sys
    check_indicator(sys.argv[1])

Run it:

python3 check_ioc.py 198.51.100.42
# [ALERT] 198.51.100.42 found in 1 event(s):
#   Event ID  : 3
#   Info      : Cobalt Strike C2 Infrastructure — April 2026
#   Threat Lvl: 1
#   Date      : 2026-04-15

Step 14: Export IOCs as a Blocklist

Pull all IDS-flagged IPs from MISP and write them to a blocklist file for use with pfSense, OPNsense, or iptables:

#!/usr/bin/env python3
# export_blocklist.py — Export IDS-flagged IPs from MISP
 
from pymisp import PyMISP
import keys
 
misp = PyMISP(keys.misp_url, keys.misp_key, keys.misp_verifycert)
 
# Get all attributes of type ip-dst with IDS flag enabled
attributes = misp.search(
    controller="attributes",
    type_attribute="ip-dst",
    to_ids=1,
    pythonify=True
)
 
ips = sorted({attr.value for attr in attributes})
print(f"Exporting {len(ips)} IDS-flagged IPs...")
 
with open("blocklist.txt", "w") as f:
    for ip in ips:
        f.write(ip + "\n")
 
print("Saved to blocklist.txt")

Step 15: Export to STIX 2.1

MISP can export any event as a STIX 2.1 bundle for sharing with external partners or ingesting into tools that speak STIX natively:

# Export a specific event as STIX 2.1 via the API
curl -s -k \
  -H "Authorization: ${MISP_KEY}" \
  -H "Accept: application/json" \
  "${MISP_URL}/events/restSearch" \
  -d '{"eventid": 3, "returnFormat": "stix2"}' \
  | python3 -m json.tool > event3_stix.json
 
# Verify the bundle
python3 -c "import json; d = json.load(open('event3_stix.json')); print(f'STIX bundle with {len(d[\"objects\"])} objects')"

Part 6: SIEM Integration

Step 16: Wire MISP into Wazuh

Wazuh can query MISP in real time to enrich security alerts. When Wazuh detects a DNS query or network connection, it calls the MISP API and adds IOC context to the alert.

On your Wazuh manager, create a custom active-response script:

#!/usr/bin/env python3
# /var/ossec/integrations/misp.py
# Wazuh custom integration for MISP IOC enrichment
 
import sys
import json
import requests
import urllib3
urllib3.disable_warnings()
 
MISP_URL = "https://misp.lab.internal"
MISP_KEY = "your_api_key_here"
 
def query_misp(indicator: str) -> dict:
    headers = {
        "Authorization": MISP_KEY,
        "Accept": "application/json",
        "Content-Type": "application/json",
    }
    payload = {
        "value": indicator,
        "returnFormat": "json",
        "limit": 5,
    }
    response = requests.post(
        f"{MISP_URL}/attributes/restSearch",
        headers=headers,
        json=payload,
        verify=False,
        timeout=10,
    )
    response.raise_for_status()
    return response.json()
 
def main():
    alert_file = sys.argv[1]
    with open(alert_file) as f:
        alert = json.load(f)
 
    # Extract destination IP from Wazuh alert data
    src_ip = alert.get("data", {}).get("srcip") or \
             alert.get("data", {}).get("dest_ip")
 
    if not src_ip:
        sys.exit(0)
 
    result = query_misp(src_ip)
    hits = result.get("response", {}).get("Attribute", [])
 
    if hits:
        print(json.dumps({
            "misp_hit": True,
            "indicator": src_ip,
            "event_count": len(hits),
            "first_seen": hits[0].get("Event", {}).get("date"),
            "event_info": hits[0].get("Event", {}).get("info"),
        }))
 
if __name__ == "__main__":
    main()

Register the integration in /var/ossec/etc/ossec.conf:

<integration>
  <name>misp</name>
  <hook_url>https://misp.lab.internal</hook_url>
  <api_key>your_api_key_here</api_key>
  <level>5</level>
  <alert_format>json</alert_format>
</integration>

Part 7: Testing Your Deployment

Verification Checklist

Run through each test to confirm your MISP stack is operating correctly.

Database connectivity:

docker exec misp-docker-db-1 mysql -u misp -p"${MYSQL_PASSWORD}" misp \
  -e "SELECT COUNT(*) as event_count FROM events;"

Feed worker health:

# Check background workers
docker compose logs misp | grep -i "worker"
 
# Confirm Redis is processing jobs
docker exec misp-docker-redis-1 redis-cli info clients

API connectivity:

curl -sk \
  -H "Authorization: ${MISP_KEY}" \
  -H "Accept: application/json" \
  "${MISP_URL}/users/view/me.json" | python3 -m json.tool | head -20

Expected: your user profile in JSON.

Feed ingestion:

# Count attributes imported from feeds
curl -sk \
  -H "Authorization: ${MISP_KEY}" \
  -H "Accept: application/json" \
  "${MISP_URL}/attributes/restSearch" \
  -d '{"returnFormat": "count"}' | python3 -m json.tool

After enabling CIRCL and abuse.ch feeds, expect 50,000+ attributes within 30 minutes.

STIX export:

curl -sk \
  -H "Authorization: ${MISP_KEY}" \
  -H "Accept: application/json" \
  "${MISP_URL}/events/restSearch" \
  -d '{"returnFormat": "stix2", "limit": 1}' | python3 -c \
  "import json,sys; d=json.load(sys.stdin); print('STIX type:', d.get('type', 'error'))"

Expected output: STIX type: bundle


Part 8: Production Hardening

Replace the Self-Signed Certificate

Use Let's Encrypt via Certbot or hook MISP behind your existing Traefik/Nginx reverse proxy:

# Example Traefik label additions in docker-compose.yml
services:
  misp:
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.misp.rule=Host(`misp.lab.internal`)"
      - "traefik.http.routers.misp.entrypoints=websecure"
      - "traefik.http.routers.misp.tls=true"
      - "traefik.http.services.misp.loadbalancer.server.port=80"

Then set MISP_BASEURL to your Traefik DNS name and remove port 443 from the MISP service's ports: block.

Enable Two-Factor Authentication

  1. Administration → Server Settings → search for MISP.totp
  2. Set MISP.totp.enabled to true
  3. Each user enables TOTP from their profile page

Persistent Volumes and Backups

The official Docker Compose already defines named volumes for the database and MISP files. Add a daily backup:

#!/bin/bash
# backup-misp.sh — run via cron daily
BACKUP_DIR="/opt/backups/misp/$(date +%Y-%m-%d)"
mkdir -p "${BACKUP_DIR}"
 
# Database dump
docker exec misp-docker-db-1 \
  mysqldump -u root -p"${MYSQL_ROOT_PASSWORD}" misp \
  > "${BACKUP_DIR}/misp-db.sql"
 
# MISP files (events attachments, feeds cache)
docker run --rm \
  --volumes-from misp-docker-misp-1 \
  -v "${BACKUP_DIR}:/backup" \
  alpine tar czf /backup/misp-files.tar.gz /var/www/MISP/app/files
 
echo "Backup complete: ${BACKUP_DIR}"

Extensions and Next Steps

With a working MISP instance you have a solid threat intelligence foundation. Here's where to take it next:

TheHive + MISP Integration

TheHive is an incident response case management platform that natively integrates with MISP. Create a case in TheHive and it automatically creates a corresponding MISP event — analysts add IOCs in TheHive and they sync back to MISP for the wider community.

Cortex Enrichment Modules

Cortex connects to MISP's module system to auto-enrich attributes using 300+ analyzers: VirusTotal, Shodan, MaxMind GeoIP, AbuseIPDB, CIRCL passive DNS, and more. Every new IOC gets a reputation score and passive DNS history without any manual lookup.

MISP Sharing Communities

Connect your MISP to the CIRCL public MISP instance to receive verified threat intelligence shared by CERTs globally:

  1. Administration → Sync Actions → List Servers
  2. Add CIRCL's server with the provided sync credentials
  3. Enable pull synchronization for one-way feed

Zeek IDS Rule Export

MISP can generate Zeek IDS rules directly from your events:

curl -sk \
  -H "Authorization: ${MISP_KEY}" \
  "${MISP_URL}/attributes/bro" > /opt/zeek/share/zeek/site/misp-iocs.zeek

Combine with the Zeek + Suricata project to get automatic detection of indicators from your MISP instance on live network traffic.

Fleet-Wide Indicator Scanning with Velociraptor

Use PyMISP to pull all hash IOCs from MISP and feed them into a Velociraptor VQL hunt to scan every endpoint for malicious files simultaneously — a complete detect-and-respond loop from a single threat intelligence platform.

# Pull hashes from MISP → feed to Velociraptor
from pymisp import PyMISP
import keys
 
misp = PyMISP(keys.misp_url, keys.misp_key, keys.misp_verifycert)
hashes = misp.search(
    controller="attributes",
    type_attribute=["md5", "sha256"],
    to_ids=1,
    pythonify=True,
)
 
print("# Paste into Velociraptor VQL hunt")
print("LET BadHashes <= ", [a.value for a in hashes])

MISP is one of those tools that rewards patience during setup with compounding returns over time — every feed you enable, every event you enrich, every integration you wire up makes every subsequent investigation faster. Start with the CIRCL feed, build your first private events, then gradually expand into sharing communities as your confidence grows.

#Threat Intelligence#MISP#IOC#STIX#TAXII#CTI#Security Operations#Homelab#Blue Team

Related Articles

Deception Technology Lab: T-Pot Honeypot with OpenCanary

Deploy a full deception technology stack using T-Pot and OpenCanary to capture real attacker behaviour, generate threat intelligence, and sharpen your...

11 min read

Velociraptor DFIR: Endpoint Forensics and Incident Response at Scale

Deploy Velociraptor — the open-source DFIR platform — to collect forensic artifacts, run live endpoint hunts with VQL, and build an incident response...

11 min read

WireGuard Road Warrior VPN Server

Build a self-hosted WireGuard VPN server on Ubuntu for secure remote access — with NAT masquerading, DNS leak protection, QR-code client provisioning, and...

7 min read
Back to all Projects