Ломаем ONLYOFFICE за 3 шага: цепочка уязвимостей OnlyShells
Введение
Осенью 2025 года мы провели анализ защищенности ONLYOFFICE Desktop Editors и обнаружили пять уязвимостей, которые сформировали цепочку OnlyShells. Она позволяет атакующему получить шелл с правами NT AUTHORITY\SYSTEM на компьютере жертвы при открытии специально сформированного документа. В статье подробно разбираем технические детали каждой из уязвимостей.
Поверхность атаки
Офисный пакет ONLYOFFICE Desktop Editors построен на Chromium Embedded Framework (CEF) и является приложением на базе Chromium. Он запускается без браузерной песочницы, а используемая версия Chromium (109.0.5414.120) устарела еще в 2023 году. Кроме того, вместе с редактором устанавливается служба для его обновления, которая действует с максимальными системными правами NT AUTHORITY\SYSTEM.
Существует еще одна большая поверхность атаки: парсеры различных файловых форматов, реализованные на небезопасных языках. Но даже имея серьезный примитив эксплуатации в одном из парсеров, полноценная атака почти всегда усложняется необходимостью эксплуатации one‑shot: эксплоит не сможет подстраиваться под митигации системы жертвы, такие как PIE и ASLR.
Эти вводные привели нас к следующей предполагаемой цепочке:
- Уязвимость XSS, исполнение произвольного кода JavaScript.
- Эксплуатация браузерной уязвимости рендерера.
- Эксплуатация уязвимости службы обновлений, повышение привилегий.
Рассмотрим найденные уязвимости для каждого этапа.
Уязвимости XSS
CVE-2025-68917
| Уровень опасности | Средний |
| CVSS score | 6.4 |
| CVSS-vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N |
| Необходимые привилегии | Отсутствуют |
Описание
При нажатии на кнопку редактирования комментария, страницей автоматически создается форма редактирования вида: <textarea>{{ПОЛЬЗОВАТЕЛЬСКИЙ_ВВОД}}</textarea>. При этом ПОЛЬЗОВАТЕЛЬСКИЙ_ВВОД не экранируется, поэтому атакующий может внедрить в комментарий полезную нагрузку и получить произвольное исполнение JavaScript‑кода, когда жертва нажмет Редактировать комментарий.
Пример эксплуатации
- Атакующий создает комментарий с вредоносным содержимым вида:
</textarea><script>{{код JavaScript}}</script><textarea>. - При попытке редактирования комментария выполняется внедренный скрипт.
Пример эксплуатации: в качестве PoC использована нагрузка <h1>Hello World</h1>
Состояние страницы после активации полезной нагрузки: заголовок Hello World успешно внедрен на страницу
CVE-2025-68935
| Уровень опасности | Средний |
| CVSS score | 6.4 |
| CVSS-vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N |
| Необходимые привилегии | Отсутствуют |
Описание
При редактировании параметров списка открывается модальное окно с возможностью выбора типа списка.
Модальное окно «Параметры списка»
Тип списка содержит в себе шрифт, который подставляется в атрибут style без экранирования.
Фрагмент DOM-дерева. Шрифт выставляется через атрибут style
Злоумышленник может добавить в название шрифта JavaScript‑код, который выполнится при открытии модального окна «Параметры списка».
Пример эксплуатации
- Атакующий добавляет в документ собственный тип списка, где в имени шрифта содержится:
;”><script>{{код JavaScript}}</script>. - При открытии модального окна «Параметры списка» скрипт выполняется.
Фрагмент DOM‑дерева после внедрения полезной нагрузки в название шрифта. Внедрен заголовок Adwaita Mono
Модальное окно «Параметры списка» после атаки
CVE-2025-68936
| Уровень опасности | Средний |
| CVSS score | 6.4 |
| CVSS-vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N |
| Необходимые привилегии | Отсутствуют |
Это самая опасная из обнаруженных XSS‑уязвимостей: она относится к классу 0‑click, то есть срабатывает сразу при открытии документа.
Описание
Название темы документа в выпадающем списке доступных тем не экранируется. Злоумышленник может подготовить документ с темой, в названии которой содержится полезная нагрузка. Уязвимость находится в выпадающем списке, который встраивается в DOM страницы при открытии файла, что позволяет проэксплуатировать XSS без взаимодействия с пользователем.
Пример эксплуатации
- Атакующий внедряет в документ тему с нагрузкой вида:
<script><{{код JavaScript}}</script>. - При открытии документа код на JavaScript будет выполнен без участия пользователя.
В качестве доказательства концепции использована нагрузка <h1>Hello World</h1>, внедренная на страницу
RCE: компрометация Chromium Web Engine
CVE-2023-2033
| Уровень опасности | Критический |
| CVSS score | 9.3 |
| CVSS-vector | CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H |
| Необходимые привилегии | Отсутствуют |
Описание
ONLYOFFICE Desktop Editors использует Chromium Embedded Framework версии 109.0.5414.120. В ее состав входит JavaScript‑движок V8 с уязвимостью CVE‑2023‑2033. Применив одну из описанных выше XSS‑уязвимостей, атакующий получает возможность удаленно выполнить произвольный код на устройстве (RCE). Мы не будем подробно разбирать эксплуатацию этой уязвимости — она заслуживает отдельной статьи, — но затронем ключевые моменты.
Уязвимость находится в JIT‑компиляторе Turbofan — компоненте V8. Из‑за ошибки компиляции появляется возможность получить значение hole — внутреннее представление пустого места в массивах JavaScript. После получения этого значения атакующий может использовать type confusion с индексами в массиве и в итоге добиться RCE.
Пример эксплуатации
- Получить внутреннее значение
hole v8. - С помощью
type confusionподменитьholeна индексы массива — это дает возможность записи за пределы массива. - Получить примитивы
addrof,fakeobj,sandbox_readиsandbox_write, позволяющие читать и писать произвольные значения в любое место внутриV8 sandbox heap. - Сгенерировать промежуточный шелл‑код с использованием техники JIT spraying.
- С помощью полученных примитивов заменить у функции JavaScript указатель на ее начало на сгенерированный шелл‑код.
- Подготовить полезную нагрузку и передать на нее управление через промежуточный шелл‑код.
LPE: эксплуатация Update Service
CVE-2026-41030
| Уровень опасности | Средний |
| CVSS score | 6.2 |
| CVSS-vector | CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| Необходимые привилегии | Непривилегированный пользователь Windows |
Описание
Для выполнения задач, требующихся при обновлении, служба открывает локальный порт для обмена данными по протоколу UDP.
Одна из задач удаляет все файлы во временном каталоге, имена которых начинаются на строку, переданную по протоколу. Поиск файлов, подходящих под условие, происходит рекурсивно, затрагивая вложенные каталоги. Валидация файла при удалении не производится, поэтому атакующий может спровоцировать удаление символической ссылки (junction) и получить примитив удаления произвольных файлов от имени NT AUTHORITY\SYSTEM.
Уязвимый блок кода в ONLYOFFICE
// csvcmanager.cpp (project:desktop-apps)
void CSvcManager::clearTempFiles(const tstring &prefix, const tstring &except)
{
m_future_clear = std::async(std::launch::async, [=]() {
#ifdef _WIN32
if (NS_File::fileExists(NS_File::appPath() + RESTART_BATCH))
NS_File::removeFile(NS_File::appPath() + RESTART_BATCH);
#endif
tstring _error;
list<tstring> filesList;
if (!NS_File::GetFilesList(NS_File::tempPath(), &filesList, _error, true)) {
NS_Logger::WriteLog(DEFAULT_ERROR_MESSAGE + _T(" ") + _error);
return;
} // returning files list to delete, big recursive cycle to find all files that matches pattern
for (auto &filePath : filesList) {
#ifdef _WIN32
if (PathMatchSpec(filePath.c_str(), L"*.json") || PathMatchSpec(filePath.c_str(), ARCHIVE_PATTERN)
|| PathMatchSpec(filePath.c_str(), L"*.msi") || PathMatchSpec(filePath.c_str(), L"*.exe")) {
#else
if (fnmatch("*.json", filePath.c_str(), 0) == 0 || fnmatch(ARCHIVE_PATTERN, filePath.c_str(), 0) == 0) {
#endif
tstring lcFilePath(filePath);
std::transform(lcFilePath.begin(), lcFilePath.end(), lcFilePath.begin(), ::tolower);
if (lcFilePath.find(prefix) != tstring::npos && filePath != except)
NS_File::removeFile(filePath); // deleting files
}
}
tstring updPath = NS_File::parentPath(NS_File::appPath()) + UPDATE_PATH;
if (except.empty() && NS_File::dirExists(updPath))
NS_File::removeDirRecursively(updPath);
});
}
Пример эксплуатации
- Инициировать установку специально подготовленного пакета MSI.
- Создать во временном каталоге файлы
0000\prefix_filename.jsonи0001\prefix_filename.json. - Установить защиту от удаления на файл
0000\prefix_filename.json. - Отправить пакет с командой очистки временного каталога с аргументом
prefix. При обработке запроса служба обновлений соберет информацию об удаляемых файлах, среди которых будут находиться0000\prefix_filename.jsonи0001\prefix_filename.json. После сбора информации служба предпримет попытку удаления0000\prefix_filename.json, но из‑за защиты от удаления WinAPI функцияDeleteFileзакончит выполнение только после того, как защита будет снята. - Подменить
0001\prefix_filename.jsonна символическую ссылку на файлConfig.Msi:$INDEX_ALLOCATIONпри оповещении об удалении защищенного от удаления файла0000\prefix_filename.json. - Отключить защиту от удаления
0000\prefix_filename.json. Служба обновлений продолжит удаление по списку, в котором осталась0001\prefix_filename.json, но из‑за подмены на символическую ссылку будет удалёнConfig.Msi:$INDEX_ALLOCATION, что также приведет к удалению каталогаConfig.Msi. - Создать собственный каталог
Config.Msi, сохраняя дескриптор созданного каталога, и подписаться на операции записи в файлы внутри него. - Повторно инициировать установку специально подготовленного пакета MSI. Во время установки права на каталог будут переписаны на исходные (
NT AUTHORITY\SYSTEM). - Обнаружить запись скрипта для отката установки.
- Вернуть себе права на изменения каталога
Config.Msiот имени непривилегированного пользователя. Это возможно, так как у нас есть открытый дескриптор с правами на изменение DACL. - Заменить скрипт отката установки на вредоносный, например, создающий reverse shell соединение на произвольный сервер.
- Отменить установку, что приведет к выполнению вредоносного скрипта отката установки с правами
NT AUTHORITY\SYSTEM.
Комбинация уязвимостей CVE‑2025‑68936, CVE‑2023‑2033 и CVE‑2026‑41030 составляет цепочку OnlyShells, позволяющую выполнять произвольный код от имени суперпользователя при открытии подготовленного файла.
Для защиты от OnlyShells необходимо обновить ONLYOFFICE Desktop Editors до версии 9.3.0. BI.ZONE EDR корректно детектирует постэксплуатацию цепочки.