Business Logic: Подмена цены в форме
Checkout читает цену товара из скрытого поля формы вместо базы данных, позволяя подменить стоимость заказа
mediumgolangPro
Задача
# Price Manipulation: доверие клиентским финансовым данным
## Сценарий
Вы зарегистрированный пользователь интернет-магазина **SecureShop** с балансом **$500**. В каталоге есть товар **CTF Flag** стоимостью **$9999** — обычной покупкой он недоступен. Команда уверена, что процесс оформления заказа защищён — есть авторизация, CSRF-токен, проверка достаточности баланса. По данным внутреннего аудита, существует способ оформить заказ на CTF Flag, не повышая баланс и не подделывая ID товара, а используя саму процедуру `checkout` так, как её обрабатывает сервер.
## Цель
1. Изучите процесс оформления заказа: какие именно поля формы отправляются на `POST /cart/checkout`, какие из них сервер использует для расчёта итоговой стоимости и списания с баланса.
2. Найдите параметр, которому сервер доверяет как финансовому решению, и определите, почему этому параметру нельзя доверять с точки зрения архитектуры.
3. Используйте обнаруженный вектор для оформления заказа на CTF Flag в пределах баланса $500 и извлеките флаг из подтверждения заказа.
## Теория
Уязвимости класса **Business Logic / Client-Side Trust** возникают, когда сервер использует финансовые данные, пришедшие от клиента, как источник истины. Классический случай — скрытое поле формы `total_price`, которое сервер списывает с баланса напрямую, вместо того чтобы пересчитать стоимость из БД на основе содержимого корзины. С точки зрения SQL-инъекций и XSS обработчик может быть полностью корректен, но любой HTTP-клиент (браузерный DevTools, Burp, curl) может изменить значение скрытого поля перед отправкой. CWE-602 «Client-Side Enforcement of Server-Side Security», OWASP A04:2021 «Insecure Design».
**Уязвимый паттерн:**
```go
// Сервер списывает сумму, которую прислал клиент
total, _ := strconv.Atoi(r.FormValue("total_price"))
db.Exec("UPDATE users SET balance = balance - ? WHERE id = ?", total, user.ID)
```
Скрытое поле формы (`<input type="hidden" name="total_price" value="...">`) — это UX-удобство, чтобы шаблон отдал серверу уже рассчитанную сумму без повторного запроса к БД. Но в HTTP нет способа гарантировать, что значение из формы пришло именно из вашего шаблона: атакующий просто меняет `value` через DevTools/Burp/curl и заказ оформляется по подменённой цене. Бизнес-инвариант «итоговая стоимость = сумма цен в корзине из БД» должен быть выражен в коде сервера, а не в шаблоне.
## Точка входа атаки
| Параметр | Значение |
|----------|----------|
| Учётные данные | `demo` / `demo` (баланс $500) |
| Эндпоинт оформления | `POST /cart/checkout` |
| Цель | оформить заказ на товар **CTF Flag** ($9999) в пределах баланса $500 и извлечь флаг из подтверждения |