XSS через атрибут (javascript: URL)
XSS через javascript: URL-схему в атрибуте href. Go html/template экранирует HTML, но пропускает опасные URL-схемы.
mediumgolangPro
Задача
# XSS в контексте HTML-атрибута (javascript: URL в href)
## Сценарий
Вы проводите аудит безопасности интернет-магазина **SecureShop**. Разработчик добавил возможность указать «свой сайт» в профиле пользователя — на странице публичного профиля ссылка отображается как кликабельный `<a href="...">`. Команда уверена, что Go-шаблонизатор экранирует всё опасное автоматически. У приложения есть бот-администратор, который просматривает профили пользователей по жалобам, отправленным через форму **«Report to Admin»** — он переходит по любым ссылкам в профиле.
## Цель
1. Найдите способ внедрить исполняемый JavaScript в поле «Website» так, чтобы шаблонизатор Go не заблокировал значение.
2. Сохраните в профиле вредоносную ссылку, которая при клике крадёт cookie на ваш Exploit Server.
3. Через `/report` отправьте администратору URL на свой публичный профиль.
4. Перехватите `session_token` администратора и используйте его для входа на `/admin`.
5. Получите флаг на странице Admin Panel.
## Теория
Go `html/template` контекстно-зависимо экранирует переменные. Внутри `href` шаблонизатор по умолчанию **проверяет URL-схему**: ссылки `javascript:`, `vbscript:`, `data:` фильтруются автоматически. Эта защита отключается, если разработчик помечает значение как «уже безопасный URL» — например, через кастомную функцию шаблона, возвращающую соответствующий тип stdlib. После этого браузер видит `<a href="javascript:...">` и при клике выполняет произвольный JavaScript в контексте сайта — со всеми правами, включая чтение `document.cookie`.
**Уязвимый паттерн:**
```go
// В funcMap регистрируется обёртка, помечающая строку как доверенный URL:
funcMap := template.FuncMap{
"marker": func(s string) template.URL { return template.URL(s) },
}
// Шаблон выводит сайт пользователя через эту обёртку:
// <a href="{{marker .User.Website}}">{{.User.Website}}</a>
```
После такой обёртки Go-шаблонизатор **перестаёт проверять схему URL** в `href`. Любая строка `javascript:fetch(...)` сохранится в БД, попадёт в HTML и выполнится при клике любого посетителя профиля — включая бота-администратора.
## Точка входа атаки
| Параметр | Значение |
|----------|----------|
| Обычный пользователь | `demo` / `demo` |
| Обновление сайта | `POST /profile/website` (поле `website`) |
| Публичный профиль | `GET /profile/{username}` |
| Доставка боту | `POST /report` (бот откроет URL и кликнет по ссылке) |
| Цель | `GET /admin` (требует роль `admin`) |
| Exploit Server | внешний URL для приёма украденных данных (см. панель лабы) |