Перейти к содержимому
← Каталог golang Race Condition

Promo Code Race

Состояние гонки при активации промокодов.

mediumgolangPro
Задача
# Race Condition: TOCTOU при применении одноразового промокода ## Сценарий Вы — исследователь безопасности интернет-магазина **SecureShop**. Команда внедрила систему промокодов: пользователь вводит код в корзине и получает соответствующий бонус на баланс. Промокоды задумывались как **одноразовые**: каждый код может быть применён конкретным пользователем не более одного раза. Команда уверена, что эндпоинт применения купона корректно отслеживает, был ли уже применён код этим пользователем. По данным внутреннего аудита, при превышении некоторого порога суммарного начисления через промокоды система выдаёт служебное сообщение с конфиденциальной меткой — её требуется получить. ## Цель 1. Изучите серверную логику применения купона: как именно сервер определяет, был ли код уже использован конкретным пользователем. 2. Найдите способ применить «одноразовый» код несколько раз — без повторной регистрации, без изменения данных запроса. 3. Накопите достаточное количество начислений для срабатывания служебной метки и извлеките флаг. ## Теория TOCTOU (Time-of-Check Time-of-Use) — класс уязвимостей, при которых между моментом проверки условия и моментом фактического использования его результата существует временное окно, в которое состояние может измениться. Применение одноразового промокода — типичный сценарий: проверка «использовал ли пользователь этот код?» выполняется отдельным запросом к БД, и **потом** делается запись о применении и начисление бонуса. При параллельных запросах несколько goroutine успевают выполнить шаг проверки **до того**, как любой из них завершит шаг записи — все увидят «код ещё не использован» и каждый начислит бонус. **Уязвимый паттерн:** ```go // Check-then-Act без атомарности — race condition var count int db.QueryRow("SELECT count(*) FROM used_coupons WHERE user_id=? AND code=?", uid, code).Scan(&count) if count == 0 { db.Exec("INSERT INTO used_coupons (user_id, code) VALUES (?, ?)", uid, code) db.Exec("UPDATE users SET balance = balance + ? WHERE id=?", value, uid) } ``` Атака полностью имитирует обычное поведение пользователя — параллельная отправка 10–50 идентичных POST-запросов на эндпоинт применения купона. Никаких payload-обходов, никаких подмен параметров; уязвимость возникает из-за свойств многозадачной обработки сервера и архитектуры самой проверки. ## Точка входа атаки | Параметр | Значение | |----------|----------| | Учётные данные | `demo` / `demo` | | Эндпоинт применения купона | `POST /cart/coupon` | | Промокод | `GIFT100` (известный код для тестирования) | | Цель | накопить достаточное начисление через параллельные запросы и получить флаг через профиль |
🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru