Поиск уязвимостей бизнес-логики: как выйти за рамки чек-листа OWASP

На третьей лабе WAPT я четыре часа методично проходил пункты OWASP Testing Guide — SQLi, XSS, CSRF, SSRF — строго по методичке, переключаясь между вкладками Burp Suite и документацией. Сканер молчал. Ручные инъекции не срабатывали. Баг нашёлся в логике применения промокодов: один код можно было активировать дважды, отправив два параллельных запроса через Burp Intruder с интервалом меньше 200 миллисекунд. Ни в одном чек-листе такого сценария не было — потому что это не техническая уязвимость с известной сигнатурой, а ошибка в бизнес-правилах конкретного приложения.
Почему OWASP чек-лист не находит логические уязвимости веб-приложений
OWASP Testing Guide (OTG) — документ, описывающий методику тестирования безопасности веб-приложений. Он покрывает типовые классы багов: инъекции, межсайтовый скриптинг, подделку запросов. Каждая проверка описана по шаблону: «отправь такой payload — ожидай такой ответ». Для технических уязвимостей это работает: SQL-инъекция в поле поиска выглядит примерно одинаково в интернет-магазине и банковском приложении.
С уязвимостями бизнес-логики всё иначе. Они привязаны к конкретным бизнес-правилам: как начисляется скидка, в каком порядке проходят шаги оформления, кто может менять роль пользователя. У каждого приложения правила свои — универсального шаблона проверки не существует.
DAST-сканер (Dynamic Application Security Testing — инструмент, который автоматически отправляет тестовые запросы к работающему приложению и анализирует ответы) не способен понять, что товар с отрицательной ценой — аномалия. Для него total: -500 — число в JSON-ответе, ничем не отличающееся от total: 500. Сканер не знает, что минус здесь — это деньги из кармана бизнеса.
OWASP сам признаёт эту проблему. Категория A04:2021 — Insecure Design описывает риски, связанные с дефектами проектирования: отсутствующие или неэффективные контрольные механизмы. Ключевое отличие от багов реализации (вроде SQL-инъекции): здесь проблема не в коде, а в архитектуре решений. Разработчик не предусмотрел сценарий, где пользователь действует «нелогично».
По данным PortSwigger Web Security Academy, корневая причина логических уязвимостей — ошибочные допущения о поведении пользователя. Разработчик считает: «Клиент пройдёт шаги 1, 2, 3 через интерфейс». Атакующий отправляет запрос сразу к шагу 3, минуя проверки на предыдущих этапах. Ещё один типичный паттерн: разработчики полагают, что к API обращаются только через браузер, и полагаются на клиентскую валидацию — которую можно обойти любым перехватывающим прокси.
Согласно отчёту Verizon DBIR 2025, доля веб-атак среди всех подтверждённых нарушений составила 26%. Заметная часть этих атак связана не с техническими уязвимостями вроде инъекций, а с логическими ошибками в процессах авторизации и обработки данных.
Как устроены уязвимости бизнес-логики
Уязвимость бизнес-логики — ситуация, когда приложение позволяет выполнить действие, не предусмотренное разработчиками, используя только штатную функциональность. Каждый отдельный запрос выглядит корректно. Каждый ответ сервера — валидный. Но последовательность или комбинация действий приводит к результату, которого быть не должно.
Что их отличает от «обычных» багов:
- Нет универсального шаблона. Логический баг в интернет-магазине (двойное применение промокода) не похож на логический баг в банке (манипуляция порядком транзакций). Каждый раз — ручная работа.
- Автоматика их не видит. Сканер ищет известные сигнатуры атак. У логических багов сигнатур нет.
- Запросы полностью легитимны. Атакующий не использует спецсимволы и не внедряет код — он взаимодействует с приложением не так, как задумано.
В MITRE ATT&CK (открытая база тактик и техник атак; T-коды — идентификаторы конкретных техник) эксплуатация логических уязвимостей веб-приложений чаще всего относится к технике T1190 — Exploit Public-Facing Application (тактика Initial Access). Атакующий находит публично доступный сервис и использует его функциональность не по назначению. Если проще — он не ломает дверь, а проходит через неё в часы, когда охранник не смотрит.
Категория A01:2021 — Broken Access Control остаётся самой распространённой в OWASP Top 10: 94% протестированных приложений имели ту или иную форму нарушения контроля доступа. Значительная часть этих нарушений — логические: IDOR (Insecure Direct Object Reference — возможность получить данные чужого пользователя, подменив идентификатор в запросе), обход шагов авторизации, манипуляция ролями.
Зачем атакующий ищет логические баги. Мотивация — финансовая выгода или доступ к конфиденциальным данным. Покупка товара за 1 рубль вместо 10 000 через манипуляцию ценой, вывод чужих средств через race condition, чтение персональных данных клиентов через IDOR — прямой ущерб бизнесу. При этом такие атаки сложнее детектировать: WAF (Web Application Firewall — межсетевой экран уровня приложения, фильтрующий HTTP-трафик по правилам) пропускает запросы, потому что в них нет вредоносных паттернов. Для WAF запрос GET /api/orders/124 выглядит точно так же, как GET /api/orders/123 — разница только в том, что 124 принадлежит другому пользователю.
Методология пентеста веб-приложений: карта бизнес-процессов вместо чек-листа
Три шага к abuse case мышлению
Навык, который отличает пентестера от оператора сканера — умение разобрать приложение на бизнес-процессы до начала технического тестирования. Методология, выработанная на десятках лаб и нескольких реальных проектах, укладывается в три шага.
Шаг 1: пройди приложение как обычный пользователь. Зарегистрируйся, заполни профиль, добавь товар в корзину, оформи заказ, примени промокод, измени настройки аккаунта. Цель — не искать баги, а понять, что приложение делает с точки зрения бизнеса. Параллельно Burp Suite работает в режиме прокси и записывает HTTP-запросы в History. На выходе — список всех бизнес-действий: «Регистрация → Подтверждение email → Вход → Каталог → Корзина → Промокод → Оплата → Профиль → Заказы».
Звучит скучно? Может быть. Но именно на этом этапе формируется понимание, где искать дальше. Без него ты тыкаешь payload’ы вслепую.
Шаг 2: определи точки доверия. Точка доверия — место, где сервер принимает данные от клиента без перепроверки на своей стороне. Открой HTTP History в Burp и ищи параметры, влияющие на бизнес-логику: price, total, discount, quantity, role, usertype, step, action, is_admin. Если параметр приходит от клиента и определяет результат операции — это потенциальный вектор. Используй поиск по телу запроса (Ctrl+F) для систематического выявления.
Шаг 3: сформулируй abuse cases. Abuse case (сценарий злоупотребления) — тестовый кейс, который описывает не «как должно работать», а «как можно обмануть систему». Для каждой точки доверия задай вопросы:
- Что если отправить отрицательное значение?
- Что если повторить запрос дважды подряд?
- Что если пропустить промежуточный шаг?
- Что если подменить идентификатор объекта на чужой?
- Что если выполнить действие после истечения таймаута?
Это threat modeling (моделирование угроз) на уровне отдельных функций приложения. Требует навыка, который не заменит никакой инструмент — умения посмотреть на интерфейс глазами человека, который хочет получить выгоду, нарушив правила.
Чем abuse case отличается от пункта чек-листа. Чек-лист: «Проверь XSS в поле поиска». Abuse case: «Пользователь может оформить заказ за 0 рублей, подменив параметр total в запросе POST /api/checkout, потому что сервер не пересчитывает сумму». Разница — в привязке к конкретному бизнес-процессу и конкретному ущербу. Ты не тестируешь «есть ли IDOR» абстрактно, а спрашиваешь: «Какие объекты используют предсказуемые ID? Какие из них содержат конфиденциальные данные? Какие проверки стоят между запросом и ответом?»
Самостоятельная практика пентеста: пошаговый разбор на лабораторном стенде
Разберём поиск уязвимости бизнес-логики на типичном сценарии — интернет-магазин с системой скидок. Подход работает на PortSwigger Web Security Academy, лабах WAPT или собственной песочнице.
Предпосылки: установленный Burp Suite Community или Pro, браузер с настроенным прокси (127.0.0.1:8080), учётная запись в тестовом приложении. На Kali Linux Burp предустановлен.
Делай раз: собери карту запросов. Пройди полный цикл покупки через браузер: каталог → карточка товара → корзина → применение промокода → оформление → подтверждение. В Burp HTTP History отфильтруй по домену приложения (правый клик → «Add to scope», затем фильтр «Show only in-scope items»). Ожидаемый результат: 15–30 запросов, покрывающих весь путь покупателя. Если видишь меньше десяти — проверь, что прокси перехватывает HTTPS (вкладка Proxy → Options → TLS pass through).
Делай два: найди параметры, влияющие на деньги. В HTTP History ищи запросы с параметрами price, total, discount, coupon, quantity, amount через поиск по телу запроса (Ctrl+F). Каждый подозрительный запрос отправь в Repeater (Ctrl+R). Ожидаемый результат: 3–5 запросов с финансовыми параметрами. Обрати внимание на формат данных: JSON ({"total": 1500}), form-encoded (total=1500), URL-параметры (?total=1500). Логика тестирования одинаковая, отличается только способ модификации.
Делай три: тестируй abuse cases в Repeater. Для каждого найденного запроса проверь четыре сценария:
-
Отрицательные значения. Замени
quantity=1наquantity=-1, нажми Send. Если сервер вернул 200 OK и сумма в ответе уменьшилась — валидация знака отсутствует. Сравни полеtotalв ответе до и после модификации. -
Повторное применение. Отправь запрос
POST /api/apply-couponс тем же промокодом второй раз. Если скидка удвоилась — сервер не отслеживает повторное использование в рамках сессии. -
Пропуск шага. Сохрани запрос финального оформления (
POST /api/checkout) из History. Открой новую сессию (очисти cookies), авторизуйся и сразу отправь этот запрос без предварительного добавления товара в корзину. Если сервер обработал — промежуточные шаги не валидируются на бэкенде. -
IDOR. Если в запросе есть
order_id=123, замени наorder_id=124. Если в ответе — данные чужого заказа, это нарушение A01:2021 Broken Access Control.
Как понять, что нашёл баг: сравни ответ с ожидаемым бизнес-поведением. Цена стала отрицательной — неправильно. Получил чужие данные — неправильно. Промокод применился дважды — неправильно. Контекст бизнес-логики здесь единственный судья: сканер не отличит total: -500 от total: 500, но ты — отличишь.
Три паттерна обхода OWASP Top 10 через логику приложения
Гонки состояний в финансовых операциях
Race condition (гонка состояний) — ситуация, когда два запроса обрабатываются параллельно и результат зависит от порядка выполнения. Распространённый паттерн в приложениях с балансом, лимитами или квотами. Сервер проверяет: «Хватает средств?» — да. Начинает списание. Но если второй запрос прошёл ту же проверку до завершения первого — оба выполнятся. Результат: два списания при одном балансе. Деньги из воздуха, только наоборот — для бизнеса.
Тестирование: в Burp Intruder создай группу из 20 одинаковых запросов на покупку, установи Null payloads (20 итераций), подними количество потоков до 20 (Resource Pool → Create new → Maximum concurrent requests: 20). Если при балансе, достаточном для одной покупки, успешно прошли две — гонка подтверждена. Этот паттерн не покрывается стандартным OWASP чек-листом: каждый отдельный запрос полностью легитимен, проблема — в отсутствии блокировки на уровне транзакции.
Пропуск шагов многоэтапного процесса
Многошаговые процессы (регистрация, оплата, KYC-верификация) часто валидируют шаги только на клиенте через JavaScript. На сервере проверяется «пришёл ли запрос с правильными параметрами», но не «прошёл ли пользователь предыдущий этап».
Показательный пример из отчёта pentest-tools.com: веб-приложение транспортной компании использовало OTP (One-Time Password — одноразовый код подтверждения) для двухфакторной аутентификации. При запросе сброса пароля сервер возвращал валидный OTP прямо в теле HTTP-ответа, в параметре OriginalOTP. Тестировщику оставалось прочитать ответ и ввести код. Захват любого аккаунта, включая администраторские. Разработчик, видимо, добавил параметр для отладки и забыл убрать перед продом.
Тестирование: запиши последовательность запросов многошагового процесса. Затем отправь финальный запрос, минуя промежуточные. Если сервер вернул 200 OK вместо ошибки — шаги не валидируются на бэкенде.
Повышение привилегий через манипуляцию параметрами
Если роль пользователя определяется значением в cookie, скрытом поле или JWT без серверной перепроверки — это вектор Privilege Escalation (повышение привилегий). В MITRE ATT&CK это техника T1078 — Valid Accounts: использование действительных учётных данных для получения доступа, к которому аккаунт не предназначен. Тактики: Initial Access, Persistence, Privilege Escalation. По данным IBM X-Force Threat Intelligence Index 2025, атаки с использованием действительных учётных данных выросли на 71% за год — часть из них эксплуатирует не кражу паролей, а логические ошибки в разграничении ролей.
Конкретный кейс из pentest-tools.com: cookie содержало URL-кодированный JSON с полем usertype: "user". Замена значения на admin открывала дополнительные пункты меню: Advance Report, Tax Exemption, Users, Settings. Ни один автоматический сканер этого не обнаружил — потому что запрос выглядел абсолютно нормально.
Тестирование: декодируй cookie (URL-decode → Base64-decode → JSON-parse) и ищи поля, связанные с ролями: role, usertype, is_admin, permissions, access_level. Измени значение на привилегированное и отправь запрос. Если ответ содержит новую функциональность — серверная валидация роли отсутствует.
Как документировать находку в тестировании логики приложения
Логические баги сложнее описать в отчёте, чем технические. SQL-инъекция самоочевидна: вот payload, вот ответ с данными из БД. Для логической уязвимости нужно объяснить, почему нормальный на первый взгляд результат — это ошибка.
Структура, которая работает в отчётах:
- Бизнес-контекст — одно предложение о том, какой процесс затронут: «Система скидок позволяет применить промокод повторно, удвоив скидку».
- Предусловия — версия приложения, роль пользователя, начальное состояние (наличие баланса, активный промокод).
- Шаги воспроизведения — конкретные HTTP-запросы из Burp Suite, каждый с ожидаемым и фактическим результатом.
- Влияние на бизнес — не «Medium по CVSS», а «атакующий может покупать товары со скидкой 100%» или «чтение персональных данных 50 000 пользователей через перебор ID».
- Рекомендация — конкретное исправление: «Добавить серверную проверку однократного использования промокода в рамках заказа».
Описание бизнес-влияния превращает «интересную находку» в «критический баг, требующий немедленного исправления». Фраза «IDOR в API /api/orders» вызывает меньше реакции у заказчика, чем «неавторизованный доступ к истории заказов любого клиента, включая адреса доставки и состав покупок». Одна и та же уязвимость, но вторая формулировка — это разговор на языке бизнеса, а не на языке CVE.
Большинство отчётов по пентесту веб-приложений — вывод сканера, отформатированный в PDF. Чек-лист пройден, XSS в трёх полях найден, Reflected — Low, Stored — Medium, готово. Заказчик закрывает XSS, считает себя защищённым. Через полгода кто-то оформляет заказы с нулевой ценой через race condition в API оплаты.
Проблема не в инструментах и не в чек-листах — они делают ровно то, для чего созданы. Проблема в подходе: пока пентестер воспринимает задачу как «пройти список проверок», он будет находить только то, что нашёл бы сканер за него. Переход к abuse case мышлению — это смена оптики. Вместо «какую атаку я знаю» — «что конкретный пользователь может сделать, чтобы получить выгоду».
На реальных проектах самые дорогие находки — не технические баги с известной сигнатурой, а логические дыры, уникальные для конкретного приложения. Их невозможно обнаружить на автопилоте. Их находит пентестер, который потратил час на изучение бизнес-процессов перед тем, как открыть Intruder. Навык формируется через практику: первые лабы — по мануалу, это создаёт базу. Следующие — с вопросом «а что если я сделаю не как написано». Через двадцать-тридцать лаб этот вопрос задаётся рефлекторно. Если хочется выстроить эту базу системно, а не собирать по разрозненным статьям и writeup’ам — на IB Basics она закрывается за пару месяцев, без академического тона.
Эту тему и смежные навыки разбирают на практике в курсе «Тестирование веб-приложений на проникновение (WAPT)» Codeby Academy.