
Документация по CVE-2025-68116
Автор: @x0root
Уязвимость: Межсайтовый скриптинг (XSS) с сохранением через загружаемые файлы, рендерящиеся в браузере (SVG / HTML)
Затронутое ПО: FileRise (< 2.7.1)
Патч-версия: 2.7.1
Официальный CVE (запрошен через GHSA): CVE-2025-68116 (отслеживание/уведомление: GHSA-35pp-ggh6-c59c)
Предыдущее связанное уведомление (исходная нейтрализация, которая была обойдена): GHSA-qrcv-vjvf-fr29
Оценка CVSS:
Оценка репортера оценивает необходимые привилегии (PR) в момент эксплуатации, а не в момент внедрения уязвимости.
Эксплуатация происходит, когда жертва переходит по сгенерированной публичной ссылке общего доступа, что не требует аутентификации или привилегий (PR:N).
Оценка CNA оценивает PR на основе возможности загрузки вредоносного файла. Однако CVSS v3.1 определяет необходимые привилегии (PR) как привилегии, которыми должен обладать атакующий на момент эксплуатации уязвимости, а не привилегии, необходимые для размещения или подготовки уязвимого состояния.
Таким образом, PR:N более точно отражает реальные условия эксплуатации, что приводит к классификации серьезности как Критический (9.6).
Примечание: GHSA-qrcv-vjvf-fr29 ввел нейтрализацию, которая предотвращала рендеринг SVG в веб-интерфейсе FileRise (панель предпросмотра). В данном отчете документируется обход этой нейтрализации — в частности, серверные конечные точки загрузки/скачивания, — который отслеживается как GHSA-35pp-ggh6-c59c / CVE-2025-68116.
Этот документ представляет собой полную техническую запись CVE-2025-68116: хранимый XSS в FileRise, который сохранился после более ранней нейтрализации и в конечном итоге был исправлен в версии v2.7.1. Он включает обнаружение, доказательства эксплуатации, многократные неудачные исправления, точный анализ корневой причины с точки зрения потока управления (с доказательствами), окончательную проверку патча и анализ характеристик эксплуатации, актуальных для оценки CVSS. Все содержимое ниже основано на воспроизведенных тестах, проверке контроллера и публичной теме уведомления.
Предыдущее уведомление, GHSA-qrcv-vjvf-fr29, касалось хранимого XSS через загрузку SVG путем блокировки встроенного рендеринга в веб-интерфейсе FileRise. Эта нейтрализация не затрагивала то, как SVG-файлы обрабатывались следующими серверными конечными точками:
/api/file/download.php/api/file/share.phpCVE-2025-68116 (отслеживается как GHSA-35pp-ggh6-c59c) документирует обход нейтрализации GHSA-qrcv-vjvf-fr29: атакующий может сохранить сфабрикованный SVG и доставить его жертвам через публичные ссылки общего доступа или определенные варианты скачивания, что приводит к выполнению скрипта в контексте origin FileRise.
Чтобы проверить, по-прежнему ли серверная часть предоставляет SVG в рендерящемся виде, я загрузил простой SVG PoC:
Доступ к файлу через:
/api/file/download.php?…/api/file/share.php?token=…привел к выполнению alert(). Исходная нейтрализация GHSA-qrcv-vjvf-fr29 (блокировка предпросмотра в интерфейсе) была обойдена прямым доступом к этим конечным точкам.
alert() — это PoC; я проверил значимое воздействие, заставив полезную нагрузку взаимодействовать с внутренними API.
Использованная тестовая нагрузка:
<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>
Когда вошедший в систему администратор открывал ссылку общего доступа, содержащую этот SVG, скрипт выполнялся и делал аутентифицированные запросы к API. Наблюдаемые эффекты включали:
{"csrf_expired":true,"csrf_token":"..."})Классификация воздействия, продемонстрированная во время тестирования:
Я сообщил о проблеме в частном порядке. Сопровождающий выпустил несколько инкрементальных исправлений:
На протяжении v2.6.0 → v2.7.0 конечная точка ссылки общего доступа продолжала обслуживать SVG таким образом, что допускался встроенный рендеринг и выполнение скриптов. Анализ корневой причины ниже объясняет, почему более ранние исправления не смогли полностью закрыть вектор.
Основной причиной был не один отсутствующий заголовок, а порядок потока управления и вывода внутри shareFile() (контроллер), который препятствовал применению заголовков безопасности во многих путях выполнения. Присутствовали два класса проблем:
exit;, которые прерывали функцию до того, как были установлены заголовки безопасности.Я использовал сканирование awk для вывода вхождений header() и exit; внутри shareFile() до вызова readfile():
Команда: awk '/function shareFile(/ {flag=1} /readfile(/ {flag=0} flag && /(header|exit;)/ {printf "%4d | %s\n", NR, $0}' src/controllers/FileController.php
Наблюдаемый вывод (сокращен из моего запуска):
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;
Заголовки безопасности (логика усиления защиты) начинаются примерно со строки 1743:
1743 | header('X-Content-Type-Options: nosniff'); ... 1770 | header("Content-Disposition: attachment; ...");
Поскольку функция выдает заголовки + exit; раньше во многих путях, эти запросы никогда не достигали кода усиления защиты, который устанавливает Content-Disposition, nosniff или ограничительный тип.
В потоке общего доступа, защищенного паролем, функция рано выводила HTML-приглашение для ввода пароля:
if (!empty($record['password']) && empty($providedPass)) { header("Content-Type: text/html; charset=utf-8"); ... exit; }
Этот путь отправляет Content-Type: text/html и завершается до логики усиления защиты SVG, что вызывает встроенный рендеринг в браузерах для защищенных паролем ресурсов, где пароль не был предоставлен.