Введение

Данный цикл статей сформировался по итогам нашего выступления на Offzone-2022 в конце августа. Ввиду ограниченности времени презентации, нам не удалось в полной мере рассказать о данном исследовании. Поэтому, чтобы исправиться и разложить всё «по полочкам», представляем вам данный материал. Итак, поехали…

1.С чего все началось

В процессе RedTeam-кампаний мы постоянно сталкиваемся не только с анализом технической части внутренней инфраструктуры заказчика, но и с изучением процессов управления данной инфраструктурой. Это позволяет более эффективно спланировать проведение той или иной атаки. Примером такого планирования может послужить проведение атаки на систему управления гипервизором непосредственно через рабочую станцию администратора этого гипервизора. В его рабочее время и используя его реквизиты доступа.  Это означает, что нам придётся изучать внутреннюю документацию ИТ-персонала, читать почту администраторов, анализировать логи доступа и куки веб-браузеров ключевых IT-сотрудников компании. С анализом технической документации и данными различных браузеров всё более-менее ясно (с технической точки зрения). В сети доступно множество различного инструментария для расшифровки сохраненных паролей и cookies.

Примеры «дешифраторов» паролей и cookies
Примеры «дешифраторов» паролей и cookies
Примеры «дешифраторов» паролей и cookies
Примеры «дешифраторов» паролей и cookies
Примеры «дешифраторов» паролей и cookies
Примеры «дешифраторов» паролей и cookies

А вот со сбором почты с почтовых серверов часто возникают проблемы. В последнее время всё больше и больше компаний «уходят в облака» и переводят туда все свои информационные потоки. Одним из популярных провайдеров облачных сервисов является Microsoft, которая предоставляет богатый инструментарий по организации и управлению почтовой системой на базе своей ActiveDirectory и сервисов Outlook Office365. И если пару-тройку лет назад почту пользователей корпоративного Outlook можно было смело читать/качать, выполнив обычную Basic-авторизацию, то сейчас такого уже практически нигде нет. У всех более-менее зрелых в отношении ИБ компаний включена 2х-факторная аутентификация для пользователей с добровольно-принудительной установкой 2го фактора (это когда ты либо привязываешь телефон или Microsoft Authenticator в качестве 2го фактора, либо тебе запрещено пользоваться всеми облачными благами).

Мы не первые, кто задался вопросом, как обойти подобную защиту. Однако обнаруженный нами инструментарий обычно сводился к парсингу и анализу PST-файлов, добытых с рабочих станций пользователей. Проблема в том, что данные файлы во-первых могут быть довольно таки-большого размера (мы встречали PST по 10-15 Гб), а во-вторых это не решало проблему возможной необходимости анализа свежеприбывающей почты. Например, вам нужно проанализировать новые письма, которые пришли уже после скачки PST. Снова качать все 10 Гб ради пары новых сообщений?

Так или иначе, нам необходимо было разобраться как приложение Outlook хранит на рабочих станциях пароли доступа к почтовым сервисам Outlook365, и как в данном случае работает 2х факторная аутентификация.

2. Первые шаги

Чтобы выяснить это, мы привязали Outlook к специально созданному корпоративному аккаунту с двухфакторной авторизацией в майкрософтовском облаке. А затем «вежливо попросили» desktop-приложение Outlook Office проверить почту под нашим чутким руководством (импортировали сертификат бурпа и выставив соответствующие настройки прокси-сервера в IE). В HTTP-пакетах мы увидели, что Outlook работает с облаком по двум почтовым протоколам: EWS (Microsoft Exchange Web Wervices) и MAPI. И в том, и в другом случаях авторизация происходит через Json Web Token (JWT) в HTTP-заголовке Authorization Bearer.  

Авторизация в EWS
Авторизация в EWS
Авторизация в MAPI
Авторизация в MAPI

Немного о JWT

Здесь необходимо сделать небольшое лирическое отступление и вкратце напомнить читателю, что такое Json Web Token.  JWT — это открытый стандарт (RFC 7519) для создания токенов доступа, основанный на формате JSON. Как правило, используется для передачи данных для аутентификации в клиент-серверных приложениях. Обычно такие токены создаются сервером, подписываются секретным ключом и передаются клиенту, который в дальнейшем использует его для подтверждения своей личности. Простыми словами, JWT — это лишь строка в следующем формате header.payload.signature, где JSON-данные закодированы в base64-виде.

JWT (Json Web Token)
JWT (Json Web Token)

В заголовке JWT закодированы его основные характеристики: тип, алгоритм подписи/шифрования, а также возможные дополнительные характеристики, такие как случайная соль, сертификат подписи и т.д. Поле payload содержит непосредственно информативную часть токена. Тут может быть всё что угодно, что может потребоваться приложению для авторизации: информация о пользователе, его правах доступа, хеш пароля (ну а что, а вдруг…). Главное, чтобы в JSON-формате, и base64 «сверху». Signature – это сама цифровая подпись header+payload (прямо вместе с точкой), осуществлённая по алгоритму, указанному в заголовке, т.е. —sign(base64(header).base64(payload)).

Для работы с JWT внутри линукса (как правило внутри скриптов на bash) удобно применять утилиту jwt из одноименного deb-пакета. Утилита позволяет декодировать JWT, подписывать и проверять подпись используя подготовленный ключевой файл.

Использование утилиты jwt
Использование утилиты jwt

Для анализа JWT внутри http-пакетов удобнее всего применять специальный плагин для BurpSuite – JWT4B (внутри встроенного в BurpApp он называется «json web tokens»).

Данный плагин позволяет также просматривать и модифицировать JWT «налету», используя заранее заданные параметры подписи. Например, можно взять JWT, подписанный по HS256 и переподписать его уже на основе RSA. Плагин также подсвечивает http-пакеты, проходящие через Burp, в составе которых он обнаруживает JWT. Поиск сигнатур JWT происходит по ключевым словам, перечень которых также можно настроить. Забегая вперед добавим, что данный плагин позволяет проводить атаки на механизмы генерации и подписи JWT. В общем, этот плагин из разряда «must have», если Вы собираетесь работать с JWT посредством BurpSuite.

Ниже мы видим раскодированный JWT, который outlook посылает в качестве авторизационного токена на свой сервер:

Данный токен сформирован по расширенному компанией Microsoft стандарту OAUTH 2.0. Здесь следует обратить внимание, что токен подписан по алгоритму RSA закрытым ключом, известным только серверу, а также на поля aud (предназначение токена – сервис, для которого предназначен этот jwt), поля временных меток iat (issued at), nbf (used not before) и exp (expiration time). Последнее поле (exp) указывает нам, когда токен перестает действовать. Проанализировав временные метки (они указаны в секундах по стандарту Unix Epoch Time), мы пришли к выводу, что время жизни данного токена составляет порядка 25 часов.

3. Начинаем искать…

Дальше нам надо было найти, где же внутри системы Outlook хранит эти JWT. Так как это Microsoft, мы предположили (как оказалось, не зря), что JWT, будучи чувствительной с точки зрения безопасности информацией (этаким своеобразным временным паролем), скорее всего зашифрован, и в открытом тексте мы вряд ли его найдем. А так как это Windows, то механизм шифрования скорее всего лежит на основе подсистемы DPAPI. Держа это в уме, мы начали поиски внутри пользовательских профилей на диске и в реестре по сигнатурам DPAPI-блобов (0x01000000D08C9d и AQAAANCMnd). И соответствующие tbres-файлы нашлись внутри профиля пользователя в каталоге TokenBroker:

Расположение tbres-файло
Расположение tbres-файло
Содержимое tbres-файла
Содержимое tbres-файла

Внутри файлов мы обнаружили DPAPI-блобы зашифрованные на мастерключах пользователя. Для дешифровки DAPAPI-блобов мы применили уже не раз выручавший нас фрейморк DPAPIck3. К cлову, фреймворк DPAPIck недавно получил некоторое развитие — в частности, был перенесён на базу Python3. Итак, после дешифровки файла посредством фреймворка DPAPIck3 (универсального декриптора filegeneric.py) нам удалось заглянуть внутрь tbres-файла. Как видно из рисунков, внутри помимо самого JWT находились дополнительные поля, фактически дублирующие поля JWT — такие как user apn, token issuers, tenant ID, Expiration time и другие, видимо, необходимые приложению для корректной работы.

Расшифрованный tbres-файл
Расшифрованный tbres-файл

Помимо файла с данными и JWT для Outlook, в каталоге tokenbroker/cache можно обнаружить много других аналогичных файлов, только уже для других офисных (и не только) приложений. Например, Microsoft Teams, Microsoft OneDrive, Microsoft Azure Active Directory. Также можно встретить tbres-файлы с JWT для MS Graph – это такой специальный REST API интерфейс, предоставляющий доступ к различным сущностям внутри облачных сервисов Microsoft. Правда, так называемый scope у найденных нами токенов оказался не такой широкий как хотелось бы. Например, часто попадались JWT для MS graph, которые позволяют работать с почтой, контактами, файлами на Sharepoint-серверах, но не позволяют читать сообщения Microsoft Teams.

Давайте еще раз взглянем на раскодированный JWT внутри tbres-файла:

Здесь мы видим важные для нас поля aud, iat, nbf, exp о которых мы говорили чуть выше. Также хотим обратить ваше внимание на такие поля как:

  • scp (scope) – область действия токена, фактически — его права. В данном случае, токен от Outlook имеет права на чтение/запись почты и контактов, а также на чтение/запись файлов;

  • tid (tenant ID) – уникальный идентификатор компании в Microsoft;

  • amr (auth claim) – json-массив, указывающий, при каких условиях был получен токен.

В данном случае, токен был получен после ввода пароля и проверки второго фактора.

Помимо указанных значений здесь могут быть такие аббревиатуры, как otp, fed (federated authentication assertion), wia (Windows Integrated Authentication).

Как мы упоминали ранее, JWT из каталога tokenbroker, выписываются на период 25-27 часов. Но тот же Outlook не спрашивает нас про пароль спустя 27 часов после авторизации. Значит где-то ещё в системе должен быть механизм, ответственный за авторизацию и обновление этих самых tbres-файлов. Чтобы найти его мы осуществили старый хакерский трюк — запустили process monitor от sysinternals, чтобы узнать, кто же читает/создает эти файлы при работе того же outlook.  К нашему удивлению это был не сам Outlook, а библиотека AAD.core.dll внутри процесса taskshost.exe. Тогда мы решили отследить какие ещё файлы создаются/читаются этим же процессом в те же временные таймстлоты, что и tbres-файлы. Так наш взгляд приковали к себе другие файлы в каталоге AAD.brokerPlugin.

Расположение Def-файлов
Расположение Def-файлов
Содержимое def-файлов
Содержимое def-файлов

Эти файлы выглядят по-другому (см. рисунок выше), и мы не смогли бы найти их ранее, когда искали внутри пользовательских профилей на диске или в реестре по сигнатурам DPAPI-блобов (0x01000000D08C9d и AQAAANCMnd). Мы догадывались, что это, вероятно, зашифрованные файлики, и что aad.core.dll умеет с ними работать. Вот тут мы уже почти что собрались открыть IDA и начать раскручивать алгоритм расшифровки, но в последний момент, внимательно присмотревшись к заголовкам файлов, заметили, что это ASN-кодировка (MIIJU…). Неплохо бы посмотреть эти файлы с помощью какого-нибудь ASN-Editor-а. Так мы и сделали. И это сэкономило нам кучу времени и сил, так как глядя на эти файлы в ASN-Editor-е, мы быстро разобрались, как именно они сформированы, что на чём зашифровано, и как это всё раскрутить в обратную сторону (см. картинку с ASN).

Выше мы видим, что вначале идёт DPAPI-blob, а ниже подсказка, что он зашифрован на пользовательском мастер-ключе. Расшифровываем и получаем 32 байта. Идём ниже и видим некий OID 2.16.840.1.101.3.4.1.45 (aes256-wrap). Он сообщает, что полученные из DPAPI-bloba 32 байта – это ключ AES256 с помощью которого мы можем сделать unwrap идущих следом 40 байт. Делаем unwrap и снова получаем 32 байта. Ниже мы видим еще один очень похожий OID 2.16.840.1.101.3.4.1.46 (aes256-GCM). Этот OID сообщает нам о том, что блок данных ниже зашифрован с помощью полученных ранее 32 байт ключа и представленных ниже 16 байт IV. С помощью AES256-GCM расшифровываем и получаем наконец-то «читаемые данные».

Промежуточный вывод: внимательно смотрите на заголовки зашифрованных файлов и не торопитесь проводить реверс.

PS. Забегая вперед, скажем что данный метод шифрования и хранения «чувствительной» информации пользователя принято называть DPAPI-NG. В отличие от DPAPI, где используются всего 4 наших любимых функции, здесь их побольше, но глобально это влияет на процесс расшифрования. DPAPI-NG = DPAPI+AES256-wrap+AES256-GCM

4. Def-файл — что внутри???

В итоге, после некоторых криптографических операций (произведенных в уме )) ), мы можем заглянуть внутрь def-файлов:

Содержимое def-файла
Содержимое def-файла
Содержимое def-файла
Содержимое def-файла

Как и предполагалось, def-файл содержит в себе refresh-token (начинается с символов 0.AX…), используемый AAD.Core для обновления JWT. Помимо refresh-токена, в файле присутствуют JWT access токены, очевидно полученные с помощью refresh-токенов. Правда, в отличие от JWT из tokenbroker, эти JWT действительны только в течение 1 часа после выпуска. Также в файле присутствуют URL и Microsoft application ID (уникальный GUID, определяющий облачное приложение в инфраструктуре Microsoft), указывающие на область действия refresh и access токенов (ресурс в облаке Microsoft).

Внутри каталога AAD.BrokerPlugin\LocalState находятся несколько подкаталогов со специфичными псевдослучайными названиями. В зависимости от количества установленных в системе приложений, таких каталогов, как правило, насчитывается штук 10-15. Но имена у них всегда одинаковые на всех системах  независимо от версии, битности операционной системы, или самого приложения. Так, например, для офисных приложений это имя c_ko4enbntgqc0mpmhkk69sogh. Внутри этих подкаталогов расположены def-файлы, содержащие уже непосредственно данные для самих приложений.

Исходя их этих данных, а также из полей внутри JWT, нам удалось сопоставить имена каталогов с соответствующими приложениями:

Folder name

Application ID

Application

c_3r0dntpi0u9vqc0ill3i9ll5

00000003-0000-0000-c000-000000000000

Microsoft Edge

c_5tqmo206bh8vfla76cd5vern

00000003-0000-0000-c000-000000000000

Microsoft Edge

c_8ip5hoi6fgltcurag437b8a4

d7b530a4-7680-4c23-a8bf-c52c121d2e87

Microsoft News Feed

c_8mb8eds39r4rmn0oveg4gg5v

268761a2-03f3-40df-8a8b-c3db24145b6b

Microsoft Universal Store

c_ctqmpl92bqceifhvfidsid87

2d7f3606-b07d-41d1-b9d2-0d0c9296a6e8

Microsoft Bing Search

c_dfvl2iag0l1tvm5ebr5fp6mi

0ec893e0-5785-4de6-99da-4ed124e5296c

Microsoft Office UWP

c_g41imis28fo5k1g5u3oi0c3m

1fec8e78-bce4-4aaf-ab1b-5451cc387264

Microsoft Teams

c_ko4enbntgqc0mpmhkk69sogh

ab9b8c07-8f02-4f72-87fa-80105867a763

Microsoft OneDrive, Sharepoint

c_mi1cmdi10dtsodg6l5e346dh

d3590ed6-52b3-4102-aeff-aad2292ab01c

Microsoft Office (Outlook, Word, etc)

c_qoa64hl0pgeegkoogaqn91si

e9c51622-460d-4d3d-952d-966a5b1da34c

Microsoft Edge

c_qvppge7as2g0b934o4siqob9

6F7E0F60-9401-4F5b-98E2-CF15BD5Fd5E3

Microsoft Azure Client

c_r7qegm25pd88coqhscltnkiv

00000003-0000-0000-c000-000000000000

Microsoft Edge

c_3r0dntpi0u9vqc0ill3i9ll5

00000003-0000-0000-c000-000000000000

Microsoft Edge

c_8ip5hoi6fgltcurag437b8a4

d7b530a4-7680-4c23-a8bf-c52c121d2e87

Microsoft News Feed

c_g41imis28fo5k1g5u3oi0c3m

1fec8e78-bce4-4aaf-ab1b-5451cc387264

Microsoft Teams

Сам процесс авторизации в облаке Microsoft с помощью refresh_token-а показан на рисунке ниже:

Здесь мы видим запрос access_token-а для ресурса (resource=…) https://outlook.office365.com через refresh_token (refresh_token=…) с указанием application id (параметр client_id=…). В ответе на данный запрос (см. рисунок ниже) нам вернётся запрошенный access_token, область его действия (scope), а также новый refresh_token и время его валидности (refresh_token_expires_in) в секундах, что соответствует 14-ти дням.

Также следует обратить внимание на параметр запроса claims. Если в запросе он присутствует и равен {"access_token":{"xms_cc":{"values":["CP1"]}}}, то запрошенный access_token будет валиден 25 часов. Если же этот параметр опустить, то нам по-прежнему вернётся access_token, но в этом случае он будет действителен только в течение 1-го часа.

В принципе, указанная схема с refresh и access токенами – это стандартная схема авторизации OAUTH 2.0, несколько модернизированная, и измененная компанией Microsoft. Интересная её особенность заключается в том, что старые refresh-токены (равно как и access-токены, полученные с помощью них) не протухают после использования, как это предписывает стандарт OAUTH 2.0, а остаются рабочими на протяжении всего срока действия (в данном случае — 14 дней). То есть, теоретически (хотя мы это и не проверяли), через один refresh-токен можно «нагенерировать» себе бесконечное число новых refresh-токенов и все они будут рабочими в течении их срока жизни.

5. Инструментарий

Для авторизации в облаке Microsoft удобно использовать специализированный python-фреймворк от известного голландского ИБ-ресерчера Dirk-Jan’a ROADTools (https://github.com/dirkjanm/ROADtools). Данный фреймворк (в частности его консольный инструмент roadrecon) позволяет «обменять» refresh-токен на access+refresh. При этом для успешного «обмена» необходимо верно указать ресурс, для которого этот refresh был получен изначально, а так же clientid (application id), о котором мы говорили ранее. Пример такой авторизации с помощью refresh-токена и roadtools приведён на рисунке ниже:

Авторизация через refreshtoken
Авторизация через refreshtoken

Кстати, обратите внимание на объявление переменных REQUESTS_CA_BUNDLE и HTTPS_PROXY. Таким образом мы заставляем roadrecon работать через Burp, так как он использует Python библиотеку requests для отправки запросов. Достаточно указать эти переменные, чтобы все запросы requests полетели через наш прокси-сервер. Конечно же, только авторизацией через refresh-токен функционал этого фреймворка не ограничен, и в следующей части статьи мы вас познакомим с другими его возможностями.

В итоге, процесс эффективного использования Microsoft Cloud токенов в ходе вашего пентеста/редтима может выглядеть следующим образом:

  1. Прежде всего требуется получить с компьютера необходимые файлы: содержимое каталогов tokenbroker\cache и Microsoft.AAD.Brokerplugin\LocalState;

  2. Далее нужно получить необходимый DPAPI мастер-ключ. Как правило, для дешифровки нужен всего один мастерключ, Guid которого прописан в файле preferred, но обычно в ходе пентеста забирается весь каталог с мастерключами;

  3. Затем нам необходимо позаботиться о том, каким образом мы будем их расшифровывать. Для этого нам необходимы мастерключи DPAPI, а также наличие сида пользователя, и его пароль. Тут уже, как говорится, на ваш вкус и цвет. У каждого хорошего пентестера существует как минимум 10 способов узнать эти данные. Мы лишь добавим, что пароль пользователя также можно брутить через его мастерключи, а с недавних пор (кстати, стараниями авторов данной статьи) знаменитый hashcat тоже научился это делать. Скорость брутфорса, конечно, так себе, но сам метод рабочий;

  4. Далее с помощью фреймворка DPAPIck3 нужно провести расшифровку соответствующих tbres и def файлов:

Для расшифровки tbres-файлов можно использовать следующий скрипт из состава dpapick3:

iconv -f utf-16 -t utf-8 file.tbres | grep -aoP '"AQAAANC.*?"' | grep -P '[^"]' > /tmp/tmpjwtfile.txt;

./filegeneric.py --masterkey ../masterkeys/ --sid S-1-5-21-4276662192-3075548024-2561254612-1002 --password Password1 --base64file /tmp/tmpjwtfile.txt --outfile file.tbres.txt

 В данном случае мы сначала конвертируем файл из юникода в utf-8, затем с помощью регулярок и grep выбираем из json base64 dpapi-блоб (помните, мы писали, что все DAPAPI-блобы начинаются с AQAAANC), и пишем его во временный файл. А затем уже используем стандартный dpapi-декриптор, подав ему на вход каталог с мастерключами, SIDом пользователя, и его паролем. На выходе у скрипта  получится расшифрованный tbres.txt-файл. Еще раз заметим, что для расшифровки DPAPI требуется знать пароль пользователя. В случае, если компьютер, с которого были получены мастерключи доменный, то подойдет NTLM-хеш пользователя (т.к. вместо sha1 при PBKDF2 используется md4). Также, в случае доменного компьютера, для расшифровки DPAPI можно использовать RSA backup key, полученный с контроллера домена. Если же у Вас нет ни пароля, ни хеша, ни RSA ключа, не беда – пароль пользователя можно сбрутить по его мастерключу.

 Для расшифровки def-файлов AAD необходимо применить специальный скрипт из состава dapilab:

AADdecrypt.py --masterkey ../masterkeys/S-1-5-21-4276662192-3075548024-2561254612-1002 --sid S-1-5-21-4276662192-3075548024-2561254612-1002 --password Password1 --base64file a_k0d3p7ef9etr0bab3ndnhosd.def   --outfile a_k0d3p7ef9etr0bab3ndnhosd.def.txt

 На вход скрипту подается сам файл из AAD (параметр --base64file), каталог с мастерключами (параметр --masterkey), SID пользователя и его пароль.

Как мы говорили ранее, в случае, если компьютер является частью ActiveDirectory, вместо пользовательского пароля и SID, можно использовать закрытый RSA-ключ с контроллера домена в PEM-формате, указав его скрипту в качестве соответствующего  параметра (--pkey);

 5) После расшифровки tbres и def файлов необходимо проверить JWT access-токены на валидность (мы ведь помним, что access-токены действительны чуть более суток после выпуска). Это можно сделать с помощью linux-утилиты jwt или плагином для Burp’а, вставляя в специальное поле JWT по одному, и обращая внимание на поле exp. Но, согласитесь, что через linux-утилиту быстрее, так как можно всё сделать скриптом. Например, так:

for ff in $(grep -aRl "outlook" --include "*.tbres.txt" ./); do echo $ff; if [[ ! -z $ff  ]]; then cat $ff | strings| grep -a -oP "eyJ.*" |  jwt -show - >> "$ff"_decoded.txt ; fi ; done

 Тут мы ищем все tbres-файлы для Microsoft outlook (с соответствующим ключевым словом), выбираем из них все JWT, и прогоняем через утилиту (jwt –show - ). Результат пишем в файл.

 При анализе JWT помимо временных меток необходимо обращать внимание на параметр aud (audience) внутри JWT, так как не все овощи одинаково полезны access-токен от одного ресурса не подойдет к другому. Например, токен от Outlook.office365.com мы не сможем использовать для обращения к Sharepoint.

6. А чё там с логами.. ?

Вы, наверное, спросите, а зачем нам гоняться за access-токенами (тем более что они действуют всего лишь сутки) если у нас есть refresh, который действителен аж две недели? Вот тут мы вам откроем небольшую хитрость:

 Дело в том, что при использовании access-токена мы не оставляем авторизационных логов в облаке Microsoft! Имеются ввиду записи обо всех авторизациях в облачной инфраструктуре Microsoft, которые мы видим, когда заходим в раздел Account/MySignins. Ведь по сути Microsoft предполагает, что раз у нас есть access-токен, то мы уже прошли авторизацию, и наши запросы не нуждаются в дополнительном логировании. Тут действует полная аналогия с cookies и одноимённой атакой — pass-the-cookie.

Напротив, «обмен» refresh-токена на access-токен рождает в авторизационном лог-файле соответствующую запись, где будет фигурировать наш IP-адрес, User-Agent, ClientId (не в виде guid, а в виде текстового значения).

Нет, конечно же сам факт доступа к ресурсу с использованием access-токена можно отследить, но для этого требуется уже более глубокий анализ, а также активация сложных механизмов аудита Microsoft. Но, согласитесь, не каждый этим будет заниматься. Именно поэтому, с точки зрения пентестера (и уж тем более редтимера), использование access-токенов гораздо эффективнее в плане скрытности.

Если же нам не удалось найти ни одного подходящего с точки зрения аудиенции и временных меток access, тогда у нас не остается выхода, кроме как использовать refresh-токен (если с момента его получения не прошло 2 недели, конечно). Здесь нам access-токены тоже могут помочь, даже если они просрочены. Как мы уже говорили ранее, внутри access-токена записан IP-адрес клиента с которого был запрошен этот токен. Мы не знаем, зачем Microsoft это делает. Тем более, что компания это никак не отслеживает, и токен, выписанный с одного IP, может применяться у другого. Но для нас (редтимеров) это становится хорошей подсказкой. Оставим за гранью статьи различные варианты с поиском уязвимых роутеров в пределах подсетей этого IP. Скажем, что информация об IP-адресе даёт нам возможность спрятаться в авторизационных логах. Мы ищем рабочий прокси-сервер или vpn в этом же городе или регионе, что и исходный IP-адрес, и производим авторизацию по refresh-токену через этот прокси/vpn. Таким образом в логах Microsoft мы не сильно выделяемся, если только наш IP не фигурирует в базах QualityScore как malicious. В общем, с помощью roadrecon, curl, или того же Burp мы получаем новый access-токен на нужный нам сервис.

7. Пентестерские фантазии

После того как мы нашли или получили access-token, мы берем наш любимый инструмент в руки (будь то BurpSuite, python, ROADTools, да хоть скрипт с curl на bash), и реализуем все свои «грязные пентестерские фантазии», не боясь, что нас засекут в логах авторизации.

Пример такой вот «грязной фантазии» показан на рисунке ниже:

Доступ к outlook EWS с помощью ExchangeLib
Доступ к outlook EWS с помощью ExchangeLib

Здесь приведен так называемый python-scratch для работы с Microsoft Outlook EWS, про который мы подробно рассказывали в прошлой части статьи.

P.s. Не забудьте поставить соответствующий user-agent в скрипте, а то как-то странно, если pycurl побежит за почтой у пользователя.

Ещё один пример - Microsoft Onedrive, он же - Sharepoint. Почему «он же»? Потому, что по факту Onedrive для доступа к файлам использует API Sharepoint и выглядит это как показано на рисунке ниже:

Доступ к OneDrive с помощью access-token
Доступ к OneDrive с помощью access-token

Сценарий ещё одной «грязной фантазии»: на это раз мы читаем переписку пользователя в Microsoft Teams, смотрим отосланные им «дикпики», а также читаем мнения об ИБ-шном руководстве компании, и о том, как же его задолбала политика информационной безопасности по смене паролей, и вводе двухфакторной аутентификации в облаке Microsoft. Шутка. 2fa ему нравится. Иначе он не стал бы пересылать дикпики через Teams ))).

Только в случае данной «фантазии» всё немного сложнее, чем было прошлый раз с outlook и sharepoint. Во-первых, у MS Teams нет официально-документированного API. Компания Microsoft рекомендует всем использовать свой механизм Microsoft GRAPH для доступа к переписке. Но проблема в том, что само приложение Teams использует именно Teams API, а это значит, что вы навряд ли найдете access-токен для graph, который позволит получить доступ к переписке (нужен соответствующий scope: Chats.Read). Поэтому пришлось немного повозиться с бурпом чтобы найти нужные api-endpoints.

Для начала нам нужно с помощью access-токена получить так-называемый skype-token (все-таки Teams — это прежде всего Skype). Для этого нам нужен Access-токен на chatsvcagg.teams.microsoft.com:

Получение skypeToken
Получение skypeToken

Затем уже с помощью этого скайптокена мы получаем список всех переписок пользователя (считай, оглавление):

Потом по этому оглавлению бежим скриптом и собираем всю переписку:

Если в переписке есть файлы, то на них будет ссылка на sharepoint, а с ним мы уже умеем работать.

Если же кому не нравится работать через Burp или Python, то специально для вас комьюнити выпустило несколько неофициальных Teams клиентов. Выбирайте на вкус и цвет. Главное условие - клиент должен уметь авторизовываться по JWT. Например, мы можем порекомендовать разработку FossTeams (https://github.com/fossteams) – Teams клиент сделанный на Go и JS. В этом же репозитории есть неплохой неофициальный api на голанге, используя который можно создать свой инструментарий для выкачивания «грязных переписок».

FossTeams – неофициальный клиент для Microsoft Teams, работающий по JWT
FossTeams – неофициальный клиент для Microsoft Teams, работающий по JWT

8. Заключение

Итак, в первой части статьи вы познакомились с облачными токенами Microsoft, увидели, где они хранятся и как шифруются, а также, как их можно использовать для авторизации и получения данных. В следующей части мы расскажем о такой сущности как PRT (Primary Refresh Token), зачем он нужен, как работает, и как шифруется, а также, что происходит с токенами, если в операционной системе включен TPM (Trusted Platform Module).

Ставьте лайки, пишите в комментариях вопросы.

До встречи!

9. Ссылки

Комментарии (1)


  1. sshipilevsky
    17.09.2022 11:01

    Спасибо за разбор!
    Было бы интересно посмотреть, насколько эффективно помогают дополнительные инструменты Identity Protection в Azure AD от подобной "атаки":

    1) Conditional Access - по идее, если возможности доступа к O365 ограничены с помощью CA, то новый токен получить будет либо невозможно, либо доступ к ресурсам будет ограничен (в зависимости от политик CA)

    2) Continuous Access Evaluation - относительно новая фича, которая была добавлена в Azure AD, которая теперь выдает Access Token на более длительное время (около 30 часов, емнип), но в real-time мониторит user context на момент обращения с действительным токеном и может среагировать на резкие изменения в контексте (например Impossible Travel)