Horizontal Privilege Escalation: изменение профиля другого пользователя
Обработчик обновления аватара принимает user_id из формы вместо сессии -- атакующий может изменить профиль любого пользователя, включая администратора.
mediumgolangPro
Задача
# Horizontal Privilege Escalation: модификация профиля другого пользователя
## Сценарий
Вы зарегистрированы в интернет-магазине **SecureShop**. На странице профиля есть форма редактирования аватара: пользователь указывает URL изображения, форма отправляет данные на сервер, и сервер обновляет аватар. Команда уверена, что эндпоинт безопасен — пользователь редактирует только свой профиль. По данным внутреннего аудита, в системе есть admin-учётка с привилегиями, которые при модификации её данных могут передаться через side-effect (флаг возвращается через канал, активирующийся при изменении admin-профиля).
## Цель
1. Изучите параметры POST-запроса, отправляемого формой обновления аватара: какие поля передаются с клиента, какие из них контролирует пользователь.
2. Найдите параметр, который определяет «чей профиль» обновлять, и который сервер принимает «как есть» из тела запроса.
3. Используйте этот канал, чтобы изменить admin-профиль из обычной учётной записи; извлеките флаг.
## Теория
Horizontal Privilege Escalation — частный случай IDOR (Insecure Direct Object Reference, CWE-639), при котором пользователь модифицирует данные **другого пользователя того же уровня привилегий** через прямой запрос. В отличие от vertical privilege escalation, не требует обхода ролевой защиты — атакующий и жертва могут быть оба «обычными пользователями». Корень проблемы — приложение определяет «чей ресурс редактировать» по полю в теле запроса (или query-параметре, или path-параметре), а не по идентификатору сессии текущего пользователя.
**Уязвимый паттерн:**
```go
// userID берётся из тела запроса — атакующий контролирует, чей профиль обновится
userID := r.FormValue("user_id")
db.Exec("UPDATE users SET avatar_url=? WHERE id=?", avatarURL, userID)
```
Реальный пример класса — **Facebook Photo Delete (2013)**: пользователь мог удалить чужие фото, изменив `photo_id` в API-запросе. Корректная реализация — **всегда** определять «чей ресурс» по `user.ID` из аутентифицированной сессии, и игнорировать любые поля в теле запроса, претендующие на эту роль.
## Точка входа атаки
| Параметр | Значение |
|----------|----------|
| Учётные данные | `demo` / `demo` |
| Эндпоинт обновления аватара | `POST /profile/avatar` (form-encoded) |
| Цель | модифицировать данные admin-профиля и получить флаг через side-effect-канал |