Исследователь опубликовал разбор пяти полных кросс-тенантных компрометаций Azure. Все они относятся к API Connections — части Azure Logic Appsоблачный сервис Microsoft для запуска рабочих процессов, которые обращаются к внешним системам через готовые коннекторы, через которую рабочие процессы обращаются к внешним сервисам. По формулировке автора, API Connections позволяют полностью скомпрометировать любое другое соединение в мире и получить полный доступ к подключённому бэкенду, включая кросс-тенантные Key Vault и базы данных Azure SQL, а также внешние сервисы вроде Jira или Salesforce. Все пять уязвимостей дают атакующему одни и те же примитивы.
Что именно изменилось
Механика атаки опирается на архитектуру API Connections. Logic App обращается к общей Azure API Management (APIM) — сервису-посреднику, который принимает вызовы коннекторов и работает с их токенами. APIM сверяет swagger-определениеописание API коннектора в формате Swagger, по которому сервис понимает набор операций и их параметры, обменивает входной токен на настроенный токен бэкенда и завершает вызов этим новым токеном. Если заставить APIM работать не со своим соединением, а с чужим, настроенный токен жертвы уйдёт на её бэкенд.
Для этого использовался ARM REST API. Через него доступны операции прямого вызова соединения и проксирования: они позволяют обратиться к APIM в обход обычного пути Logic App и выполнить операцию коннектора от имени выбранного соединения. ARM как resource manager имеет полный доступ ко всему, поэтому задача сводится к тому, чтобы обмануть вызывающий сервис и заставить его запросить другое соединение. В запросе на прямой вызов собственного соединения параметр path содержал последовательности %2e%2e — URL-кодированные .. — и выводил за пределы соединения к секрету Key Vault другого тенанта.
Отдельно применялась операция построения списка: она получает от коннектора описание того, как собрать список значений из источника данных, и подставляет переданные параметры в запрос к этому источнику. Тем же способом обхода пути через неё выполнялся произвольный SQL-запрос к базе жертвы.
После раскрытия Microsoft добавила проверку: runtime URL должен точно совпадать с ожидаемым эндпоинтом API для соответствующего соединения, иначе возвращается сообщение «The host API runtime URL is not valid…». В нём предлагается либо убрать входное свойство host.api, либо исправить runtime URL под API соединения. Автор оценивает такой фикс как подходящий: runtime URL должен точно совпадать с ожидаемым, иначе — отказ.
Как было раньше
Подменить ссылку на чужое соединение напрямую не получалось: среда выполнения проверяет, что соединение принадлежит вам. Обход строился на входном параметре host.api.RuntimeUrl — это поле во входных данных подключения, которое задаёт адрес, по которому среда выполнения будет вызывать API вместо адреса, зашитого в само соединение. Указать в нём другой URL можно после серии проверок самого соединения. Если хост оканчивается на azure-apihub.net, к запросу автоматически добавляется нужный заголовок Authorization. Доступ к редактированию входных параметров даёт представление Code в GUI: оно показывает входы детальнее, позволяет их менять и добавлять.
Автор предположил, что каждая Consumption Logic App имеет неявный доступ ко всем Version 1 API ConnectionsТип соединения API Connections, который создаётся в Consumption Logic Apps и, по предположению автора, неявно доступен каждой такой Logic App, из-за чего единственной защитой остаётся валидация ввода., и единственное, что мешает эксплуатации, — валидация ввода.
Почему это сделали и в чём слабое звено
Проблема формулируется как расхождение между тем, что проверяет runtime-слой Logic Apps, и тем, что фактически видит APIM. Проверка выполняется до нормализации пути: runtime считает URI указывающим на собственное соединение, а APIM интерпретирует его иначе. Плюс запрос от ARM к APIM имеет права на все соединения независимо от того, с каким он работает.
Единственной защитой остаются слои входной валидации, навешанные на разные системы, и поймать все краевые случаи трудно. Исправления носили характер ограничения разрешённых путей, а не устранения базовой проблемы с токенами.
Что это меняет на практике
При создании API-подключения теперь обязательна проверка соответствия runtime URL ожидаемому эндпоинту API. Но проверка значения выполняется до нормализации пути, из-за чего её удавалось обойти. Когда Microsoft выпустила фикс для обхода пути, исходный путь runtime URL перестал проверяться — и атаку снова стало возможно выполнить.
Для эксплуатации нужно собственное соединение в своём тенанте. Успех подтверждается ответом HTTP/2 200 OK и телом с "statusCode": "OK", содержащим запрошенные данные. В приведённых запросах фигурируют подписка 8e3ce52f-d45b-4347-8705-65892507465e, группа ресурсов token-storer, соединение custom2 с телом длиной 147 байт и ответом Content-Length: 1329, где значение секрета — dontreadme, имя — victimsecret, версия — 7914d45aa60342809fb8cc12dc68b10e, время создания — 2025-04-04T05:38:26Z. Второй запрос — через эндпоинт динамического списка к подписке 162fc6db-03cd-4fe8-ab44-dc0a947e74af, группе api-connection, соединению custom_validator, с Content-Length: 524 и SQL-запросом Insert INTO MySecrets VALUES ('NewEvilSecrets', 3) к victimservice.database.windows.net,VictimDatabase.
Настроившие соединения могут ограничить права токенов или ключей, чтобы API Connection имел минимальные привилегии в бэкенде, но, по предположению автора, это делается редко.
Ограничения и открытые вопросы
Автор прямо признаёт неполноту фикса: после исправления обхода пути исходный адрес среды выполнения перестал проверяться, и атаку можно было повторить. Новое требование к runtime URL тоже обходится из-за порядка нормализации пути. Все отчёты были исправлены в разумные сроки после отправки, хотя по ходу работы были разногласия с MSRCподразделение Microsoft, принимающее сообщения об уязвимостях; в целом автор доволен результатами. Конкретных сроков, сумм выплат и формулировок ответов Microsoft не приводится.