Обсудить проект

Rate Limiting: как его обойти за 5 минут с Burp Intruder

27.08.2026

Сегодня тема, за которую я лично обожаю Burp Intruder — Rate Limiting. Разработчики думают, что поставили счётчик — и всё, брутфорс невозможен. Ага, конечно. Погнали разберём, почему «429 Too Many Requests» — это не стена, а вежливое предупреждение, которое можно проигнорировать.

Как вообще ломается rate limit

Rate limiting почти всегда завязан на один из трёх идентификаторов клиента: IP-адрес, сессионный токен или комбинацию заголовков. Проблема в том, что сервер часто доверяет клиентским заголовкам вместо того, чтобы брать реальный source IP из TCP-соединения. А клиентский заголовок — это то, что контролируешь ты. Вот и вся дыра, детка.

Это не баян, это конвейер CVE 2026

Скептики скажут «да все давно это пофиксили». Ну-ну:

  • CVE-2026-24000 (Fleet) — сервис доверял X-Forwarded-For, X-Real-IP, True-Client-IP без валидации, что позволяло спуфить IP и полностью обходить per-IP rate limit на эндпоинтах аутентификации, усиливая brute-force и password spraying. Патч вышел только в версии 4.80.1.
  • Mastodon, GHSA-c2r5-cfqr-c553 — Rails-мидлварь RemoteIp слепо доверяла заголовку Client-Ip/X-Forwarded-For, из-за чего атакующий с прямым доступом к Puma мог подделать IP и обойти почти весь rate limiting.
  • Свежий фикс от июля 2026 (cve-dev intel) чинит login rate limiter, который брал IP из X-Forwarded-For в проксированном режиме без проверки доверенности источника.

Видишь тренд? Проблема не в самой концепции rate limit, а в том, что имплементация продолжает бездумно доверять заголовкам в 2026-м, будто это 2015-й.

Пять способов обойти счётчик

1. Header spoofing — классика, которая до сих пор рулит

Добавляй эти заголовки в запрос, меняя значение на каждой итерации:

X-Originating-IP: 127.0.0.1
X-Forwarded-For: 127.0.0.1
X-Remote-IP: 127.0.0.1
X-Remote-Addr: 127.0.0.1
X-Client-IP: 127.0.0.1
X-Host: 127.0.0.1
X-Forwarded-Host: 127.0.0.1

Если бэкенд парсит X-Forwarded-For без проверки, доверенный ли это прокси — можно просто инкрементить IP на каждый запрос: 127.0.0.1, 127.0.0.2, 127.0.0.3. Некоторые сервера ещё смешнее реагируют на дублирующиеся X-Forwarded-For заголовки в одном запросе — тоже рабочий обход.

2. Race condition — когда счётчик не успевает досчитать

Самый изящный метод. Если приложение обновляет счётчик rate limit после выполнения бизнес-логики (а не до), можно отправить пачку идентичных запросов одновременно, и все они проскочат проверку до того, как счётчик успеет их учесть. PortSwigger прямо так и учит:

  1. Найди POST /login в истории прокси.
  2. Отправь в Repeater, создай 19 дубликатов в новой группе табов.
  3. Выдели пароль, правой кнопкой → Extensions > Turbo Intruder > Send to Turbo Intruder.
  4. Отправь группу единым залпом через отдельные соединения — race condition делает всю грязную работу.

3. HTTP Parameter Pollution и вариации запроса

Меняй регистр URL, добавляй мусорные query-параметры, играйся с методом (POSTpost), вставляй null-байты (%00), спецсимволы (%09, %0d%0a, %20) — некоторые rate-limit-имплементации хэшируют запрос целиком и считают вариации разными «уникальными» запросами.

4. Burp 429 Bypasser — автоматизация всего перечисленного

Ставь расширение из BApp Store: Extensions → 429 Bypasser → Send To 429 Bypasser tab. Оно само перебирает добавление кастомных заголовков, смену User-Agent, регистр URL, HTTP Parameter Pollution, смену метода, кодировки и null-байты — жмёшь OK и наблюдаешь, какая комбинация пробивает 429.

5. Burp Intruder с грамотным Resource Pool — база для брутфорса

Тут ключевой лайфхак: не долби на максимальной скорости, это спалит тебя моментом. В Intruder иди в Resource Pool → Create new resource pool, ставь Maximum concurrent requests = 1 и delay между запросами ~1000ms — многие rate limiters детектят по всплеску RPS, а не по общему количеству попыток за долгий период. Комбинируй с payload processing, который на каждый N-й запрос меняет X-Forwarded-For через правило «Add prefix/suffix» или отдельный payload set — вот тебе и обход за 5 минут, как в заголовке.

Практический payload-сетап в Intruder

Сетап для брутфорса логина с обходом IP-based rate limit:

  1. Отправь POST /login в Intruder.
  2. Отметь §password§ как payload position, тип атаки — Sniper.
  3. Добавь заголовок X-Forwarded-For: §ip§ и отметь §ip§ вторым payload position, тип атаки меняй на Pitchfork.
  4. Payload 1 (password) — словарь. Payload 2 (ip) — генератор чисел с шаблоном 127.0.0.§, каждый следующий пароль сопровождается новым IP.
  5. Через ffuf то же самое одной строкой:
ffuf -u https://target.com/login -w passwords.txt -H "X-Forwarded-For: FUZZ" -w ip_list.txt:FUZZ2

Как закрывать эту дыру (для отчёта клиенту)

  • Никогда не доверяй клиентским IP-заголовкам напрямую — бери реальный IP из TCP-соединения или строго валидируй X-Forwarded-For только от известного доверенного прокси, отбрасывая остальное.
  • Инкрементируй счётчик до выполнения бизнес-логики, а не после — это закрывает race condition класс атак.
  • Rate-limit по составному ключу: IP + user-agent + session/device fingerprint, а не по одному признаку.
  • Нормализуй URL и параметры перед хэшированием запроса, чтобы регистр, null-байты и мусорные query-параметры не создавали «новый» уникальный ключ.
  • Логируй и алертить на резкие изменения X-Forwarded-For в рамках одной сессии — это красный флаг спуфинга.

Короче, rate limiting без грамотной архитектуры — это не защита, а плацебо для чек-листа комплаенса. За 5 минут в Burp Intruder с парой заголовков и Resource Pool ты пробиваешь то, на что разработчик потратил спринт разработки. WAF — не стена, а приглашение, помни это.