Stored XSS в комментариях к товарам
Комментарии к товарам хранятся без санитаризации и отображаются как HTML. Укради сессию администратора.
mediumgolangPro
Задача
# Stored XSS (Кража сессии админа через комментарии к товарам)
## Сценарий
Вы тестируете интернет-магазин хакерского мерча. На странице каждого товара есть форма для оставления комментариев. Разработчик хотел красиво отображать форматирование (жирный шрифт, ссылки) и для этого включил вывод комментариев как «доверенный HTML», обойдя автоматическое экранирование Go-шаблонизатора. Это открыло дверь для **Stored XSS**: любой комментарий с JavaScript-payload'ом будет исполняться в браузере каждого, кто откроет страницу товара — включая бота-администратора.
## Цель
1. Найдите Stored XSS в форме комментариев к товару.
2. Сохраните в базе вредоносный комментарий с JavaScript, отправляющим cookie на ваш Exploit Server.
3. Через форму `/report` отправьте боту-администратору ссылку на страницу товара с XSS.
4. Перехватите `session_token` администратора с Exploit Server.
5. Установите перехваченный cookie и зайдите на `/admin` — там лежит флаг.
## Теория
**Stored XSS** (он же persistent XSS) — атака, при которой вредоносный payload сохраняется на сервере (в БД, файлах, кэше) и затем отображается всем посетителям страницы. В отличие от reflected, payload вводится один раз и работает многократно, без необходимости каждый раз заманивать жертву по специальной ссылке.
Go-шаблонизатор `html/template` по умолчанию экранирует весь пользовательский ввод. Чтобы получить XSS, разработчик должен явно «снять защиту», объявив строку доверенным HTML — обычно через кастомную функцию шаблона, помечающую её соответствующим типом из stdlib.
**Уязвимый паттерн:**
```go
// В funcMap регистрируется функция, помечающая строку как доверенный HTML:
funcMap := template.FuncMap{
"marker": func(s string) template.HTML { return template.HTML(s) },
}
// Шаблон выводит комментарий через эту функцию:
// <p>{{marker .Text}}</p>
```
После такой обёртки шаблонизатор считает, что строка уже безопасна, и отдаёт её в DOM «как есть». Любой `<script>` или `<img onerror=...>` из текста комментария становится исполняемым кодом.
## Точка входа атаки
| Параметр | Значение |
|----------|----------|
| Аккаунт атакующего | `demo` / `demo` |
| Уязвимый эндпоинт | `POST /product/{id}/comment` (поле `text`) |
| Точка отображения | `GET /product/{id}` |
| Цель | `GET /admin` (требует роль `admin`) |
| Механизм доставки | `POST /report` — отправка ссылки боту-администратору |
| Exploit Server | внешний URL для приёма украденных данных (см. панель лабы) |
## Флоу атаки
```
1. Вы (demo) → оставляете XSS-комментарий на странице /product/1
2. Вы → через /report отправляете ссылку на /product/1 боту (admin)
3. Бот-admin → открывает страницу товара
4. Браузер бота → выполняет ваш <script>
5. Скрипт → отправляет document.cookie на ваш Exploit Server
6. Вы → видите сессию admin на Exploit Server и используете её для /admin
```