На последнем пентесте API финтех-сервиса одна подмена параметра
account_id в запросе GET /api/v2/transactions раскрыла историю транзакций чужого счёта - с реквизитами карты и суммами переводов. Разработчики были уверены: UUID v4 - достаточная защита от перебора. UUID утёк через эндпоинт поиска пользователей в поле id каждого результата. Два запроса, ноль WAF-алертов, severity P1.Это типичный IDOR - Insecure Direct Object Reference, он же BOLA (Broken Object Level Authorization, первая позиция в OWASP API Security Top 10, API1:2023). По CWE - CWE-639: Authorization Bypass Through User-Controlled Key. По данным OWASP Top 10 2021, 94% протестированных приложений содержат ту или иную форму broken access control (A01:2021). IDOR - самый массовый подтип этой категории, и причина простая: одна пропущенная проверка авторизации на уровне объекта раскрывает каждую запись в базе. Масштабируется моментально.
Дальше - конкретные паттерны горизонтальной и вертикальной IDOR-эскалации, техники обхода UUID и непрямых ссылок на объекты, разбор с реальными HTTP-запросами и workflow в Burp Suite.
Место IDOR-эскалации в цепочке атаки на API
IDOR - не самодостаточная атака. Понимание её позиции в kill chain определяет и стратегию эксплуатации, и оценку импакта в репорте.
Initial Access -> Аутентификация -> IDOR Exploitation -> Data Collection / Privilege Escalation -> Impact
На этапе initial access атакующий получает легитимную сессию: регистрация аккаунта, OAuth-авторизация, украденный токен. IDOR эксплуатируется уже после аутентификации. Проблема не в том, кто вы, а в том, что приложение не проверяет ваше право запрашивать конкретный объект. Вы уже внутри - и это принципиальное отличие от injection-атак или XSS.
Бизнес-логика атаки: атакующий регистрирует бесплатный аккаунт, находит IDOR в API заказов и за час выгружает полную базу клиентов с платёжными данными. Финансовый импакт - штрафы за утечку ПД, репутация в минус, прямой ущерб клиентам. Или: через вертикальный IDOR атакующий повышает свою роль до администратора и получает контроль над всей платформой.
В терминологии MITRE ATT&CK IDOR-эксплуатация маппится на несколько техник в зависимости от результата:
| Действие через IDOR | Техника ATT&CK | Тактика |
|---|---|---|
| Перечисление пользователей через подмену ID | Account Discovery (T1087) | Discovery |
| Массовое вытягивание данных | Data from Information Repositories (T1213) | Collection |
| Модификация чужих данных (email, phone) | Data Manipulation (T1565) | Impact |
| Эскалация до admin через role_id | Valid Accounts (T1078) | Privilege Escalation |
[Применимо: внешний и внутренний пентест] IDOR работает и на public API, и на internal microservices. Разница существенная: на внешнем пентесте вы ограничены public-facing endpoints и rate limiting-ом; на внутреннем - часто получаете доступ к internal API без ограничений и с минимальным логированием. Массовая эксплуатация на внутреннем API - дело десяти минут.
Горизонтальная и вертикальная эскалация IDOR: паттерны эксплуатации
Русскоязычные источники обычно останавливаются на определении: горизонтальная - тот же уровень привилегий, вертикальная - переход выше. На практике различие глубже: разные точки входа, разные эндпоинты, разный подход к эксплуатации.Горизонтальная эскалация привилегий: где живёт IDOR в современных API
ОчевидныеGET /api/users/123 разработчики давно закрыли. Уязвимость переместилась в менее заметные места. Паттерны, которые реально встречаются на bug bounty:Тело POST/PUT-запросов. Эндпоинт
PUT /api/profile принимает JSON с полем "user_id": 4521. Сервер берёт user_id из тела запроса вместо сессии. Меняете на 4522 - обновляете чужой профиль. Подтверждение: зайдите под Victim и проверьте, что данные реально изменились.Составные ключи в query-параметрах. Запрос
GET /api/org/15/team/3/member/42 проверяет принадлежность к организации 15 и команде 3, но не проверяет, что member 42 - это вы. Подмена последнего параметра раскрывает данные другого участника.HTTP-заголовки. Некоторые API-шлюзы передают identity через
X-User-Id или X-Account-Id. Если backend доверяет заголовку без перепроверки токена сессии - прямой IDOR через подмену заголовка. На одном проекте мы именно так вытянули данные 12 000 аккаунтов - API Gateway проксировал X-Account-Id "как есть".Файловые пути. URL вида
/uploads/user_4521/passport.pdf - замена 4521 на 4522 отдаёт чужой документ. Это IDOR, скомбинированный с path traversal. По описанию PortSwigger, IDOR с прямыми ссылками на статические файлы - частый вектор при доступе к чат-логам, документам и конфигурациям.GraphQL-переменные. В GraphQL идентификатор передаётся как переменная, а вложенность объектов создаёт дополнительные точки подмены:
Код:
query {
user(id: "victim-uuid") {
email
orders { id, total, shippingAddress }
}
}
user, но не на уровне вложенного orders, атакующий получает заказы жертвы. Batched queries в GraphQL позволяют отправить десятки запросов с разными ID в одном HTTP-запросе, обходя per-request rate limiting.[Ограничение: GraphQL-интроспекция отключена в продакшене у зрелых команд. Если
__schema возвращает ошибку - поиск IDOR-точек требует ручного анализа клиентского JS-кода]Ключевой сигнал при тестировании: сравнивайте не только статус-код, но и размер response body. Если запрос с несуществующим ID возвращает body одного размера, а с существующим чужим ID - другого, данные утекают, даже если визуально ответ похож на generic error. Этот приём сэкономит часы.
Вертикальная эскалация через IDOR: role_id и admin-эндпоинты
Вертикальный IDOR встречается реже, но его severity всегда P1. Типичные паттерны:Числовой role_id в запросе обновления. Запрос
PUT /api/users/me принимает "role_id": 2 (обычный пользователь). Замена на "role_id": 1 (admin) повышает привилегии, если сервер не валидирует право пользователя менять свою роль. Это частный случай BOPLA - Broken Object Property Level Authorization (API3:2023 в OWASP API Security Top 10), где приложение позволяет модифицировать свойства объекта, к которым у пользователя не должно быть доступа.Подмена user_id на ID администратора. Если admin-аккаунт имеет ID
1 (auto-increment - встречается постоянно), запрос GET /api/admin/dashboard?user_id=1 может вернуть админские данные обычному пользователю. Вертикальный IDOR часто живёт именно в admin-эндпоинтах, где проверка авторизации реализована на уровне UI (кнопка скрыта), а на уровне API - пусто.JWT payload с role claim. Приложения, хранящие
role в JWT payload без серверной перепроверки, уязвимы к модификации токена. При слабом алгоритме подписи (alg: none, HMAC вместо RSA) атакующий меняет "role": "user" на "role": "admin". Пересечение с техникой Valid Accounts (T1078, Privilege Escalation).[Применимо: внешний и внутренний пентест. На внутреннем пентесте вертикальный IDOR чаще обнаруживается в internal admin API, которые разработчики считают "скрытыми" за VPN и не защищают проверками авторизации]
Обход UUID и непрямых ссылок на объекты
Разработчики регулярно считают UUID v4 защитой от IDOR. Пространство UUID v4 - 2^122 значений, перебор невозможен. Но IDOR - не атака перебором. Как точно формулирует Zeriflow: "UUIDs reduce discoverability - an attacker can't guess the next ID. But if the application still doesn't check authorization, a UUID endpoint is still vulnerable.""UUID уменьшает исследовательность - атакующие не могут указать следующий ID. Но если приложение всё ещё не проверяет авторизацию, UUID всё ещё уязвим."
UUID - это замок на стеклянной двери. Красиво, но бесполезно, если ключ валяется рядом.
Где утекают UUID на реальных пентестах
- Response body других эндпоинтов. Поисковый запрос
GET /api/users/search?q=johnвозвращает список пользователей с UUID в полеid. Атакующий использует полученный UUID вGET /api/users/{uuid}/documents. Два запроса - один легитимный (поиск), второй с подменой контекста. - Referer-заголовки. Страница профиля с UUID в URL (
/profile/3f5c2e8a-...) при наличии внешних ресурсов (аналитика, CDN, пиксели ретаргетинга) утекает черезRefererв логи третьих сторон. На одном из пентестов UUID пользователей утекал через Google Analytics - профиль содержал embed-скрипт, и вся "защита через непредсказуемость" пошла к чертям. - Публичные ссылки и функции sharing. Функция "поделиться документом" генерирует ссылку с UUID документа. Этот UUID далее используется для прямого доступа через API без проверки авторизации - разработчик предполагал, что "ссылку знает только тот, кому отправили". Знакомая логика?
- Verbose error messages. Stack trace или debug-вывод может раскрыть UUID объектов. Подпадает под Security Misconfiguration (A05:2021) и часто встречается в staging-окружениях, доступных из интернета.
Обход indirect object reference maps
Indirect reference map - защитный паттерн, при котором клиент получает не реальный database ID, а сессионный маппинг. ВместоGET /api/orders/5291 клиент видит GET /api/orders/a8f3e2b1, а сервер внутри сессии маппит a8f3e2b1 на реальный ID.Обход возможен в нескольких сценариях:
- Маппинг общий, а не per-session. Если
a8f3e2b1разрешается в5291для всех пользователей, атакующий получает чужой маппинг через другой эндпоинт. - Маппинг детерминистический. Если indirect reference вычисляется как
md5(user_id + object_id)- при знании алгоритма маппинг воспроизводится. Видел такое в продакшене дважды. - Маппинг утекает. Та же проблема, что с UUID: indirect reference может появиться в search-эндпоинтах, email-нотификациях, response body.
Практическая эксплуатация IDOR: workflow и ограничения
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Scope query в ORM. Фреймворки вроде Django REST Framework с
django-guardian проверяют ownership на уровне SQL-запроса: WHERE id = ? AND user_id = ?. Подмена ID в параметрах возвращает пустой результат. Это правильный подход - и он убивает IDOR на корню.Server-side identity resolution. Если сервер полностью игнорирует
user_id из запроса и берёт его из JWT/session - подмена бессмысленна.Anomaly detection. Массовый перебор ID генерирует характерный паттерн: один пользователь запрашивает сотни объектов за короткий период. В SigmaHQ есть правило
web_multiple_susp_resp_codes_single_source.yml, детектирующее множественные подозрительные коды ответа от одного источника - косвенный индикатор IDOR-перебора. С точки зрения D3FEND, защита строится через Access Modeling (D3-AM) и Network Resource Access Mediation (D3-NRAM).Большинство IDOR-репортов на HackerOne содержат одну и ту же ошибку: хантер показывает подмену ID и останавливается. Триажер ставит P3, выплата минимальная.
Реальная ценность IDOR-находки - не в факте подмены, а в цепочке. Горизонтальный IDOR на чтение email позволяет инициировать password reset на подконтрольный ящик - и вот у вас account takeover. Вертикальный IDOR через подмену
role_id открывает admin API и массовый экспорт данных. Один изолированный IDOR - P3 за минимальную выплату. Цепочка IDOR -> ATO - P1.Индустрия продолжает учить IDOR как "замени число в URL", а не как точку входа в атаку на бизнес-логику. Пока разработчики надеются на UUID вместо серверной авторизации, а хантеры останавливаются на первом подтверждении вместо построения цепочки - обе стороны недорабатывают. API-first архитектуры сделают BOLA-уязвимости ещё массовее, и application-layer authorization станет таким же обязательным элементом, как TLS. Те, кто сейчас тренируется строить цепочки от единичного IDOR до full compromise, будут задавать стандарт пентестов. Если хотите отработать эту связку - на курсе WAPT цепочку IDOR -> ATO разбирают в отдельном модуле с лабами.
Последнее редактирование модератором: