How to Install and Use MISP on Linux: Managing and Sharing Threat Intelligence

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Context & Need: When You Have Too Many Logs but Lack Actionable Intelligence

Back when I was working on-call shifts with our DevOps team, every time the SIEM or firewall triggered an alert for a suspicious IP, it was a nightmare. The team would spend 20 to 30 minutes cross-referencing indicators across VirusTotal and AbuseIPDB, then manually logging the findings into an internal Excel spreadsheet. This workflow quickly collapsed. Data was fragmented, and the incoming shift had zero visibility into what the previous shift had handled. Worse still, we had no automated way to push Indicators of Compromise (IoCs) down to our Suricata cluster or iptables rules for timely blocking.

That is why our team decided to deploy MISP (Malware Information Sharing Platform). This open-source threat intelligence sharing platform solves three major challenges:

  • Centralized data: Consolidates file hashes, IPs, C2 domains, CVEs, and threat actor campaigns into a standardized STIX/TAXII database.
  • Automated synchronization: Automatically pulls 50,000 to 100,000 IoCs per day from CIRCL, AlienVault OTX, or abuse.ch directly to your server.
  • Automated defense: Provides REST APIs for SIEMs, SOAR platforms, iptables scripts, or Snort/Suricata to automatically fetch blocklists and drop malicious traffic immediately.

Deploying MISP: A Practical Docker Approach on Linux

Installing MISP directly (bare-metal) on Linux can be a daunting experience. The ecosystem involves multiple intertwined layers: PHP 7.4/8.x, Apache/Nginx, MariaDB, Redis, Python virtual environments, and externally compiled C libraries. Version upgrades often trigger dependency conflicts. Therefore, deploying with Docker (using the official misp-docker repository) is the safest approach: the environment is fully isolated, straightforward to back up via snapshots, and keeps your host operating system clean.

Step 1: Prepare the Ubuntu/Debian Server

The minimum hardware requirement is 2 vCPUs and 4GB of RAM. If you plan to enable five or more large feeds (such as URLhaus or OTX), allocate at least 8GB of RAM and a 40GB SSD so MariaDB and Redis avoid I/O bottlenecks under heavy workloads. Install Docker Engine and the Compose plugin:

# Update repositories and install Docker engine
sudo apt update && sudo apt install -y curl git docker.io docker-compose-plugin

# Start and enable the Docker service
sudo systemctl enable --now docker

# Add the current user to the docker group for direct execution
sudo usermod -aG docker $USER
newgrp docker

Step 2: Clone the Repository and Configure Environment Variables

We will use the standard Docker Compose setup maintained by the MISP core team:

git clone https://github.com/MISP/misp-docker.git
cd misp-docker
cp template.env .env

Open the .env file to configure it. Never use default passwords for MySQL, encryption keys, or the admin account. You should generate random strings of at least 24 characters (for example, using a client-side tool like toolcraft.app/en/tools/security/password-generator to generate secure passwords without risking secret exposure over the network).

# Key configuration parameters in the .env file
MISP_BASEURL="https://misp.yourdomain.local"
MYSQL_USER="misp"
MYSQL_PASSWORD="Use_Password_Generator_To_Create_A_Complex_String_Here_123!"
MYSQL_DATABASE="misp"
MYSQL_ROOT_PASSWORD="Super_Long_Root_Password_456!"
ADMIN_PASSPHRASE="Initial_Admin_Password_789!"

Step 3: Launch the Container Cluster

docker compose up -d

On the initial run, Docker needs to pull roughly 2GB of images and execute database schema migrations, taking about 3 to 5 minutes. You can monitor the initialization logs with:

docker compose logs -f misp-core

Once the logs indicate that the web service is ready, navigate to https://<Server-IP> in your browser. The default login is [email protected] along with the password defined in ADMIN_PASSPHRASE. The platform will prompt you to change your password upon your first login.

Operational Configuration: Bringing MISP into Production

1. Configure the Base URL and Verify the GnuPG Key

Log in with administrative privileges and navigate to Administration → Server Settings & Maintenance → the MISP settings tab:

  • Locate the MISP.baseurl setting: Enter your exact FQDN (e.g., https://misp.company.com). If configured incorrectly, all email verification links, node-to-node sync webhooks, and export URLs will break.
  • Switch to the GnuPG settings tab: Verify the GPG key status. MISP uses this key pair to encrypt and digitally sign threat data exchanged between participating organizations.

2. Enable Public Threat Feeds

A fresh MISP instance is merely an empty repository. You need to ingest Open Source Intelligence (OSINT) feeds:

  1. Navigate to Sync Actions → List Feeds.
  2. Click Load default feed metadata. The system will populate a catalog of over 60 reputable global sources.
  3. Select appropriate feeds: We recommend enabling CIRCL OSINT Feed and abuse.ch URLhaus. Click the gear icon and select Enable.
  4. Click Fetch and capture all feeds to trigger background workers to pull threat data. The initial sync will fetch tens of thousands of records, taking approximately 5–10 minutes depending on your network bandwidth.

3. Record Your First Event and Set the IDS Flag

Suppose your SOC team identifies a ransomware C2 server communicating with your internal network segment. You can document the event as follows:

  • Go to Event Actions → Add Event.
  • Fill in the event details: Set Distribution to This Community Only (internal use only), Threat Level to High, and Analysis to Initial.
  • After creating the event, click Add Attribute: Set Category to Network activity, Type to ip-dst, and enter the suspicious IP address (e.g., 198.51.100.23).
  • Important: Check the IDS box. This flag signals firewalls and automated defense scripts that this IoC should be used to enforce blocking rules.

4. Generate an API Key for Automated Integration

To allow external tools to query MISP programmatically, you need to generate a dedicated authentication key:

Go to Administration → List Users → select your user → View Auth Keys → Add Authentication Key. Save this 40-character token in your password manager immediately; MISP will mask it once you leave the page.

Verification & Maintenance: Ensuring Seamless Data Pipelines

1. Verify Worker Health

All background tasks—such as IoC extraction, hash analysis, and feed ingestion—run through Redis queues and CakePHP workers. If workers hang, incoming data will get stuck in the pipeline.

To verify worker status, go to Administration → Server Settings & Maintenance → the Workers tab. Ensure that all queues—default, email, cache, and prio—display a green OK (Active) status.

2. Write a Python Script to Extract Automated Blocklists

Below is a sample script that tests the API connection and automatically extracts malicious IPs flagged for IDS over the past 7 days to feed into iptables or firewalls:

import requests
import json

MISP_URL = "https://misp.yourdomain.local"
AUTH_KEY = "YOUR_MISP_API_KEY_HERE"

headers = {
    "Authorization": AUTH_KEY,
    "Accept": "application/json",
    "Content-Type": "application/json"
}

# Query malicious IPs flagged with IDS from the last 7 days
payload = {
    "returnFormat": "json",
    "type": "ip-dst",
    "to_ids": 1,
    "last": "7d"
}

response = requests.post(
    f"{MISP_URL}/attributes/restSearch",
    headers=headers,
    data=json.dumps(payload),
    verify=False  # Skip SSL verification if using an internal self-signed certificate
)

if response.status_code == 200:
    data = response.json()
    attributes = data.get("response", {}).get("Attribute", [])
    print(f"[+] Successfully extracted {len(attributes)} malicious IPs from MISP:")
    for item in attributes[:5]:
        print(f" - {item['value']} (Event ID: {item['event_id']})")
else:
    print(f"[-] API connection error: {response.status_code} - {response.text}")

3. Resource Maintenance and Scheduled Cleanups

After running continuously with multiple feeds for 2–3 weeks, the MariaDB database and Docker data volumes can swell to 10–20GB. You should schedule recurring cron jobs on the host machine to maintain optimal performance:

# Check the disk usage of the MariaDB volume
docker exec -it misp-docker-misp-db-1 df -h /var/lib/mysql

# Prune completed job logs older than 30 days in the core container
docker exec -it misp-docker-misp-core-1 /var/www/MISP/app/Console/cake Admin cleanupLogs 30

Once the setup is complete, the turnaround time from detecting a new attack indicator to enforcing firewall drop rules across your entire infrastructure drops to under five minutes—a stark contrast to the hours previously spent on manual lookups.

Share: