DOM XSS через URL-фрагмент
JavaScript читает location.hash и вставляет значение через innerHTML — DOM XSS без участия сервера.
mediumphpPro
Задача
# DOM-based XSS через URL-фрагмент
## Сценарий
Перед вами PHP-приложение интернет-магазина SecureShop. На странице каталога подключён небольшой клиентский JavaScript-скрипт, который читает «фрагмент» URL-адреса (часть после `#`), декодирует его и отображает над списком товаров как метку «Filtering by tag:..» — типичная UX-фича для запоминаемых ссылок-фильтров.
В отличие от server-side XSS (Reflected/Stored), у этого варианта своя специфика: **фрагмент URL не отправляется на сервер вообще** — браузер хранит его локально и обрабатывает только клиентский код. То есть никакая серверная санитизация (`htmlspecialchars()`, фильтры в Twig, экранирование в шаблонах PHP), никакой WAF не имеют отношения к проблеме. Уязвимость и её фикс полностью живут в JavaScript-коде в браузере.
В реализации этого скрипта декодированный фрагмент склеивается со статическим префиксом и присваивается элементу через свойство, которое **парсит строку как HTML** и вставляет результат в DOM. Любые HTML-теги в фрагменте URL — включая теги-векторы исполнения JavaScript — оказываются настоящими тегами в дереве страницы и срабатывают с правами скрипта на этой странице, в том числе видят сессионные cookies пользователя.
В сочетании с формой «Report to Admin» (бот открывает присланный URL и взаимодействует со страницей в собственной авторизованной сессии) это даёт классический канал кражи административной сессии и эскалации до админских прав, под которыми приложение отдаёт CTF-флаг.
## Ключевые наблюдения
- **Sink:** строка с JavaScript присваиванием значения в свойство, которое парсит HTML. Это видно прямо в HTML-ответе страницы каталога (View Source).
- **Source:** `location.hash` после `decodeURIComponent`. Никакой санитизации между source и sink нет.
- **Доставка:** форма `/report` принимает произвольный URL и передаёт его боту-администратору. Бот авторизован и открывает ссылку в своём браузере; фрагмент обрабатывается локально.
- **Ограничение `innerHTML`:** тег `<script>` через `innerHTML` не исполняется (HTML5-спецификация). Используются другие теги с авто-обработчиками событий (`<img>`, `<svg>`, `<details>`, `<iframe>` через `javascript:` URL и т.п.).
## Цели
1. Изучите клиентский JavaScript на странице каталога (DevTools → Sources, или Ctrl+U). Подтвердите, что фрагмент URL декодируется и попадает в DOM **через свойство, которое парсит HTML**, а не через свойство, устанавливающее текстовое содержимое.
2. Сконструируйте URL c фрагментом, который при открытии страницы в браузере жертвы извлечёт `document.cookie` и доставит его на ваш Exploit Server.
3. Доставьте этот URL администратору через форму отчёта; перехватите его сессию; войдите от его имени в админский раздел и заберите CTF-флаг.
## Данные
| Параметр | Значение |
|----------|----------|
| Обычный пользователь | `demo` / `demo` |
| Целевая страница | `/catalog` |
| Канал доставки админу | форма `/report` |
| Exploit Server | ссылка «Exploit Server» на панели лабы |