Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
SecretsStalker — Оценка учётных данных приложений Entra ID в режиме только для чтения: перечисляет разрешения Graph, Azure RBAC и доступные облачные данные, затем сопоставляет полученные результаты с путями повышения привилегий и латерального перемещения. | Kitploit
Инструменты/GitHubGitHub/rootsecdev/secretsstalker
Аутентификация и авторизацияБезопасность облачной инфраструктурыПовышение привилегийРазведкаЛатеральное перемещениеПост-эксплуатацияТестирование на ПроникновениеБезопасность облачных средУправление идентификацией и доступом (IAM)Red Teaming
GitHub
18111 месяц назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
rootsecdev/secretsstalker

SecretsStalker

Оценка учётных данных приложений Entra ID в режиме только для чтения: перечисляет разрешения Graph, Azure RBAC и доступные облачные данные, затем сопоставляет полученные результаты с путями повышения привилегий и латерального перемещения.

Репозиторий

secret_stalker```


/ / ______ ___ ___ / /_ / / / /__ _ / / /_____ ____ \ / -) / -) -)/ / \ \ / __/ _ `// / '/ -) / //_/_/_/_/ _/ // _/_,////_\__/_/

root@kitploit:~
     ╔╦╦╬╬╬╬╬╬╦╦╗
 ╔╬╬╬╝╝┘      ╚╝╝╬╬╬┐
╬╬╝╚╩╬╗╔          ╚╬╬╬

╬╝ ╚╬╬╗╗ ╔ ╚╬╗ ╬╬ ╔╗ ╚╬╬╬╬╬╬╦ ╬╬ we found your secret... ╔╬┤ ╬╬╬ ╬╬╬╬╬╬╬╬╝╝╝╬╬╗ ...now let's see what it ╬╬┤ ╚╩┘ ╚╬╬╬╬╬╩ ╠╬╬ can REALLY do. ( o_o)>=|= ╬╬┤ ╠╬╬ ╬╬ ╦╗ ╗╗ ╬╬ [ client_id + secret -> total recall ] └╬┐ ╚╬╗╗ ╔╬╬╝ ╔╬┘ └╬╗ ╚╩╩╬╬╬╩╩╝╝ ╔╬╬ ╚╬╬╬╗ ┌╗╬╬╝┘ ╚╩╬╬╬╦╦╦╦╦╦╬╬╬╝╝ ╚╚╝╝╝╝ // pst... that app registration talks too much. \

root@kitploit:~
**Что на самом деле может делать этот client ID + секрет Entra ID?**

Вы нашли учётные данные приложения Entra ID (Azure AD) — client ID и секрет —
в рамках авторизованного тестирования, и тенант, к которому они относятся, входит в область действия.
`secret_stalker` принимает эти два значения и сообщает вам с нуля:

1. **Действительны ли учётные данные, и когда истекает срок действия секрета?** — а если нет, *почему*
   (неверный секрет, истёкший секрет, приложения нет в тенанте…). Для действительного секрета
   он читает `passwordCredentials` регистрации приложения и сообщает дату
   истечения + оставшиеся дни (требуется чтение каталога; см. примечание ниже).
2. **Какими правами Microsoft Graph оно обладает?** — разрешения приложения, считываемые
   напрямую из выданного токена, плюс **роли каталога Entra**, которыми оно владеет (даже
   пассивно обнаруживаемые по утверждению `wids` в токене), и **объекты, которыми оно владеет**
   (приложения/субъекты-службы, к которым можно добавить учётные данные).
3. **Какой контроль над Azure оно имеет?** — назначения ролей RBAC на уровне
   группы управления и подписки.
4. **Может ли оно добраться до реальных данных?** — опциональные проверки достижимости в плоскости данных
   Key Vault (секреты / ключи / сертификаты),
   Storage (blob / файл / очередь / таблица) и Cosmos DB.
5. **Каково влияние?** — опасные разрешения, роли, владение и достижимые данные,
   сопоставленные с известными примитивами повышения привилегий / бокового перемещения,
   оценённые по степени серьёзности, с конкретными описаниями **путей атак**.

Оно аутентифицируется либо с помощью **секрета клиента**, либо **сертификата** (`--cert`),
и работает с **коммерческими и суверенными облаками** (`--cloud`).

Оно **пассивно по умолчанию** и **никогда ничего не изменяет** — только перечисление в режиме чтения.

> ⚠️ **Только авторизованное тестирование.** Запускайте его исключительно против тенантов,
> явно входящих в область действия задания, на проведение которого вы авторизованы.

---

## Установка```bash
pip install -r requirements.txt        # just runs it from source
#   — or —
pip install .                          # installs the `secret_stalker` command
pip install '.[cert]'                  # + certificate (--cert) auth support
pip install '.[dev]'                   # + pytest for the test suite

The only runtime dependency is requests. Tokens are decoded locally (base64 + JSON) — no signature verification, no crypto library, no Microsoft SDK. The one exception is certificate auth (--cert), which needs the optional cryptography package to sign the JWT client assertion. Requires Python 3.7+.

After pip install . you can invoke it as secret_stalker … instead of python -m secret_stalker ….


Быстрый старт

Самый быстрый способ узнать, что могут учётные данные:```bash python -m secret_stalker
--tenant contoso.onmicrosoft.com
--client-id 11111111-2222-3333-4444-555555555555
--secret ''

root@kitploit:~
`--tenant` принимает либо GUID тенанта, либо домен — домен автоматически преобразуется в
его идентификатор тенанта через публичную конечную точку конфигурации OpenID.

### Не оставляйте секрет в истории вашей оболочки

Передавайте учетные данные через переменные окружения вместо флагов:```bash
export SS_TENANT=contoso.onmicrosoft.com
export SS_CLIENT_ID=11111111-2222-3333-4444-555555555555
export SS_SECRET='<client-secret>'

python -m secret_stalker

Любой из --tenant / --client-id / --secret может браться из SS_TENANT / SS_CLIENT_ID / SS_SECRET. Флаги имеют приоритет над окружением.

Дело не только в истории shell: значение argv доступно для чтения любому локальному пользователю в течение всего времени жизни процесса (ps, /proc/<pid>/cmdline). Если --secret или --cert-password передаётся как флаг, инструмент выводит однострочное напоминание в stderr — оно никогда не появляется в выводе --json или --export.

Аутентификация с помощью сертификата вместо секрета

Регистрации приложений часто используют сертификат, а не секрет. Передайте --cert (PEM-файл, содержащий закрытый ключ и сертификат, или .pfx/.p12), и инструмент выполнит аутентификацию с помощью подписанного JWT-клиентского утверждения:```bash python -m secret_stalker --tenant contoso.onmicrosoft.com
--client-id --cert ./app.pem # or app.pfx

encrypted key / PFX:

python -m secret_stalker ... --cert app.pfx --cert-password ''

root@kitploit:~
Аутентификация по сертификату требует опциональный пакет `cryptography` (`pip install '.[cert]'`).
Инструмент сообщает о сроке действия самого сертификата (сопоставленного по его отпечатку в
`keyCredentials` приложения) так же, как и для секрета. `--cert`/`--cert-password`
также читаются из `SS_CERT` / `SS_CERT_PASSWORD`.

### Суверенные и государственные облака

По умолчанию secret_stalker нацелен на **коммерческое** облако. Для суверенных тенантов
передайте `--cloud` (или `SS_CLOUD`), чтобы центр авторизации Entra и конечные точки Graph / ARM / Key
Vault совпадали — иначе действительные учётные данные будут выглядеть так, будто у них нет доступа:```bash
# US Government (GCC High)
python -m secret_stalker --cloud usgov  --tenant contoso.onmicrosoft.us ...

# US DoD (L5)
python -m secret_stalker --cloud usdod  ...

# Azure operated by 21Vianet (China)
python -m secret_stalker --cloud china  --tenant contoso.partner.onmschina.cn ...

Принимаются такие псевдонимы, как gov, dod, commercial, gcc-high и 21vianet. (Аудитория плоскости данных Storage, storage.azure.com, одинакова во всех облаках.)


Рекомендуемый порядок действий в рамках задания

  1. Обновите карту разрешений для этого клиента (один раз). Преобразует Graph GUID разрешений в авторитетные имена для целевого клиента: ```bash python -m secret_stalker --update-manifest
    root@kitploit:~

Это выполняет аутентификацию, кэширует карту appRole Graph клиента в ~/.secret_stalker/app_roles_cache.json и завершает работу. Пропустите этот шаг, если учётные данные не могут читать субъекты-службы — встроенная карта по-прежнему покрывает известные разрешения.

  1. Пассивная базовая линия. Проверка действительности, разрешений Graph и Azure RBAC без обращения к объектам клиента: ```bash python -m secret_stalker
    root@kitploit:~
  2. Переходите в активный режим, когда нужна глубина + отчёт для сохранения. Добавляет образцы объектов Graph только для чтения и проверку доступности data-plane для Key Vault / Storage, а также записывает плоский экспорт для триажа или загрузки: ```bash python -m secret_stalker --active --export results.ndjson
    root@kitploit:~

Чтение вывода

Терминальный отчёт организован сверху вниз: от «сработало ли» до «каков ущерб». Типичный запуск выглядит так:``` secret_stalker — credential assessment

Credential status : VALID Tenant : aaaaaaaa-... Client (app) id : 1111... App display name : Recon App SP object id : cccc... Secret : valid — expires 2027-03-01 (in 207 days)

Token acquisition

OK graph OK arm NO storage — no storage token

Microsoft Graph application permissions (from token)

  • Application.ReadWrite.All
  • Mail.Read

...

Findings — escalation / control

[CRITICAL] (GRAPH) Application.ReadWrite.All Can add credentials to any app/SP and impersonate it — tenant-wide pivot. [CRITICAL] (ARM) Owner Full control including granting access to others. [CRITICAL] (DATA) keyvault:secrets Can read Key Vault secret values — connection strings, passwords, tokens. [MEDIUM] (GRAPH) Mail.Read Read all mailboxes — data exposure.

Overall risk: CRITICAL

root@kitploit:~
- **Получение токена** перечисляет каждую проверенную аудиторию (Graph, ARM и — при
  `--active`, когда обнаружены соответствующие ресурсы — Key Vault / Storage /
  Cosmos DB). Graph и ARM *независимы*: учётные данные могут обладать одной и не
  обладать другой.
- **Секрет** показывает действительность и, для действительного секрета, дату истечения и
  оставшиеся дни (близкое истечение подсвечивается). См. примечание ниже об истёкших секретах.
- **Находки** — раздел, который следует читать первым — высоковлиятельные разрешения Graph (`GRAPH`),
  роли ARM (`ARM`), роли каталога Entra (`ROLE`), собственные приложения/SP (`OWN`),
  доступные поверхности data-plane (`DATA`) и запрошенные, но не одобренные
  цели consent-атак (`WANT`) — дедуплицированные и с оценкой серьёзности. Возможность
  читать каждый секрет Key Vault или наличие роли каталога — самостоятельная находка,
  даже без опасных прав Graph/ARM.
- **Пути атак** превращают главные находки в конкретные следующие шаги (например, *Privileged
  Role Administrator → назначить себе Global Administrator → захват тенанта*).
- **Активное перечисление Graph** (`--active`) сообщает, что вернул каждый read-only
  зонд. Большинство зондов запрашивают небольшую ограниченную страницу, поэтому заполненная
  страница показывается как `N+` (например, `users  accessible  (returned 5+)`) — то есть
  *как минимум* пять, а не ровно пять. Зонды без ограничения (`organization`, `directoryRoles`)
  сообщают реальное общее число без `+`.
- **Роли каталога / Собственные объекты / Делегированные разрешения** получают собственные разделы.
  Роли каталога определяются из утверждения `wids` в токене, даже без чтения
  каталога; делегированные разрешения непригодны для учётных данных только приложения, но
  показываются для переключений контекста пользователя и нацеливания consent-атак.
- **Общий риск** — это серьёзность самой высокой отдельной находки.

> **Истечение секрета — что можно узнать.** Дата истечения *не* содержится в токене;
> она хранится в `passwordCredentials` регистрации приложения в Entra ID. Для
> **действительного** секрета secret_stalker читает её через Graph и сопоставляет ваш
> секрет с нужными учётными данными по `hint` (первые 3 символа) — для этого требуется
> чтение каталога (`Application.Read.All` / `Directory.Read.All`); если у SP его нет,
> дата сообщается как недоступная, а не угадывается. Для **истёкшего** секрета сама
> аутентификация завершается ошибкой, поэтому мёртвые учётные данные не могут прочитать
> собственные метаданные — инструмент помечает их `EXPIRED (AADSTS7000222)`, но точную
> дату окончания через одни лишь эти учётные данные получить нельзя.

### Коды выхода

Полезно для скриптов:

| Код | Значение |
|------|---------|
| `0`  | Учётные данные действительны (получен хотя бы один токен). |
| `2`  | Учётные данные недействительны / нет доступа. |
| `1`  | Ошибка — не удалось определить тенант, загрузить сертификат или записать файл `--export`. |

---

## Все флаги

| Флаг | Действие |
|------|--------|
| `--tenant` | GUID или домен тенанта. (или `SS_TENANT`) |
| `--cloud` | Облако Azure: `public` (по умолчанию), `usgov` (GCC High), `usdod` (DoD), `china` (21Vianet). Выбирает центр Entra и конечные точки Graph/ARM/Key Vault. Принимаются алиасы вроде `gov`/`dod`/`commercial`. (или `SS_CLOUD`) |
| `--client-id` | Идентификатор приложения (клиента). (или `SS_CLIENT_ID`) |
| `--secret` | Секрет клиента. Предпочтительнее `SS_SECRET`, чтобы не оставлять его в истории. |
| `--cert` | Сертификат для аутентификации JWT-assertion вместо секрета: PEM (ключ+сертификат) или `.pfx`/`.p12`. Требует `cryptography`. (или `SS_CERT`) |
| `--cert-password` | Пароль для зашифрованного ключа/PFX из `--cert`. (или `SS_CERT_PASSWORD`) |
| `--active` | Необязательное перечисление только для чтения: образцы объектов Graph **плюс** доступность data-plane Key Vault / Storage. По умолчанию выключено, чтобы оставаться незаметным. |
| `--deep` | С `--active`: спуститься на один уровень в доступное Storage — перечислить blob в доступных контейнерах и файлы в доступных файловых ресурсах (только имена, с ограничением). Более шумно. |
| `--no-arm` | Пропустить перечисление групп управления / подписок / RBAC (только Graph). |
| `--workers N` | Параллельные HTTP-воркеры для поиска областей ARM и data-plane-зондов (по умолчанию 8; `1` = последовательно). |
| `--update-manifest` | Получить эталонную карту appRole GUID→name из живого тенанта (Graph **плюс** любые другие ресурсные API, на которые назначены эти учётные данные), закэшировать её и выйти. |
| `--json` | Вывести полный вложенный результат в виде JSON вместо отчёта. |
| `--export PATH` | Записать результаты в файл. Формат определяется по расширению (`.csv` / `.ndjson` / `.jsonl` / `.json` / `.html`). Файлы записываются только для владельца (`0600`). |
| `--export-format` | Принудительно задать формат экспорта (`ndjson` / `csv` / `json` / `html`). |
| `--timeout N` | Таймаут на запрос в секундах (по умолчанию 20). Запросы ARM control-plane (перечисление RBAC + обнаружение Resource Graph) используют более длинный таймаут — `1.5×`, минимум 30 с — так как выполняются медленнее. |
| `--verbose`, `-v` | Трассировать каждый HTTP-запрос Graph/ARM/data-plane (метод, URL, статус) в stderr. |
| `--no-banner` | Подавить ASCII-баннер. |
| `--version` | Вывести версию и выйти. |

---

## Экспорт результатов

`--export` преобразует результат в **одну запись на каждый обнаруженный объект** —
учётные данные, токен, разрешение Graph, назначение app-role, роль ARM, обнаружение
data-plane и оценённую находку — каждая с контекстом учётных данных, чтобы строка
была самодостаточной.```bash
# NDJSON — stream into a SIEM / log pipeline
python -m secret_stalker --export results.ndjson

# CSV — open in a spreadsheet for triage
python -m secret_stalker --active --export results.csv

# Full nested JSON to a file
python -m secret_stalker --export results.json

Каждая запись несёт record_type (credential, secret, token, graph_permission, app_role_assignment, directory_role, owned_object, arm_role, dataplane, delegated_permission, requested_permission, finding), поэтому потребитель может отфильтровать только то, что ему нужно — например, только оценённые совпадения:```bash jq 'select(.record_type=="finding")' results.ndjson

root@kitploit:~
Терминальный отчёт и `--export` работают вместе — экспорт не подавляет
отчёт (подтверждение «Exported …» уходит в stderr, поэтому передача `--json` по конвейеру
остаётся чистой).

Экспортируемые файлы несут контекст учётных данных (утверждения токена, секретный `hint`, идентификаторы ключей),
поэтому они записываются **только для владельца (`0600`)** — чтобы избежать утечки на общем или синхронизируемом
хосте. Относитесь к ним как к чувствительным артефактам тестирования. Запись через символическую ссылку
отклоняется безоговорочно, поэтому путь экспорта не может быть перенаправлен на усечение чего-то
другого.

Имена в результате приходят от оцениваемого тенанта — отображаемые имена приложений и групп,
имена контейнеров и blob-объектов, — поэтому они считаются недоверенным выводом:

- Значения **CSV**, которые были бы прочитаны как формула (ведущие `=`, `+`, `-`, `@`),
  предваряются одинарной кавычкой, поэтому такое отображаемое имя, как `=cmd|' /C calc'!A0`,
  не выполнится при открытии файла в электронной таблице. Электронные таблицы убирают кавычку
  при отображении.
- Вывод **терминала, CSV и HTML** очищается от управляющих символов, поэтому имя,
  несущее ANSI-escape-последовательности, не может изменить заголовок вашего терминала или перезаписать
  результаты выше него — читаете ли вы отчёт в реальном времени, `cat` CSV или `cat` HTML.
- **JSON / NDJSON остаются без изменений**: `json.dumps` кодирует управляющие символы как
  `\uXXXX`, что инертно как текст, при этом парсер по-прежнему без потерь воспроизводит точное
  значение, возвращённое тенантом. Исходное имя — это улика, поэтому оно сохраняется там.

---

## Как разрешаются GUID разрешений

`appRoleAssignments` возвращаются в виде GUID. secret_stalker преобразует их в имена с помощью
плоского поиска (GUID appRole глобально уникальны), который продолжает работать **даже когда
чтение каталога запрещено**:

- Карта общеизвестных разрешений Graph (best-effort) поставляется в
  `secret_stalker/data/graph_app_roles.json`.
- `--update-manifest` заменяет её авторитетными данными, полученными в реальном времени от
  тенанта в области оценки, — Microsoft Graph **плюс каждый другой ресурсный API, для которого
  назначено это учётное данное** (например, Exchange Online, SharePoint), поэтому не-Graph GUID тоже разрешаются.
- Неизвестный GUID отображается **в исходном виде и помечается** — инструмент никогда не угадывает имя.

---

## Как это работает (краткая версия)

- **Действительность + разрешения одним запросом.** Утверждение `roles` успешного токена Graph
  *и есть* список разрешений, предоставленных приложению. secret_stalker читает его
  из декодированного токена — быстро и бесшумно, вызовы Graph не нужны.
- **Graph ≠ ARM.** Это разные аудитории токенов. Учётное данное может иметь права
  на одной из них и не иметь на другой, поэтому каждая проверяется независимо.
- **Плоскость данных ≠ плоскость управления.** Наличие прав ARM на Key Vault (управление) —
  это не то же самое, что возможность читать его секреты (плоскость данных). В режиме `--active`
  доступность плоскости данных проверяется с использованием собственной аудитории токена ресурса — и при этом
  перечисляются **только имена** объектов, никогда не значения и не содержимое.
- **Проверка плоскости данных по каждой поверхности.** RBAC плоскости данных предоставляется по типу объекта /
  службе, поэтому каждая проверяется независимо: Key Vault — **секреты / ключи /
  сертификаты**, Storage — **blob / файл / очередь / таблица**, Cosmos DB —
  **базы данных**. Учётное данное, которое является `Storage File Data SMB Share Reader`, но не
  читателем blob, обнаруживается, а не упускается. (Cosmos использует нестандартный заголовок AAD REST
  и работает по принципу **best-effort** — проверяйте результат `denied` на живом аккаунте.)
- **Обнаружение по всему тенанту.** Ресурсы находятся одним проходом Azure Resource Graph
  по всем подпискам, которые видит субъект (с учётом RBAC), с откатом
  к перечислению поставщиков по подпискам, если ARG запрещён. В отчёте помечается, какой
  путь использовался (`[discovery: resource-graph]` vs `per-subscription`). Проход
  перебирает результаты постранично вплоть до предела (40 страниц × 1000 строк на тип ресурса), поэтому
  выполнение всегда завершается; `--verbose` сообщает об этом, если предел когда-либо достигнут.
- **Сопоставление уровней серьёзности** находится в `secret_stalker/risk.py` — отредактируйте его, чтобы настроить,
  что ваша команда считает критичным.

---

## Структура проекта```
secret_stalker/
  clouds.py      Azure cloud endpoint table (public / usgov / usdod / china)
  auth.py        client_credentials flow + tenant discovery + AADSTS decoding
  jwt_utils.py   local JWT claim extraction
  manifest.py    Graph appRole GUID -> name resolution (bundled + live cache)
  graph.py       service principal lookup + appRole resolution + active probes
  arm.py         management-group / subscription RBAC + resource discovery
  dataplane.py   Key Vault / Storage data-plane reachability probes
  risk.py        permission/role/data-plane -> impact mapping (tune this)
  report.py      terminal + JSON output
  export.py      flatten to NDJSON / CSV / JSON records for ingestion
  util.py        shared HTTP (retry/backoff + safe JSON), pmap parallel map,
                 untrusted-output sanitizing
  banner.py      ASCII banner (stderr only)
  cli.py         orchestration
  data/graph_app_roles.json   bundled permission manifest
tests/           pytest suite (run: pytest)
pyproject.toml   packaging + `secret_stalker` console entry point

Реализованные возможности

  • Аутентификация по секрету или сертификату (--cert) — JWT client-assertion (RS256) из PEM или PFX, с сообщением об истечении срока действия сертификата. auth.py
  • Роли каталога Entra, принадлежащие субъекту — включая пассивное обнаружение из утверждения wids токена (чтение каталога не требуется) — оцениваются по роли. graph.py / risk.py
  • Объекты во владении — приложения/субъекты-службы, которыми владеет учётная запись (переход к добавлению учётных данных). graph.py
  • Видимость делегированных разрешений (--active) — согласованные предоставления + запрошенные разрешения, при этом несогласованные опасные разрешения помечаются как мишени атак на согласие. graph.py / risk.py
  • Сценарии путей атак + HTML-отчёт (--export report.html). risk.py / report.py

Идеи для дальнейшего развития

  • Чтение атрибутов ключей/сертификатов Key Vault (включено/срок действия) для триажа — по-прежнему только метаданные, без материала ключей.
  • Просмотр содержимого очередей/таблиц хранилища означал бы чтение данных, поэтому он намеренно вне области действия этого инструмента, предназначенного только для чтения.
Скачать инструмент
--cloudЦентр выдачи EntraMicrosoft GraphARMKey Vault
public (по умолчанию)login.microsoftonline.comgraph.microsoft.commanagement.azure.comvault.azure.net
usgov (GCC High)login.microsoftonline.usgraph.microsoft.usmanagement.usgovcloudapi.netvault.usgovcloudapi.net
usdod (DoD)login.microsoftonline.usdod-graph.microsoft.usmanagement.usgovcloudapi.netvault.usgovcloudapi.net
china (21Vianet)login.chinacloudapi.cnmicrosoftgraph.chinacloudapi.cnmanagement.chinacloudapi.cnvault.azure.cn
  • Коммерческие и суверенные облака (--cloud) — публичное, US Gov (GCC High), US DoD и China (21Vianet), каждое с правильным центром Entra и аудиториями Graph / ARM / Key Vault. clouds.py
  • Обнаружение ресурсов по всему тенанту с помощью одного сканирования Azure Resource Graph (с учётом RBAC), с резервным вариантом для каждой подписки и восстановлением через потомков групп управления для подписок, пропущенных плоским списком. arm.py
  • Полное покрытие плоскости данных — секреты / ключи / сертификаты Key Vault, хранилище blob / file / queue / table и базы данных Cosmos DB, каждая проверяется независимо и включается в оцениваемые находки (доступные данные — это находка, а не просто метаданные). dataplane.py / risk.py
  • Точные подсчёты — перечисление в плоскости данных использует токены продолжения (с ограничением), поэтому подсчёт поверхности отражает реальный итог; знак + (например, 25+) указывает, что перечисление было ограничено, а не молча занижено. dataplane.py
  • Устойчивые к троттлингу запросы — один общий HTTP-путь повторяет запросы при 429/503 с учётом Retry-After, поэтому временный троттлинг не ошибочно принимается за «отказано / нет доступа». util.py
  • Глубокое погружение в хранилище (--deep) — перечисляет блобы в доступных контейнерах и файлы в доступных общих папках, только имена, с ограничением. dataplane.py
  • Разрешение GUID вне Graph — --update-manifest кэширует appRoles для каждого API ресурса, на который назначена учётная запись, а не только Graph. graph.py / manifest.py
  • Параллелизм (--workers N) при поисках по областям ARM и проверках плоскости данных, с изоляцией ошибок по каждому элементу. util.py