open atlas
↑ К треку
Наступательная безопасность RED · 01 · 04

Техники перечисления

Перечисление превращает неизвестную поверхность атаки в конкретный список целей — скрытые эндпоинты, реальные пользователи, недокументированные объекты API. Ровно это и призваны замедлить и выявить лимиты запросов и мониторинг.

RED Middle ◷ 15 min
Уровень
ОсновыJuniorMiddleSenior

Лабораторный стенд отвечает на POST /api/login двумя разными сообщениями: «аккаунта с таким email нет» и «неверный пароль». Безобидная формулировка — вот только скрипт теперь может скормить ему список из десяти тысяч email и за несколько минут оставить только те, что вернули «неверный пароль». Он только что подтвердил, у кого из ваших клиентов есть аккаунт, не угадав ни одного пароля. Это и есть перечисление: не взлом, а превращение неизвестной поверхности в точный, ранжированный список того, что стоит атаковать следующим. У формы входа не было бага в привычном смысле. Она просто сказала правду слишком конкретно — а защитник, понимающий перечисление, как раз и замечает, что ответ, тайминг и частота запросов все вместе утекают.

К концу урока вы будете знать, как атакующие перечисляют эндпоинты, пользователей и объекты API в авторизованной лаборатории и как именно лимиты запросов и мониторинг превращают это дешёвое, тихое прощупывание в медленную, дорогую, заметную операцию, которую защитник может поймать.

Сначала граница: только лаборатория, и перечисление — это разведка

Прежде всего о механиках: всё ниже рассчитано на систему, которой вы владеете или которую вам явно разрешено тестировать, — CTF-стенд, намеренно уязвимое приложение в вашей собственной VM, согласованный по объёму проект. Перечисление обращается к реальным эндпоинтам и реальным аккаунтам, поэтому без письменной авторизации и определённого scope это неавторизованный доступ, точка. Здесь нет вооружённых скриптов; цель — понять механизм достаточно глубоко, чтобы обнаруживать и притуплять его на системах, которые вы защищаете.

В последовательности атакующего перечисление — это разведка, первая тактика MITRE ATT&CK (TA0043). Само по себе оно не даёт пробоя. Оно даёт карту: какие пути существуют, какие имена пользователей реальны, какие объекты API можно назвать. Каждая последующая стадия дешевле и тише, потому что перечисление сузило поиск с «всего интернета» до «вот этих сорока вещей». Именно поэтому притупление перечисления имеет несоразмерно высокую защитную ценность — вы повышаете стоимость фундамента, на котором строится вся остальная атака.

Перечисление эндпоинтов: найти то, на что нет ссылок

Первая цель — структура. Карта сайта приложения показывает парадную дверь; перечисление ищет двери, на которые никогда не было ссылок, — /admin, /api/internal, /.git/config, /backup.zip, старую /v1, которую должны были вывести из эксплуатации. Техника — это перебор директорий и контента: берётся список частых путей и имён файлов, каждый запрашивается, и по HTTP-статусу и размеру ответа отличается «это существует» от «этого нет».

Сигнал, который читает атакующий, — это разница в ответах. Аккуратное приложение возвращает 404 на всё, чего нет. Дырявое возвращает 403 Forbidden на /admin (подтверждая, что путь существует, но защищён), 200 на /api/internal/users (существует и не защищён) и редирект 301, тихо раскрывающий реальный путь. Размер ответа важен не меньше статуса: типовая страница 404 имеет фиксированную длину, поэтому 404 с другой длиной часто оказывается реальной страницей в чужом статус-коде. Вся игра — в чтении этих признаков на тысячах запросов.

Перечисление пользователей и API: подтвердить, кто и что существует

Вторая цель — личности и объекты. Перечисление пользователей — это история формы входа из вступления: любое место, где приложение ведёт себя по-разному для реального и фальшивого аккаунта, — это оракул. Классические признаки — отдельное сообщение об ошибке («email не найден» против «неверный пароль»), другой HTTP-ответ и — самый тонкий — разница в тайминге. Если реальный аккаунт запускает дорогое хеширование пароля (bcrypt, argon2), а несуществующий возвращается мгновенно, потому что хешировать нечего, то одно лишь время ответа отделяет реальное от фальшивого даже при одинаковых сообщениях. Потоки регистрации и сброса пароля утекают так же («этот email уже зарегистрирован»).

Перечисление API обобщает это на объекты. REST API по адресу GET /api/orders/1001 напрашивается на вопрос: а что насчёт 1002, 1003, 1000000? Последовательные целочисленные ID позволяют атакующему пройти всю коллекцию простым счётом. Даже когда контроль доступа корректен и каждый запрос отклоняется, шаблон отказов размечает, какие ID существуют (403 на реальный, но запрещённый заказ, 404 на пробел), а подробные тела ошибок, утёкший документ OpenAPI/Swagger или introspection-запрос GraphQL выдают модель объектов целиком.

ЦельУтечка (оракул)Что узнаёт атакующийЗащитный фикс
ЭндпоинтыСтатус/размер различаются (404 vs 403 vs 200)Какие скрытые пути существуютЕдиный 404; deny by default; авторизация до маршрутизации
Пользователи (вход)Отдельное сообщение об ошибке или ответУ каких email есть аккаунтыОдинаковое общее сообщение для обоих случаев
Пользователи (тайминг)Реальный аккаунт хеширует, фальшивый отвечает мгновенноРеальный vs фальшивый по времени ответаХешировать фиктивный пароль и на ветке промаха
Объекты APIПоследовательные ID; раскол 403 vs 404Какие записи существуют и сколько ихСлучайные UUID; одинаковый статус для запрета и отсутствия
Форма APIПодробные ошибки, Swagger, introspection GraphQLПолную модель объектовОбщие ошибки; закрыть доки/introspection в проде
Почему это работает

Почему возврат одной и той же общей ошибки для «пользователь не найден» и «неверный пароль» реально помогает, если реальный атакующий всё равно может перебирать пароли? Потому что это меняет экономику. Без оракула атакующий вынужден разбрасывать учётные данные по неизвестному множеству аккаунтов — большинство попыток тратится на несуществующие email, и каждая впустую — это лишний шум для вашего лимитера и ваших алертов. С оракулом он сначала дёшево перечисляет валидные аккаунты, а затем нацеливает сфокусированную, более медленную атаку по паролям только на реальные цели. Закрытие оракула не останавливает атаку целиком; оно убирает дешёвый разведывательный шаг, который делал дорогой шаг эффективным, — а именно в этом и смысл срыва перечисления.

Что притупляет это: лимиты запросов и мониторинг

Определяющая слабость перечисления — объём. Подтверждение скрытых путей, валидных пользователей или объектов API требует от сотен до миллионов запросов, потому что атакующий ищет в пространстве, а не эксплуатирует одну известную брешь. Вот рычаг, за который тянут защитники.

Лимиты запросов бьют прямо по стоимости. Ограничьте запросы на IP, на аккаунт и на эндпоинт — и перебор, который должен был занять минуты, теперь занимает дни, достаточно долго, чтобы окно проекта закрылось или атакующий ушёл. Зрелый нюанс — где ограничивать: лимиты на IP тривиально обходятся ботнетом или ротацией прокси, поэтому высокоценные оракулы (вход, сброс пароля, эндпоинты токенов) нуждаются ещё и в лимитах на аккаунт и в глобальных потолках, плюс экспоненциальный backoff и CAPTCHA или proof-of-work на подозрительном пути. Лимиты редко делают перечисление невозможным; они делают его достаточно медленным, чтобы оно стало непрактичным, и достаточно громким, чтобы его заметили.

Мониторинг бьёт по скрытности. У перечисления есть отпечаток, которого нет у нормального трафика: один источник, генерирующий поток 404, прогон по последовательным ID, сотни неудачных входов по множеству имён пользователей или частота запросов, которую не выдаёт человек. Алертите на эти паттерны — всплески доли 4xx, доступ к путям или ID высокой кардинальности от одного клиента, всплески неудачной аутентификации — и вы обнаружите стадию разведки до того, как она перерастёт в эксплойт. Это выгода kill chain в миниатюре: перечисление — самая дешёвая, ранняя стадия атакующего, поэтому поймать её здесь — самое дешёвое, раннее место, чтобы разорвать цепочку.

Выбери лучший вариант

API входа возвращает «аккаунта с таким email нет» для неизвестных email и «неверный пароль» для реальных. Вы укрепляете его против перечисления пользователей. Выберите лучший фикс.

Викторина

Атакующий запрашивает тысячи угаданных путей и оставляет только те, что не вернули 404. Какое поведение сервера даёт ему больше всего сигнала?

Викторина

Почему лимиты запросов — настолько эффективный контроль именно против перечисления?

Расставь шаги по порядку

Упорядочьте авторизованную оценку перечислением от первого шага к последнему:

  1. 1 Подтвердить письменную авторизацию и scope для цели
  2. 2 Перечислить эндпоинты: перебрать пути, читать разницу статуса/размера
  3. 3 Перечислить пользователей и объекты API через оракулы сообщения/тайминга/ID
  4. 4 Ранжировать подтверждённую поверхность по эксплуатируемости для следующей стадии
  5. 5 Сообщить об оракулах и рекомендовать лимиты запросов + мониторинг
Вспомните перед уходом
  1. 01
    Объясните три главные цели перечисления — эндпоинты, пользователей и объекты API — и конкретный «оракул», который утекает информацию в каждой.
  2. 02
    Почему лимиты запросов и мониторинг — правильная защита против перечисления, и в чём зрелый нюанс о том, где применять лимиты?
Итог

Перечисление — это шаг разведки, превращающий неизвестную поверхность атаки в конкретный, ранжированный список целей: оно не взламывает, а сообщает атакующему, куда целиться следующим, — поэтому его притупление имеет несоразмерно высокую защитную ценность. У него три главные цели, у каждой свой утекающий оракул: эндпоинты, находимые перебором путей и чтением разницы HTTP-статуса и размера ответа по путям; пользователи, подтверждаемые через отдельные сообщения об ошибке или разницу в тайминге, когда реальный аккаунт запускает дорогое хеширование, а фальшивый отвечает мгновенно; и объекты API, проходимые через последовательные целочисленные ID и выдаваемые целиком подробными ошибками, утёкшими доками Swagger или introspection GraphQL. Всё это работает на объёме, поэтому защита идёт в два хода. Первый — убрать оракулы: возвращать единообразные ответы и общие ошибки, выровнять тайминг хешированием фиктивного пароля на ветке промаха, использовать случайные UUID вместо последовательных ID и закрывать доки API и introspection в проде. Второй — поднять стоимость и видимость: ограничить запросы на IP, на аккаунт и на эндпоинт — помня, что один лишь IP-лимит обходится ботнетами, так что высокоценным эндпоинтам нужны ещё лимиты на аккаунт и глобальные, — и мониторить безошибочный отпечаток перечисления: потоки 404, прогоны по последовательным ID и всплески неудачной аутентификации. Поймайте его на этой стадии — и вы разорвали kill chain на самом дешёвом, раннем звене. Теперь, проектируя эндпоинт, ваш рефлекс — спросить: что каждый ответ раскрывает о том, что существует, и насколько быстро кто-то может задать этот вопрос миллион раз?

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 6 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

Примени это

Примени этот урок в реальном проекте.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.