Перейти к содержимому

Поиск по платформе

Promo Code Race

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

Автор: Hack & Fix
Освоишь: SELECT FOR UPDATEadvisory-lockidempotency key
Средне+60 XP ~45 мин php
CWE-362 · A04:2021 Pro
Обложка: Promo Code Race Обложка: Promo Code Race
Задача
# Состояние гонки: многократная активация промокода ## Сценарий Магазин эко-товаров **EcoBazar** запустил балльную систему: промокод пополняет баланс покупателя на фиксированную сумму, и по правилам акции каждый код активируется для одного пользователя ровно один раз. Разработчик реализовал проверку честно — «сначала убедиться, что код ещё не использован, потом начислить». Перед масштабированием кампании маркетинг попросил проверить: нельзя ли обнулить всю акцию, гоняя один и тот же код? У вас есть обычный аккаунт и подозрение, что между «убедиться» и «начислить» есть зазор. ## Цель 1. Изучите логику обработчика применения промокода: как сервер проверяет, что код ещё не использован, и как фиксирует факт использования. 2. Активируйте один и тот же промокод многократно от лица одного пользователя — без подмены параметров и обхода CSRF, исключительно за счёт параллельной обработки запросов. 3. Накопите баланс, достаточный для покупки служебного товара **CTF Flag**, оформите заказ и получите флаг на странице профиля. ## Теория **TOCTOU (Time-of-Check to Time-of-Use)** — класс гонок состояния, где между проверкой условия и использованием её результата есть временное окно. Типовой паттерн — «прочитать → проверить → действовать» тремя отдельными запросами к БД без транзакции и блокировки. Параллельные запросы успевают пройти проверку до того, как любой из них завершит запись, и все действуют на основании одного устаревшего состояния. **Уязвимый паттерн:** ```php // CHECK: прочитали, использован ли код... $stmt = $db->prepare('SELECT count(*) as cnt FROM used_coupons WHERE user_id = ? AND code = ?'); // ...а USE — отдельный шаг с записью факта использования redeemCoupon($db, (int)$user['id'], $code, (int)$coupon['value']); ``` Механика словами: проверка уникальности и запись о использовании — независимые операции, между которыми сервис начислений ещё и выдерживает паузу, имитируя обращение во внешнюю систему. В WAL-режиме SQLite множество одновременных читателей не мешают друг другу: все параллельные запросы читают «ещё не использован», и каждый начисляет бонус. Одноразовый код срабатывает столько раз, сколько запросов попало в окно, а баланс растёт кратно номиналу. ## Точка входа атаки `POST /cart/coupon` — применение промокода, поле `code` (требуется CSRF-токен со страницы профиля). Промокоды акции: `PROMO50`, `PROMO100` и крупный `SUPER5000` (+$5000). * **Обычный пользователь:** `demo` / `demo` * **Цель:** покупка служебного товара **CTF Flag**; флаг появится в профиле после оформления заказа

Похожие лабораторные (4)

другие лабы по этой уязвимости
Обложка лабы: Race Condition: Double-spend баланса Обложка лабы: Race Condition: Double-spend баланса
Race

Race Condition: Double-spend баланса

Race condition: чтение и списание баланса без транзакции позволяет двойную трату при параллельных запросах.

+60 XP
Go Pro
Exploit Fix
Обложка лабы: Promo Code Race Обложка лабы: Promo Code Race
Race

Promo Code Race

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

+60 XP
Go Pro
Exploit Fix
Обложка лабы: Promo Code Race Обложка лабы: Promo Code Race
Race

Promo Code Race

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

+60 XP
Python Pro
Exploit Fix
Обложка лабы: Race Condition: Гонка при активации промокода в Express Обложка лабы: Race Condition: Гонка при активации промокода в Express
Race

Race Condition: Гонка при активации промокода в Express

Эндпоинт активации промокода в Express + better-sqlite3 содержит TOCTOU между проверкой счётчика и обновлением баланса. Получи бонус несколько раз параллельными запросами, накопи баланс и открой VIP-функцию с флагом.

+90 XP
Node.js Pro
Exploit Fix