SSTI: Report Template RCE
Пользовательский шаблон отчёта рендерится через render_template_string() — SSTI позволяет выполнить произвольный код через цепочку __subclasses__.
hardpythonPro
Задача
# Server-Side Template Injection: до RCE
## Сценарий
Перед вами Flask-приложение интернет-магазина SecureShop. На странице отчётов любому авторизованному пользователю доступна настройка собственного шаблона отчёта: пользователь вводит произвольный шаблон, в нём могут использоваться подстановки данных профиля и заказов (имя, баланс, число заказов), и при генерации отчёта эти подстановки заменяются реальными значениями.
Реализация выглядит безобидно — это же просто шаблон с фиксированным набором переменных. Но обработчик отчёта пропускает шаблон через машинерию шаблонизатора **как сам шаблон**, без какой-либо изоляции. Шаблонизатор Jinja2 — мощный язык; он умеет вычислять выражения, ходить по атрибутам Python-объектов, перебирать классы и вызывать их. В Python через цепочку «обычных» атрибутов любого объекта можно дотянуться не только до переменных окружения процесса (как в базовом SSTI), но и до **классов, отвечающих за запуск подпроцессов** в самой стандартной библиотеке Python. То есть простая «настройка шаблона отчёта» оказывается полноценным RCE-каналом — выполнением произвольных системных команд на сервере с правами процесса приложения.
## Цели
1. Найдите в личном кабинете поле произвольного текста, рендеримого как шаблон с подстановками. Авторизуйтесь как `demo / demo`.
2. Подтвердите, что сервер действительно интерпретирует поле как шаблон, а не показывает его «как есть» (простейший детектор — арифметическое выражение).
3. От подтверждения SSTI перейдите к полному RCE: подберите выражение, которое через внутренние атрибуты Python-объектов получит ссылку на класс запуска подпроцессов, и выполните системную команду. Прочитайте через эту команду переменные окружения процесса и извлеките CTF-флаг.
## Данные
| Параметр | Значение |
|----------|----------|
| Обычный пользователь | `demo` / `demo` |