
Una documentazione di CVE-2025-68116
Autore: @x0root
Vulnerabilità: Cross-Site Scripting persistente (XSS) tramite caricamenti renderizzabili dal browser (SVG / HTML)
Software interessato: FileRise (< 2.7.1)
Versione con patch: 2.7.1
CVE ufficiale (richiesto tramite GHSA): CVE-2025-68116 (tracciamento/advisory: GHSA-35pp-ggh6-c59c)
Advisory precedente correlato (mitigazione originale che è stata aggirata): GHSA-qrcv-vjvf-fr29
Valutazione CVSS:
La valutazione del reporter considera i Privilegi Richiesti (PR) nel momento dello sfruttamento, non nel momento in cui la vulnerabilità viene introdotta.
Lo sfruttamento avviene quando una vittima accede a un link di condivisione pubblico generato, il che non richiede autenticazione né privilegi (PR:N).
La valutazione del CNA valuta i PR in base alla capacità di caricare un file dannoso. Tuttavia, CVSS v3.1 definisce i Privilegi Richiesti (PR) come i privilegi che un attaccante deve possedere nel momento in cui la vulnerabilità viene sfruttata, non i privilegi necessari per introdurre o predisporre la condizione vulnerabile.
Di conseguenza, PR:N riflette in modo più accurato le condizioni di sfruttamento nel mondo reale, portando a una classificazione di gravità Critica (9.6).
Nota: GHSA-qrcv-vjvf-fr29 ha introdotto una mitigazione che impediva il rendering degli SVG all'interno dell'interfaccia web di FileRise (riquadro di anteprima). Questo report documenta un bypass di tale mitigazione — in particolare gli endpoint backend di condivisione/download — tracciato come GHSA-35pp-ggh6-c59c / CVE-2025-68116.
Questo documento è una registrazione tecnica completa di CVE-2025-68116: una XSS persistente in FileRise che è persistita dopo una mitigazione precedente ed è stata infine corretta nella v2.7.1. Include la scoperta, le prove di concetto di sfruttamento, i ripetuti tentativi di correzione falliti, una precisa analisi del flusso di controllo della causa principale (con evidenze), la verifica finale della patch e un'analisi delle caratteristiche di sfruttabilità rilevanti per la valutazione CVSS. Tutto il contenuto seguente si basa su test riprodotti, ispezione del controller e sul thread pubblico dell'advisory.
Un advisory precedente, GHSA-qrcv-vjvf-fr29, affrontava la XSS persistente tramite caricamenti di SVG bloccando il rendering inline nell'interfaccia web di FileRise. Quella mitigazione non affrontava il modo in cui i file SVG venivano serviti dagli endpoint backend come:
/api/file/download.php/api/file/share.phpCVE-2025-68116 (tracciato come GHSA-35pp-ggh6-c59c) documenta un bypass della mitigazione GHSA-qrcv-vjvf-fr29: un attaccante può memorizzare un SVG appositamente creato e consegnarlo alle vittime tramite link di condivisione pubblici o determinati comportamenti di download, portando all'esecuzione di script nell'origine di FileRise.
Per verificare se il backend esponesse ancora gli SVG in modo renderizzabile, ho caricato un semplice SVG di prova (PoC):
Accedendo al file tramite:
/api/file/download.php?…/api/file/share.php?token=…si è verificata l'esecuzione di alert(). La mitigazione originale di GHSA-qrcv-vjvf-fr29 (blocco dell'anteprima nell'interfaccia) è stata aggirata tramite accesso diretto a questi endpoint.
Un alert() è una prova di concetto; ho testato un impatto concreto facendo interagire il payload con le API interne.
Payload di test utilizzato:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">
fetch('/api/upload/upload.php')
.then(response => response.text())
.then(data => alert('API Response: ' + data));
</script>
</svg>
Quando un amministratore connesso apriva un link di condivisione contenente questo SVG, lo script veniva eseguito e effettuava richieste API autenticate. Gli effetti osservati includevano:
{"csrf_expired":true,"csrf_token":"..."})Classificazione dell'impatto dimostrata durante i test:
Ho segnalato il problema privatamente. Il maintainer ha rilasciato diverse correzioni incrementali:
Durante il periodo v2.6.0 → v2.7.0, l'endpoint dei link di condivisione ha continuato a servire l'SVG in un modo che consentiva il rendering inline e l'esecuzione di script. L'analisi della causa principale di seguito spiega perché le correzioni precedenti non sono riuscite a chiudere completamente il vettore.
La causa sottostante non era un singolo header mancante, ma il flusso di controllo e l'ordine di emissione dell'output all'interno di shareFile() (controller), che impedivano l'applicazione degli header di sicurezza in molti percorsi di esecuzione. Erano presenti due classi di problemi:
exit; anticipati che interrompevano prematuramente la funzione prima che gli header di sicurezza venissero impostati.Ho usato una scansione awk per elencare le occorrenze di header() e exit; all'interno di shareFile() fino alla chiamata readfile():
Comando: awk '/function shareFile(/ {flag=1} /readfile(/ {flag=0} flag && /(header|exit;)/ {printf "%4d | %s\n", NR, $0}' src/controllers/FileController.php
Output osservato (ridotto dalla mia esecuzione):
1649 | header('Content-Type: application/json; charset=utf-8'); 1651 | exit; 1657 | header('Content-Type: application/json; charset=utf-8'); 1659 | exit; 1664 | header('Content-Type: application/json; charset=utf-8'); 1666 | exit; 1670 | header("Content-Type: text/html; charset=utf-8"); 1693 | exit; 1699 | header('Content-Type: application/json; charset=utf-8'); 1701 | exit; 1719 | header('Content-Type: application/json; charset=utf-8'); 1721 | exit; 1725 | header('Content-Type: application/json; charset=utf-8'); 1727 | exit;
Gli header di sicurezza (la logica di indurimento) iniziano alla riga ~1743:
1743 | header('X-Content-Type-Options: nosniff'); ... 1770 | header("Content-Disposition: attachment; ...");
Poiché la funzione emette header + exit; prima in molti percorsi, quelle richieste non raggiungevano mai il codice di indurimento che imposta Content-Disposition, nosniff o il tipo restrittivo.