Intro
Wer MISP schon mal mit Wazuh verknüpft hat, wird sicherlich eine dieser beiden Anleitungen gefolgt sein. Es gibt auch einige Youtube Videos die einen Schritt für Schritt durch die Installation führen. Das Problem an diesen Artikeln ist, dass sie nur als Proof of Concept betrachtet werden können, da das Script sehr statisch agiert. Es werden z.B. für File Hashes nur sha256 Werte an MISP übergeben, doch die wenigstens wissen, dass die meisten MISP Feeds nur md5/sha1 Werte beinhalten.
Dieses Problem wurde in der letzten Erweiterung v2 des Scripts aufgegriffen und optimiert. In diesem Artikel beschäftigen wir uns mit der Migration von v1 auf v2.
Migration
Das alte Script liegt üblicherweise in /var/ossec/integrations und heißt einfach nur custom-misp. Manche Howtos legen eine custom-misp Datei an die auf eine custom-misp.py verweist, in diesem Fall dann bitte die .py Variante löschen.
In der alten Version wird sowohl die URL von MISP, also auch der API Key in der Datei selbst hinterlegt. Mittlerweile konfigurieren wir diesen Bereich in der integration von ossec.conf. Also bitte die alten Daten aus dem Script notieren und dann löschen
rm -f /var/ossec/integrations/custom-misp*
Wir laden die neue Integration herunter und setzen die korrekten Berechtigungen.
cd /var/ossec/integrations
wget https://raw.githubusercontent.com/wazuh/integrations/refs/heads/main/integrations/misp/custom-misp.py
mv custom-misp.py custom-misp
chmod 750 custom-misp
chown root:wazuh custom-misp
Wir wechseln jetzt in ossec.conf und passen dort die Konfiguration an
vi /var/ossec/etc/ossec.conf
So in etwas sieht der alte Inhalt aus:
<integration>
<name>custom-misp</name>
<group>sysmon_event1,sysmon_event3,sysmon_event6,sysmon_event7,sysmon_event_15,sysmon_event_22,syscheck,sshd</group>
<alert_format>json</alert_format>
</integration>
Den Bereich ändern wir in:
<integration>
<name>custom-misp</name>
<api_key>apikey</api_key>
<hook_url>https://misp/attributes/restSearch/</hook_url>
<alert_format>json</alert_format>
<group>sysmon_event1,sysmon_event2,sysmon_event3,sysmon_event4,sysmon_event5,sysmon_event6,sysmon_event7,sysmon_event8,sysmon_event9,sysmon_event_10,sysmon_event_11,sysmon_event_12,sysmon_event_13,sysmon_event_14,sysmon_event_15,sysmon_event_16,sysmon_event_17,sysmon_event_18,sysmon_event_19,sysmon_event_20,sysmon_event_21,sysmon_event_22,sysmon_event_23,sysmon_event_24,sysmon_event_25,sysmon_event_26,sysmon_event_255,syscheck</group>
</integration>
Hier kommen noch einige Gruppen dazu. Warum? Weil in der neuen Variante einige Core-Regeln überschrieben werden um auch diese Werte gegen MISP zu prüfen. Die war mit der alten Version einfach nicht ausreichend dokumentiert, bzw. hat in Teilen auch nicht funktioniert. Wir passen das Regelwerk an. Wenn die alte Anleitung befolgt wurde, finden wir den Regelsatz in unserer local_rules.xml und sieht in etwa so aus:
<group name="windows,default,misp,">
<rule id="100620" level="10">
<field name="integration">misp</field>
<match>misp</match>
<description>MISP Events</description>
<options>no_full_log</options>
</rule>
<rule id="100621" level="5">
<if_sid>100620</if_sid>
<field name="misp.error">\.+</field>
<description>MISP - Error connecting to API</description>
<options>no_full_log</options>
<group>misp_error,</group>
</rule>
<rule id="100622" level="12">
<field name="misp.category">\.+</field>
<description>MISP - IoC found in Threat Intel - Category: $(misp.category), Attribute: $(misp.value)</description>
<options>no_full_log</options>
<group>misp_alert,</group>
</rule>
</group>
Wir ersetzen mit den Regeln aus github:
<group name="windows,sysmon,">
<rule id="61603" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^1$</field>
<description>Sysmon - Event 1: Process creation $(win.eventdata.description)</description>
<options>no_full_log</options>
<group>sysmon_event1,</group>
</rule>
<rule id="61604" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^2$</field>
<description>Sysmon - Event 2: $(win.eventdata.image) changed file $(win.eventdata.targetFilename) creation time </description>
<options>no_full_log</options>
<group>sysmon_event2,</group>
</rule>
<rule id="61605" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^3$</field>
<description>Sysmon - Event 3: Network connection to $(win.eventdata.destinationIp):$(win.eventdata.destinationPort) by $(win.eventdata.image)</description>
<options>no_full_log</options>
<group>sysmon_event3,</group>
</rule>
<rule id="61606" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^4$</field>
<description>Sysmon - Event 4: Sysmon service state changed to "$(win.eventdata.state)"</description>
<options>no_full_log</options>
<group>sysmon_event4,</group>
</rule>
<rule id="61607" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^5$</field>
<description>Sysmon - Event 5: Process terminated $(win.eventdata.image)</description>
<options>no_full_log</options>
<group>sysmon_event5,</group>
</rule>
<rule id="61608" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^6$</field>
<description>Sysmon - Event 6: Driver loaded $(win.eventdata.imageLoaded)</description>
<options>no_full_log</options>
<group>sysmon_event6,</group>
</rule>
<rule id="61609" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^7$</field>
<description>Sysmon - Event 7: Image $(win.eventdata.imageLoaded) loaded by $(win.eventdata.image)</description>
<options>no_full_log</options>
<group>sysmon_event7,</group>
</rule>
<rule id="61610" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^8$</field>
<description>Sysmon - Event 8: CreateRemoteThread by $(win.eventdata.sourceImage) on $(win.eventdata.targetImage), possible process injection</description>
<options>no_full_log</options>
<group>sysmon_event8,</group>
</rule>
<rule id="61611" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^9$</field>
<description>Sysmon - Event 9: RawAccessRead by $(win.eventdata.image)</description>
<options>no_full_log</options>
<group>sysmon_event9,</group>
</rule>
<rule id="61612" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^10$</field>
<description>Sysmon - Event 10: $(win.eventdata.targetImage) process accessed by $(win.eventdata.sourceImage)</description>
<options>no_full_log</options>
<group>sysmon_event_10,</group>
</rule>
<rule id="61613" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^11$</field>
<description>Sysmon - Event 11: FileCreate by $(win.eventdata.image)</description>
<options>no_full_log</options>
<group>sysmon_event_11,</group>
</rule>
<rule id="61614" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^12$</field>
<description>Sysmon - Event 12: RegistryEvent $(win.eventdata.eventType) on $(win.eventdata.targetObject) by $(win.eventdata.image)</description>
<options>no_full_log</options>
<group>sysmon_event_12,</group>
</rule>
<rule id="61615" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^13$</field>
<description>Sysmon - Event 13: RegistryEvent $(win.eventdata.eventType) on $(win.eventdata.targetObject) by $(win.eventdata.image)</description>
<options>no_full_log</options>
<group>sysmon_event_13,</group>
</rule>
<rule id="61616" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^14$</field>
<description>Sysmon - Event 14: RegistryEvent (Key and Value Rename) by $(win.eventdata.image)</description>
<options>no_full_log</options>
<group>sysmon_event_14,</group>
</rule>
<rule id="61617" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^15$</field>
<description>Sysmon - Event 15: $(win.eventdata.targetFilename) FileCreateStreamHash by process $(win.eventdata.image)</description>
<options>no_full_log</options>
<group>sysmon_event_15,</group>
</rule>
<rule id="61644" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^16$</field>
<description>Sysmon - Event 16: Sysmon configuration changed using file $(win.eventdata.configuration)</description>
<group>sysmon_event_16,</group>
</rule>
<rule id="61645" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^17$</field>
<description>Sysmon - Event 17: Pipe created</description>
<options>no_full_log</options>
<group>sysmon_event_17,</group>
</rule>
<rule id="61646" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^18$</field>
<description>Sysmon - Event 18: Pipe connected</description>
<options>no_full_log</options>
<group>sysmon_event_18,</group>
</rule>
<rule id="61647" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^19$</field>
<description>Sysmon - Event 19: WmiEventFilter activity</description>
<options>no_full_log</options>
<group>sysmon_event_19,</group>
</rule>
<rule id="61648" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^20$</field>
<description>Sysmon - Event 20: WmiEventConsumer activity</description>
<options>no_full_log</options>
<group>sysmon_event_20,</group>
</rule>
<rule id="61649" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^21$</field>
<description>Sysmon - Event 21: WmiEventConsumerToFilter activity</description>
<options>no_full_log</options>
<group>sysmon_event_21,</group>
</rule>
<rule id="61650" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^22$</field>
<description>Sysmon - Event 22: DNS Query event</description>
<options>no_full_log</options>
<group>sysmon_event_22,</group>
</rule>
<rule id="61651" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^23$</field>
<description>Sysmon - Event 23: File deleted and archived</description>
<options>no_full_log</options>
<group>sysmon_event_23,</group>
</rule>
<rule id="61652" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^24$</field>
<description>Sysmon - Event 24: Clipboard change</description>
<options>no_full_log</options>
<group>sysmon_event_24,</group>
</rule>
<rule id="61653" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^25$</field>
<description>Sysmon - Event 25: Process tampering - Image change</description>
<options>no_full_log</options>
<group>sysmon_event_25,</group>
</rule>
<rule id="61654" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^26$</field>
<description>Sysmon - Event 26: File deleted</description>
<options>no_full_log</options>
<group>sysmon_event_26,</group>
</rule>
<rule id="61655" level="5" overwrite="yes">
<if_sid>61600</if_sid>
<field name="win.system.eventID">^255$</field>
<description>Sysmon - Event 255: Sysmon error</description>
<options>no_full_log</options>
<group>sysmon_event_255,</group>
</rule>
</group>
<group name="misp,">
<rule id="100620" level="10">
<decoded_as>json</decoded_as>
<field name="integration">misp</field>
<description>MISP Events</description>
<options>no_full_log</options>
</rule>
<rule id="100621" level="5">
<if_sid>100620</if_sid>
<field name="misp.error">\.+</field>
<description>MISP - Error connecting to API</description>
<options>no_full_log</options>
<group>misp_error,</group>
</rule>
<rule id="100622" level="12">
<field name="misp.category">\.+</field>
<description>MISP - IoC found in Threat Intel - Category: $(misp.category), Attribute: $(misp.value)</description>
<options>no_full_log</options>
<group>misp_alert,</group>
</rule>
</group>
Hier werden viele Regeln von Level 0 hochgesetzt, damit die alerts ebenfalls gegen MISP geprüft werden. Jeder muss für sich selbst entscheiden wie viele Logs er gegen seine Instanz schicken will. Bei den MISP Rules prüfen ob es vorher die gleichen waren, damit Visualisierungen und Search Strings weiterhin funktionieren.
Neuerdings arbeitet das Script mit Queues, falls es MISP nicht erreichen kann oder zu lange für eine Antwort benötigt, speichert es den Alert in der Queue und holt die Abfrage nach. Hierzu müssen wir noch die Ordnerstruktur anlegen. Für meinen Geschmack liegt sie am falschen Ort, aber ich halte mich an den Code im Github, wobei hier noch ein Bug im Script existiert. Man muss den trailing slash entfernen (Zeile 21, 24, 27):
mkdir -p /var/ossec/custom-misp-integration/logs
mkdir /var/ossec/custom-misp-integration/wazuh-retry-queue
mkdir /var/ossec/custom-misp-integration/misp-failed-enrichment
chown -R wazuh:wazuh /var/ossec/custom-misp-integration/
Jetzt noch prüfen ob nach dem Neustart von Wazuh das Log sauber ist
/var/ossec/bin/wazuh-control restart
tail -200 /var/ossec/logs/ossec.log
Und das Script loggt jetzt auch selbst
tail -200 /var/ossec/custom-misp-integration/logs/integrations.log
Dort ist dann relativ klar zu sehen ob alles funktioniert, bzw. noch am MISP geprüft werden muss
2025-09-28 19:02:31,165 [WARNING] wazuh-misp-integration: No IOCs extracted from alert (alert_id=1759078867.10008080), skipping enrichment
2025-09-28 19:02:32,607 [WARNING] wazuh-misp-integration: Skipping MISP failed alert retries because MISP is still unreachable.
2025-09-28 19:02:32,638 [WARNING] wazuh-misp-integration: No IOCs extracted from alert (alert_id=1759078867.10011219), skipping enrichment
2025-09-28 19:02:34,095 [WARNING] wazuh-misp-integration: Skipping MISP failed alert retries because MISP is still unreachable.
2025-09-28 19:02:34,129 [WARNING] wazuh-misp-integration: No IOCs extracted from alert (alert_id=1759078867.10014368), skipping enrichment
2025-09-28 19:02:35,615 [WARNING] wazuh-misp-integration: Skipping MISP failed alert retries because MISP is still unreachable.
2025-09-28 19:02:35,658 [WARNING] wazuh-misp-integration: No IOCs extracted from alert (alert_id=1759078867.10017697), skipping enrichment
Da es hier um eine Migration geht, sind die Schritte für das Aufsetzen von MISP nicht dokumentiert. Ihr könnt euch die wichtigsten Themen in meinem Blog heraussuchen.