CSRF: Несанкционированное действие через поддельный запрос
Форма администратора не защищена CSRF-токеном. Заставь бота выполнить действие от имени admin.
easygolangPro
Задача
# CSRF: Несанкционированное действие от имени администратора
## Сценарий
Вы проводите аудит безопасности интернет-магазина **SecureShop**. В админ-панели обнаружен эндпоинт активации распродажи `POST /admin/activate-sale` — он добавляет в каталог промо-товар и доступен только пользователям с ролью `admin`. Однако обработчик проверяет лишь наличие admin-сессии и **не проверяет**, откуда пришёл запрос. У приложения есть бот-администратор, который проверяет жалобы через форму **«Report to Admin»** — он откроет любую переданную HTML-страницу с уже активной admin-сессией.
## Цель
1. Найдите эндпоинт, выполняющий чувствительное действие, и убедитесь, что он не защищён CSRF-токеном.
2. Подготовьте HTML-страницу с автоматически отправляемой POST-формой, нацеленной на этот эндпоинт.
3. Через форму `/report` доставьте ссылку на эту страницу боту-администратору.
4. Убедитесь, что бот, открыв страницу, неявно выполнил `POST /admin/activate-sale` со своими admin-куками.
5. Получите флаг — после успешной атаки в каталоге появится товар «CTF Flag», в описании которого указано значение флага.
## Теория
**CSRF (Cross-Site Request Forgery)** — атака, при которой злоумышленник заставляет браузер жертвы выполнить запрос на целевой сайт от её имени. Браузер автоматически прикрепляет cookies к любому запросу на нужный домен, поэтому залогиненная сессия жертвы передаётся вместе с запросом, инициированным внешней страницей атакующего. Если сервер не отличает «свои» формы от «чужих», действие выполняется с правами жертвы.
Стандартная защита — **CSRF-токен**: уникальное значение, привязанное к сессии и встраиваемое в каждую форму. Внешний сайт не может прочитать значение cookie или сессионного токена жертвы (Same-Origin Policy), а значит и не может подставить корректный CSRF-токен в свою форму. Сервер, не найдя токена или увидев несовпадение, отвергает запрос.
**Уязвимый паттерн:**
```go
// Обработчик чувствительного действия проверяет только сессию,
// но не источник запроса:
func (h *Handler) ActivateSale(w http.ResponseWriter, r *http.Request) {
user := h.getUser(r)
if user == nil || user.Role != "admin" {
http.Error(w, "Access Denied", 403)
return
}
// CSRF-токена нет — любой сайт может вызвать этот эндпоинт
flag := env.GetFlag()
h.db.Exec(`INSERT OR IGNORE INTO products ...`, flag)
http.Redirect(w, r, "/admin", 302)
}
```
## Точка входа атаки
| Параметр | Значение |
|----------|----------|
| Ваш аккаунт | `demo` / `demo` |
| Уязвимый эндпоинт | `POST /admin/activate-sale` |
| Доставка боту | `POST /report` (бот откроет переданный URL) |
| Exploit Server / hosting | внешний хостинг для HTML-payload (см. панель лабы → вкладка HTML Payload) |
| Где появится флаг | `GET /catalog` — товар «CTF Flag» |