Одна подмена параметра в API-запросе - и ты читаешь чужие паспортные данные, скачиваешь чужие документы или переназначаешь чужой проект на свой аккаунт. IDOR уязвимость - пожалуй, самый недооценённый класс проблем в bug bounty. Автоматические сканеры её не ловят, WAF не блокирует, а разработчики продолжают верить, что клиентская валидация и скрытые поля формы - достаточная защита. На словах всё выглядит надёжно.
У меня IDOR - стабильный источник выплат от нескольких сотен до нескольких тысяч долларов за один репорт. А если удаётся построить цепочку от простого чтения чужих данных до Account Takeover, сумма вырастает кратно. По публикациям исследователей из Deteact, только за несколько описанных ими кейсов IDOR было выплачено более $25 000 - а реальный ущерб от действий злоумышленника многократно превысил бы эту сумму.
Дальше - полный цикл работы с IDOR в bug bounty: от природы уязвимости до написания репорта, который оценят на P1. Без абстрактных определений - конкретные HTTP-запросы, инструменты и логика мышления, которая отличает результативного хантера от человека, месяцами получающего дубликаты.
IDOR уязвимость - что это и чем отличается от BOLA
Insecure Direct Object Reference - ситуация, когда приложение берёт пользовательский ввод (ID в URL, параметр в теле запроса, заголовок) и напрямую лезет с ним в базу данных, не проверяя, имеет ли текущий пользователь право доступа к этому объекту.Классическое объяснение: запрос
GET /api/documents/1234 возвращает документ с ID 1234. Замени на GET /api/documents/1235 - получи чужой документ. Это IDOR. Но такое объяснение создаёт ложное ощущение простоты и загоняет мышление хантера в рамки. IDOR - это не только подмена числа в URL.В терминологии OWASP API Security Top 10 та же проблема называется BOLA - Broken Object Level Authorization. Первая позиция в рейтинге API-угроз, и название точнее бьёт в суть: проблема не в «прямой ссылке на объект» (объекты так и должны адресоваться), а в отсутствии проверки авторизации на уровне конкретного объекта. Когда пишешь репорт, понимание этой разницы критично:
- IDOR - термин из классического OWASP Top 10 (впервые выделен в 2007 году как категория A4). Привычен широкому кругу разработчиков и триажеров.
- BOLA - термин из OWASP API Security Top 10. Используй его при тестировании API-first приложений - триажеры на HackerOne и Bugcrowd знают эту классификацию и воспринимают репорт серьёзнее.
Маппинг IDOR на MITRE ATT&CK - штука условная. ATT&CK описывает поведение атакующих в корпоративных сетях, а IDOR - application-layer logic bug (CWE-639, OWASP API1:2023 BOLA). С оговорками, эксплуатацию IDOR можно соотнести с техникой Exploit Public-Facing Application (T1190, Initial Access), а последствия - с Account Discovery (T1087, Discovery) при перечислении пользователей и Data from Information Repositories (T1213, Collection) при массовом вытягивании данных.
Классификация IDOR по импакту - от утечки данных до захвата аккаунта
Не каждая IDOR уязвимость стоит одинаково. Триажеры оценивают импакт, и от него зависит, получишь ты $200 или $5000. Я делю IDOR по двум осям: тип операции и направление эскалации привилегий.По типу операции:
- Чтение (Read) - несанкционированный доступ к чужим данным. Самый частый тип. Профили, документы, история транзакций. P3–P2 в зависимости от чувствительности данных.
- Изменение (Write) - модификация чужих данных. Смена email, номера телефона, настроек аккаунта. P2–P1, потому что тут возможна Data Manipulation (T1565, Impact).
- Удаление (Delete) - удаление чужих объектов. Файлы, проекты, целые аккаунты. P2–P1.
- Создание (Create) - создание объектов от имени другого пользователя. Спам, финансовые потери, подрыв репутации.
- Горизонтальная эскалация привилегий - доступ к данным пользователя с тем же уровнем привилегий. Пользователь A читает данные пользователя B. Классический IDOR.
- Вертикальная - доступ к данным или функциям более привилегированного пользователя. Обычный юзер лезет в админ-панель. Это уже ближе к полноценному Privilege Escalation и технике Valid Accounts (T1078).
PUT /api/users/{id}, добавление чужого проекта в свою группу с получением контроля, подключение чужого менеджера к своему аккаунту.Понимание этой классификации - то, что отличает репорт на $300 от репорта на $3000 за одну и ту же техническую уязвимость.
Как найти IDOR уязвимость - пошаговая методология
Поиск IDOR - это не слепой перебор числовых ID в URL. Это системный процесс с чёткими шагами, который повторяется на каждой программе.Требования к окружению
Перед началом подготовь рабочее место:- Burp Suite Pro (Community подойдёт для обучения, но без Autorize работать тяжело). Версия 2024.x и выше с поддержкой HTTP/2.
- Два браузера или два профиля в одном - для работы с двумя тестовыми аккаунтами одновременно.
- Расширение Autorize - ставится через BApp Store в Burp Suite.
- Param Miner (BApp Store) - для обнаружения скрытых параметров.
- Текстовый файл для маппинга - записывай каждый эндпоинт и найденные в нём идентификаторы.
Маппинг эндпоинтов и подготовка тестовых аккаунтов
Первый шаг - создать два аккаунта в целевом приложении. Назовём их Attacker и Victim. У каждого должны быть свои данные: документы, проекты, настройки, платёжная информация. Чем больше сущностей создашь - тем больше эндпоинтов увидишь в логах Burp.Залогинься под Victim и пройди по всем функциям приложения с включённым Burp Proxy. Задача - собрать полную карту API. Обращай внимание на каждый параметр, который пахнет идентификатором объекта:
- Числовые ID:
user_id=4521,document_id=89012 - UUID:
order=3f5c2e8a-29d7-4b05-a7d3-6e4f2a5b0001 - Slug или имя:
project=my-secret-project - Составные ключи:
org_id=15&team_id=3&member_id=42
Систематическая подмена параметров в Burp Suite
Теперь залогинься под Attacker и начни подставлять идентификаторы объектов Victim в каждый запрос. Гони модифицированные запросы через Burp Repeater и внимательно сравнивай ответы.Ключевые сигналы обхода авторизации:
- HTTP 200 с чужими данными - классический IDOR на чтение. Подтверди, что в теле ответа именно данные Victim, а не Attacker.
- HTTP 200 после PUT/PATCH с чужим ID - IDOR на запись. Проверь, что данные Victim реально изменились (зайди под Victim и посмотри).
- HTTP 200 вместо ожидаемого 403/404 - сервер вообще не проверяет авторизацию для этого эндпоинта.
- Разный размер ответа - если запрос с чужим ID возвращает body одного размера, а запрос с заведомо несуществующим ID - другого, данные утекают, даже если визуально ответ похож на ошибку.
"owner_id", "assigned_to", "parent_id"), в HTTP-заголовках (X-User-Id, X-Account-Id), в cookie-значениях, в GraphQL-переменных (query { user(id: "victim_id") { email } }), в файловых путях (/uploads/user_4521/passport.pdf - попробуй user_4522).Деталь, которая спасает от бана: некоторые программы прямо указывают, какие ID использовать для тестирования IDOR. Программа MAX на Standoff 365 рекомендует Profile IDs 10371924 и 10346997 для проверки IDOR в сервисе «MAX для бизнеса». Всегда читай scope и правила программы.
Поиск IDOR в API - паттерны, которые пропускают сканеры
DAST-инструменты заточены на поиск инъекций и XSS. Уязвимости авторизации для них - слепая зона, потому что обнаружение требует понимания контекста. Вот паттерны object reference manipulation, на которые стоит смотреть в первую очередь.Предсказуемые числовые ID. Если приложение использует инкрементальные integer-идентификаторы - это подарок. Перебор
GET /api/orders/10001, 10002, 10003 позволяет массово собирать данные. По данным Huntress, последовательные запросы file.php?id=1, file.php?id=2, file.php?id=3 от одного источника - ключевой индикатор компрометации. Учитывай, что некоторые программы явно исключают перебор инкрементальных идентификаторов из скоупа - MAX на Standoff 365 не принимает такие репорты для ряда функций.UUID, которые утекают. Разработчики считают, что UUID нельзя подобрать - и формально правы. Но UUID жертвы часто валяется в других местах: публичные профили, ответы API на поисковые запросы, WebSocket-сообщения, JS-код фронтенда. Как отмечают исследователи из Deteact, на практике «почти всегда получалось найти способы узнать ID жертвы» - например, через публичную страницу проекта, где идентификатор торчал в JSON-данных внутри HTML-кода.
Вложенные объекты в REST API. Эндпоинт
GET /api/organizations/15/users/42/documents/789 проверяет, что пользователь 42 принадлежит организации 15. Но проверяет ли он, что документ 789 принадлежит именно пользователю 42? Тестируй каждый уровень вложенности отдельно - подменяй по одному идентификатору за раз.Mass Assignment как путь к IDOR. Запрос
PUT /api/profile с телом {"name": "New Name"} может принимать и неочевидное поле "user_id": 9999 или "role": "admin". Результат - несанкционированный доступ к чужим объектам или повышение привилегий. На одном из публичных кейсов эндпоинт обновления профиля принимал поле "balance", позволяя произвольно менять баланс аккаунта. Красота.Разные HTTP-методы на одном эндпоинте.
GET /api/users/42 возвращает 403 - отлично, access control работает. А DELETE /api/users/42? А PATCH? Разработчики часто прикручивают проверку авторизации только для GET, забывая про остальные методы. Проверяй каждый метод на каждом эндпоинте - у меня не раз срабатывало именно на DELETE.Autorize и автоматизация проверок broken object level authorization
Ручная подмена ID в каждом запросе через Repeater - рабочий метод, но катастрофически медленный на приложениях с сотнями эндпоинтов. Autorize - расширение для Burp Suite, которое автоматизирует проверку авторизации.Принцип работы: ты ходишь по приложению в браузере от имени low-privilege пользователя (Attacker), а в Autorize подгружаешь cookie или токен другого пользователя (Victim). Каждый запрос Attacker Autorize автоматически повторяет с токеном Victim и без токена вовсе (unauthenticated), сравнивая ответы. Если ответы совпадают - авторизация не работает. Включай оба режима - второй часто выявляет публично доступные API-эндпоинты, о которых разработчики даже не подозревают.
Настройка занимает пару минут. Открываешь вкладку Autorize в Burp, в поле «Authorization enforcement headers» вставляешь cookie или заголовок
Authorization: Bearer <victim_token>. Ставишь фильтры, исключив статику (.js, .css, .png), чтобы не засорять результаты. Начинаешь работать с приложением от имени Attacker в браузере - Autorize параллельно дублирует каждый запрос с токеном Victim и без токена.Autorize показывает три статуса для каждого перехваченного запроса:
| Статус | Цвет | Что означает | Действие |
|---|---|---|---|
| Bypassed | Красный | Ответ с подменённым токеном идентичен оригинальному - авторизация обойдена | Потенциальный IDOR, проверяй немедленно |
| Enforced | Зелёный | Сервер вернул 403/401 | Авторизация работает корректно |
| Is enforced??? | Оранжевый | Ответы отличаются, но не очевидно, заблокирован ли доступ | Требует ручного анализа |
Красные строки - кандидаты на репорт. Открывай каждую, сравнивай тела ответов, подтверждай наличие чужих данных.
Autorize не заменяет ручной анализ. Он пропускает случаи, где IDOR требует подмены ID в теле запроса (расширение меняет только заголовки), и не понимает сложную бизнес-логику. Но для первичного прогона двух-трёхсот эндпоинтов за одну сессию - незаменим.
Для точечной проверки конкретного эндпоинта - кастомный скрипт на Python:
Python:
import requests, time
url = "https://target.com/api/documents/{}"
cookies = {"session": "attacker_session_token"}
for doc_id in range(1000, 1100):
try:
r = requests.get(url.format(doc_id), cookies=cookies, headers={"User-Agent": "Mozilla/5.0"}, timeout=10)
except requests.RequestException as e:
print(f"[ERR] doc {doc_id}: {e}")
continue
if r.status_code == 200 and len(r.text) > 50:
print(f"[IDOR] doc {doc_id}: {r.text[:80]}")
time.sleep(0.25) # rate limit - учитывай, что лимит считается суммарно по аккаунту (включая браузер)
time.sleep(0.25) обязательна - программа MAX на Standoff 365 рекомендует ограничивать сканирование четырьмя запросами в секунду. Превышение лимита приводит к автоматической блокировке аккаунта. Потерять доступ к программе из-за жадного скрипта - обидно.Реальные кейсы IDOR с выплатами - разбор цепочек атак
Теория хороша, но деньги платят за реальные находки. Разберём примеры IDOR атак из публичных источников - разные подходы к эксплуатации, разные суммы.
🔓 Эксклюзивный контент для зарегистрированных пользователей.
IDOR в управлении проектами - захват через Enterprise-группу
Кейс описан исследователями из Deteact. Сервис с тарифными планами имел функцию Enterprise-группы, куда можно было добавлять проекты. IDOR обнаружился сразу в двух эндпоинтах.При добавлении проекта: POST-запрос с JSON-телом содержал имя проекта - публично доступное значение. Подставив имя чужого проекта, атакующий добавлял его в свою Enterprise-группу и получал полный контроль.
При удалении проекта: запрос передавал сериализованное описание группы, из которого предварительно удалялся идентификатор ненужного проекта. Атакующий мог подменить ID оставшегося проекта на ID чужого. Сложность: идентификатор был случайным, не инкрементальным - но исследователь нашёл его в JSON-коде публичной страницы проекта, доступной через фронтенд.
Этот кейс идеально показывает, почему UUID сам по себе не защита от IDOR. Реальная защита - серверная проверка авторизации на каждом запросе, без исключений.
Цепочка Improper Access Control + IDOR = Account Takeover
Второй кейс из того же исследования - классический chaining, когда две уязвимости средней критичности вместе дают критический импакт.Первая уязвимость - неправильная настройка доступов (Improper Access Control), позволявшая просматривать чужие проекты и привязанных к ним менеджеров вместе с их идентификаторами. Сама по себе - утечка информации, P3–P4.
Вторая - IDOR в эндпоинте сохранения профиля, позволявший подключить чужого менеджера к своему аккаунту по его ID. Результат цепочки: полный доступ к данным менеджера и его проекту, включая чтение и редактирование. Две «средних» уязвимости превратились в одну критическую.
Отдельно стоит упомянуть публичный репорт на HackerOne (#863983), тоже описанный Deteact. Уязвимость позволяла получить доступ к данным более миллиона водителей: паспорта, водительские удостоверения. Через захват аккаунта партнёра-таксопарка атакующий мог изменять данные водителей, зарегистрированных через этого партнёра. Data from Information Repositories (T1213, Collection) в чистом виде - массовый доступ к хранилищу конфиденциальных документов через одну логическую ошибку.
Суммарно за описанные кейсы, по данным Deteact, было выплачено более $25 000.
Маппинг атак на MITRE ATT&CK
Для тех, кто пишет репорты для корпоративных программ с требованием маппинга:| Этап атаки | Техника ATT&CK | Тактика |
|---|---|---|
| Эксплуатация IDOR через веб-интерфейс | Exploit Public-Facing Application (T1190)* | Initial Access |
| Перечисление пользователей перебором ID | Account Discovery (T1087) | Discovery |
| Массовая выгрузка документов | Data from Information Repositories (T1213) | Collection |
| Доступ к облачным объектам через IDOR | Data from Cloud Storage (T1530) | Collection |
| Изменение/удаление чужих данных | Data Manipulation (T1565) | Impact |
\* T1190 применима условно: в строгом смысле ATT&CK описывает получение initial access к инфраструктуре (RCE, auth bypass). Для IDOR в аутентифицированной сессии маппинг корректен только при вертикальной эскалации (доступ к админ-функциям/инфраструктуре), а не при горизонтальном доступе к данным пользователя того же уровня.
Заведи себе привычку: нашёл IDOR - не беги сразу писать репорт. Покрути эндпоинт ещё. Попробуй другие HTTP-методы, поищи связанные эндпоинты, проверь, нет ли Mass Assignment. Одна IDOR на чтение - $500. Цепочка из IDOR + Improper Access Control с выходом на Account Takeover - $5000+. Разница в часе дополнительной работы. Потренировавшись на нескольких программах, начинаешь видеть эти цепочки почти автоматически. Попробуйте взять любое приложение из скоупа HackerOne с широким API - и пройтись по методологии из этой статьи. Готов поспорить, оранжевые строки в Autorize появятся быстрее, чем вы думаете.
Вопрос к читателям
Коллеги, кто работает с Autorize в Burp Suite Pro 2024.x на приложениях с JWT-авторизацией - как вы настраиваете «Authorization enforcement headers», когда токен Victim передаётся одновременно вAuthorization: Bearer и в httpOnly-cookie? Autorize по умолчанию подменяет только то, что вы явно указали в поле заголовков, и при двойной схеме часто даёт ложный Enforced - сервер валидирует cookie, игнорируя подменённый Bearer. Какой workaround используете: модифицируете Match/Replace в Burp для перезаписи cookie-значения параллельно с заголовком, или переходите на ручной Repeater-пайплайн для таких эндпоинтов? Особенно интересует связка с вложенными REST-эндпоинтами типа /api/organizations/{org_id}/users/{user_id}/documents/{doc_id} - как тестируете каждый уровень вложенности без взрывного роста ложных срабатываний?
Последнее редактирование модератором: