API Mass Assignment: Повышение привилегий через PATCH
Уязвимость Mass Assignment возникает, когда приложение слепо доверяет входному JSON и биндит его напрямую в модель базы данных.
mediumgolangPro
Задача
# Mass Assignment в REST API: повышение привилегий через JSON
## Сценарий
Вы аудируете REST API интернет-магазина **SecureShop**. У приложения есть JSON API для редактирования профиля: пользователь видит свои данные через `GET /api/user`, редактирует их через `PUT /api/user`. UI-форма позволяет изменить имя и аватар, но сам API возвращает **больше полей**, чем форма редактирует. Команда уверена, что эндпоинт безопасен — пользователь работает только со своим профилем, а данные подставляются с серверной стороны. По данным внутреннего аудита, доступ к admin-функциональности приложения требует роль администратора, а флаг возвращается в ответе API сразу после получения этой роли.
## Цель
1. Изучите ответ `GET /api/user` — какие поля сервер возвращает, помимо тех, что отображаются в UI.
2. Найдите способ модифицировать поле, которое сервер возвращает но UI не редактирует — через прямой запрос к JSON API.
3. Получите admin-функциональность и извлеките флаг из ответа.
## Теория
Mass Assignment в REST API — частный случай той же уязвимости, что встречается в form-handlers (см. `golang-go-idor-mass-assignment`), но применённый к структурированному JSON API. Уязвимость возникает когда обработчик API принимает JSON-тело и применяет **все** переданные поля к доменной модели или к SQL UPDATE без явного allowlist. В JSON-API уязвимость особенно частая, потому что:
1. Структура данных модели **видна** через `GET /api/...`-эндпоинт того же ресурса — атакующему не нужно гадать имена полей.
2. Многие фреймворки (`encoding/json`, Fiber `BodyParser`, Echo `Bind`) поощряют «удобный» паттерн bind в полную модель.
3. Внешние клиенты ожидают «гибкости» от API — разработчики оставляют open schema.
**Уязвимый паттерн:**
```go
// Тело декодируется в generic map или в саму доменную модель,
// все поля применяются к UPDATE без allowlist
var updates map[string]interface{}
json.NewDecoder(r.Body).Decode(&updates)
for field, value := range updates {
db.Exec("UPDATE users SET "+field+"=? WHERE id=?", value, user.ID)
}
```
Атака — простейшая: отправить `PUT /api/user` с дополнительным полем привилегий (`role`, `is_admin`, `permissions`, `verified`), которое известно атакующему из ответа `GET /api/user`. Сервер прозрачно его применяет, потому что не делает различия между «полями для самообслуживания» и «server-managed полями».
## Точка входа атаки
| Параметр | Значение |
|----------|----------|
| Учётные данные | `demo` / `demo` |
| Эндпоинт чтения профиля | `GET /api/user` |
| Эндпоинт редактирования | `PUT /api/user` (JSON body) |
| Цель | повысить роль текущего пользователя через JSON API и получить флаг из ответа |