Ко мне обратился владелец производственной компании — плановый аудит доступов, без конкретного повода. Просто хотел понять, кто и куда может дотянуться в его цифровом хозяйстве. За полгода до этого менеджер по продажам подключил нейросеть-помощника к рабочей почте и облачному хранилищу — чтобы та помогала составлять коммерческие предложения по шаблонам. При первом подключении сервис запросил доступ только к одной папке. Согласие дали не глядя — как это делают почти все.
Когда я полез в настройки подключённых сторонних приложений, обнаружил, что у сервиса уже есть доступ не к одной папке, а ко всему облачному диску и к переписке в рабочей почте — включая договоры с индивидуальными ценами для конкретных клиентов и переговоры с поставщиками. Никто повторно ничего не разрешал. Это и есть суть проблемы, которую недавно подтвердило независимое исследование: у трети коннекторов Claude и ChatGPT набор прав меняется в течение шести недель после подключения — без повторного запроса согласия у пользователя.
Как это эксплуатируется
Технически здесь нет «дыры» в смысле уязвимого софта с CVE — механизм абсолютно легитимный, встроенный в спецификацию OAuth 2.0 и называется incremental authorization (постепенное расширение прав). Проблема в том, как этим механизмом пользуются разработчики интеграций и как мало кто это проверяет.
- Разведка подключённых приложений. Первым делом смотрю, что вообще авторизовано в организации. В Google Workspace это делается через Admin SDK Reports API или консольную утилиту GAM:
Вывод по каждому пользователю содержит client id стороннего приложения и текущий список scope, например:gam all users print oauth
При первом подключении в этом же логе стоял всего один scope —user: manager@company.ru clientId: 1234567890-abc.apps.googleusercontent.com displayText: AI Assistant Pro scopes: https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/gmail.senddrive.file(доступ только к файлам, созданным самим приложением). Разница видна невооружённым глазом, если есть с чем сравнивать. - Для Microsoft 365 аналогичная проверка делается через Graph PowerShell:
и через Unified Audit Log ищутся событияConnect-MgGraph -Scopes "Application.Read.All" Get-MgOAuth2PermissionGrant -Filter "clientId eq ''" Consent to applicationиAdd app role assignment grant to service principal— там фиксируется момент, когда scope расширился. - Как это выглядит со стороны атакующего. Если сам сервис-коннектор скомпрометирован (утечка ключей у вендора, supply chain-атака) или используется классический OAuth consent phishing — жертве присылают ссылку на поддельное приложение с именем вроде «PDF Helper» или «CRM Sync», запрашивающее сразу широкий scope. Пользователь видит стандартный экран согласия Google/Microsoft и жмёт «Разрешить», не читая список прав. После этого у злоумышленника на руках — валидный refresh token без пароля и без MFA.
- Пост-эксплуатация через API, без единого запроса к самому серверу компании. Получив токен, дальше работают напрямую с облачным API — никакого фишинга или брутфорса больше не нужно:
или для Microsoft Graph:curl -s -H "Authorization: Bearer $TOKEN" \ "https://gmail.googleapis.com/gmail/v1/users/me/messages?q=%22коммерческое+предложение%22"
Для массовой постэксплуатации в Microsoft 365 существует специализированный инструмент GraphRunner — публичный фреймворк для пентеста, который после получения токена автоматически перечисляет письма, файлы OneDrive, вложения и даже умеет закрепиться, создав скрытое переадресующее правило. Для Google-инфраструктуры массовую выгрузку файлов удобно делать черезcurl -s -H "Authorization: Bearer $TOKEN" \ "https://graph.microsoft.com/v1.0/me/messages?\$search=%22договор%22"rclone, подключённый как удалённый диск: одна команда синхронизации выгружает весь Google Drive компании на внешний сервер.
Полутехнические пруфы
- Протокол: OAuth 2.0 / OpenID Connect, порт 443, endpoint выдачи токена
https://oauth2.googleapis.com/tokenилиhttps://login.microsoftonline.com/common/oauth2/v2.0/token. - Исходный scope при подключении:
drive.file— приложение видит только файлы, к которым его явно допустили. Через полтора месяца в логах уже стоитdrive— полный доступ ко всему диску, плюс добавленныйgmail.readonly, которого при первом согласии не было вовсе. - До расширения прав запрос к письмам возвращал бы
403 insufficient_scopeс заголовкомWWW-Authenticate: Bearer error="insufficient_scope"; после расширения — обычный200 OKс телом ответа, содержащим переписку. - В Admin Console событие фиксируется в разделе Security → API Controls → App Access как «Scope changed» с указанием даты и client id — но по умолчанию никто эти события не мониторит и уведомление не приходит.
Что и почему сработало бы
Дальше сценарий развивается без единого «взлома» в привычном смысле. Через выгруженную переписку и файлы ищутся ключевые слова: цена, прайс, скидка, договор, спецификация. В облаке лежали индивидуальные условия для трёх крупных клиентов — цены ниже прайса за объём. Утечка этих данных к конкуренту означала риск потери крупнейшего контракта: владелец оценил это примерно в 4,5 млн рублей выручки в год только по одному клиенту, без учёта репутационных потерь и цепной реакции у остальных.
Если бы токен использовался не разово, а атакующий закрепился, следующий шаг — тихое создание правила пересылки входящих писем от ключевых клиентов на внешний ящик (классика BEC, Business Email Compromise), что позволяет годами получать актуальную переписку без повторного взлома чего-либо.
Как закрыли
Первым делом отозвал у сервиса лишние права, оставив только доступ к папке шаблонов — тот объём, который реально нужен для работы. Дальше выстроил процесс, которого в компании не было вовсе:
- Составил реестр всех сторонних приложений, подключённых к почте, дискам и CRM, с фиксацией исходно выданных scope как baseline.
- В Google Workspace ограничил доступ через Admin Console → Security → API Controls → App Access Control: перевёл режим на «Trusted apps only», заблокировав неконтролируемым сторонним сервисам доступ по умолчанию.
- В Microsoft 365 отключил пользовательское согласие (user consent) на уровне Enterprise Applications и перевёл выдачу прав только через admin consent workflow, чтобы новый scope не мог появиться без ведома ИТ.
- Настроил ежемесячную автоматическую сверку через API Reports/GAM-скрипт, сравнивающий текущие scope с baseline и присылающий отчёт по расхождениям.
- Подключил алерт в мессенджер владельцу на любое событие расширения прав — простой cron-скрипт, дергающий Reports API раз в сутки:
gam all users print oauth > current.csv diff baseline.csv current.csv && echo "OK" || notify_owner.sh
Вся работа заняла два дня — аудит плюс настройка мониторинга. Теперь если завтра любой инструмент, будь то нейросеть или новая CRM, попробует расширить свои полномочия сверх исходных, владельцу прилетит уведомление в течение суток, а не через полтора месяца случайно при плановой проверке.
