
PoC-репозиторий для CVE-2025-68147: хранимая межсайтовая сценарная уязвимость (XSS) в OpenSourcePOS. Уязвимость позволяет повысить привилегии с помощью вредоносной инъекции JavaScript в модуль Store Config. Включает детали полезной нагрузки и проверку исправления (v3.4.0). Исследователь безопасности: Адитья Сингх (Nixon-H).
| Метаданные | Подробности |
|---|
| Идентификатор CVE | CVE-2025-68147 |
| Серьезность | Высокая CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:H/A:N |
| Тип уязвимости | Межсайтовый скриптинг с сохранением (CWE-79) |
| Затронутые версии | OpenSourcePOS v3.4.0, v3.4.1 |
| Исправленная версия | v3.4.2 |
| Уязвимый компонент | Модуль конфигурации магазина (поле «Политика возврата») |
| Автор отчета | Aditya Singh (Nixon-H) |
Уязвимость межсайтового скриптинга с сохранением (Stored XSS) была обнаружена в модуле конфигурации магазина OpenSourcePOS. Приложение не выполнило надлежащую санитизацию вводимых пользователем данных в поле «Политика возврата» перед сохранением их в таблице базы данных ospos_app_config.
Эта ошибка позволила аутентифицированному злоумышленнику с привилегиями конфигурации (или злоумышленнику, использующему отдельную CSRF-цепочку) внедрять произвольные полезные нагрузки JavaScript. Поскольку «Политика возврата» динамически отображается в каждом чеке продажи, внедренная нагрузка автоматически выполняется в браузере любого пользователя — включая кассиров с низкими привилегиями, других администраторов или клиентов — при генерации или просмотре чека.
Уязвимость находится в шаблоне просмотра чека: app/Views/sales/receipt_default.php.
Приложение извлекает строку «Политика возврата» из глобального массива конфигурации ($this->config['return_policy']) и подготавливает ее для отображения.
nl2br() для преобразования новых строк в HTML-разрывы строк (<br>).nl2br() не выполняет санитизацию HTML-спецсимволов. Она оставляет такие теги, как <script>, `` и атрибуты onload, полностью нетронутыми.Уязвимый код (до исправления):
<div id="sale_return_policy">
<?php echo nl2br($this->config['return_policy']); ?>
</div>
Когда администратор сохраняет конфигурацию, полезная нагрузка сохраняется в базу данных в необработанном виде.
ospos_app_configreturn_policyPolicy Text... <script>alert('XSS')</script>Из-за отсутствия санитизации ввода на стороне контроллера (Config.php) и экранирования вывода на стороне представления (receipt_default.php) приложение подвержено уязвимости Stored XSS.
Атака нацелена на панель конфигурации магазина, но затрагивает модуль Продажи/Чеки.
http://[TARGET]/config (POST-запрос для сохранения конфигурации)http://[TARGET]/sales/receipt/[SALE_ID]Шаг 1: Внедрение Мы вошли как администратор и перешли в Конфигурация магазина -> Общие. В текстовое поле «Политика возврата» мы внедрили следующую нагрузку:
Standard Return Policy: No Refunds.
<script>alert('XSS_BY_NIXON_SUCCESSFUL')</script>
Шаг 2: Сохранение
После нажатия «Отправить» приложение отправило POST-запрос на /config/save. Полезная нагрузка была успешно сохранена в базе данных.
Шаг 3: Запуск Чтобы проверить влияние на других пользователей:
http://localhost/sales/receipt/1). Браузер обрабатывает div return_policy, встречает тег <script> и немедленно выполняет JavaScript.Наблюдаемый результат:
Появилось всплывающее окно браузера с сообщением: XSS_BY_NIXON_SUCCESSFUL.
Скриншот 1: Срабатывание оповещения
Скриншот 2: Нагрузка в конфигурации
🎥 Видеодемонстрация: Нажмите, чтобы скачать / посмотреть PoC видео
Это уязвимость с изменением области действия (S:C), поскольку атака сохраняется на сервере, но выполняется в контексте браузера жертвы.
Повышение привилегий и перехват учетной записи:
/sales/receipt/105). Скрипт выполняется незаметно, отправляя document.cookie (содержащий ID ospos_session) на сервер злоумышленника.Создание администратора с червеобразным распространением:
/employees/save.hacker / password123). Жертва видит только чек, а злоумышленник получает постоянный бэкдор.Дефейс и фишинг:
Уязвимость была исправлена в OpenSourcePOS v3.4.2.
Разработчик применил патч, реализующий контекстно-зависимое кодирование вывода. Значение конфигурации теперь оборачивается в глобальную вспомогательную функцию esc() CodeIgniter перед передачей в nl2br().
Патч (коммит 22297a):
<div id="sale_return_policy">
<?php echo nl2br(esc($this->config['return_policy'])); ?>
</div>
Проверка: После обновления до v3.4.2 та же нагрузка отображается как безвредный текст:
Standard Return Policy: No Refunds. <script>alert('XSS_BY_NIXON_SUCCESSFUL')</script>
22297a) и подтвержден исследователем.