# Az - Entra ID (AzureAD) & Azure IAM

{{#include ../../../banners/hacktricks-training.md}}

## Informations de base

Azure Active Directory (Azure AD) sert de service basé sur le cloud de Microsoft pour la gestion des identités et des accès. Il est essentiel pour permettre aux employés de se connecter et d'accéder aux ressources, tant au sein qu'en dehors de l'organisation, englobant Microsoft 365, le portail Azure et une multitude d'autres applications SaaS. La conception d'Azure AD se concentre sur la fourniture de services d'identité essentiels, incluant principalement **l'authentification, l'autorisation et la gestion des utilisateurs**.

Les fonctionnalités clés d'Azure AD incluent **l'authentification multi-facteurs** et **l'accès conditionnel**, ainsi qu'une intégration transparente avec d'autres services de sécurité Microsoft. Ces fonctionnalités élèvent considérablement la sécurité des identités des utilisateurs et permettent aux organisations de mettre en œuvre et d'appliquer efficacement leurs politiques d'accès. En tant que composant fondamental de l'écosystème des services cloud de Microsoft, Azure AD est essentiel pour la gestion des identités des utilisateurs basée sur le cloud.

## Énumération

### **Connexion**

{{#tabs }}
{{#tab name="az cli" }}
```bash
az login #This will open the browser (if not use --use-device-code)
az login -u <username> -p <password> #Specify user and password
az login --identity #Use the current machine managed identity (metadata)
az login --identity -u /subscriptions/<subscriptionId>/resourcegroups/myRG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myID #Login with user managed identity

# Login as service principal
## With password
az login --service-principal -u <application ID> -p VerySecret --tenant contoso.onmicrosoft.com # Tenant can also be the tenant UUID
## With cert
az login --service-principal -u <application ID> -p ~/mycertfile.pem --tenant contoso.onmicrosoft.com

# Request access token (ARM)
az account get-access-token
# Request access token for different resource. Supported tokens: aad-graph, arm, batch, data-lake, media, ms-graph, oss-rdbms
az account get-access-token --resource-type aad-graph

# If you want to configure some defaults
az configure

# Get user logged-in already
az ad signed-in-user show

# Help
az find "vm" # Find vm commands
az vm -h # Get subdomains
az ad user list --query-examples # Get examples
```
{{#endtab }}

{{#tab name="Mg" }}
```bash
# Login Open browser
Connect-MgGraph

# Login with service principal secret
## App ID and Tenant ID of your Azure AD App Registration
$appId = "<appId>"
$tenantId = "<tenantId>"
$clientSecret = "<clientSecret>"
## Convert the client secret to a SecureString
$secureSecret = ConvertTo-SecureString -String $clientSecret -AsPlainText -Force
## Create a PSCredential object
$credential = New-Object System.Management.Automation.PSCredential ($appId, $secureSecret)
## Connect using client credentials
Connect-MgGraph -TenantId $tenantId -ClientSecretCredential $credential

# Login with token
$token = (az account get-access-token --resource https://graph.microsoft.com --query accessToken -o tsv)
$secureToken = ConvertTo-SecureString $token -AsPlainText -Force
Connect-MgGraph -AccessToken $secureToken

# Get token from session
Parameters = @{
Method     = "GET"
Uri        = "/v1.0/me"
OutputType = "HttpResponseMessage"
}
$Response = Invoke-MgGraphRequest @Parameters
$Headers = $Response.RequestMessage.Headers
$Headers.Authorization.Parameter


# Find commands
Find-MgGraphCommand -command *Mg*
```
{{#endtab }}

{{#tab name="Az" }}
```bash
Connect-AzAccount #Open browser
# Using credentials
$passwd = ConvertTo-SecureString "Welcome2022!" -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential("test@corp.onmicrosoft.com", $passwd)
Connect-AzAccount -Credential $creds

# Get Access Token
# Request access token to other endpoints: AadGraph, AnalysisServices, Arm, Attestation, Batch, DataLake, KeyVault, MSGraph, OperationalInsights, ResourceManager, Storage, Synapse
(ConvertFrom-SecureString (Get-AzAccessToken -ResourceTypeName Arm -AsSecureString).Token -AsPlainText)

# Connect with access token
Connect-AzAccount -AccountId test@corp.onmicrosoft.com [-AccessToken $ManagementToken] [-GraphAccessToken $AADGraphToken] [-MicrosoftGraphAccessToken $MicrosoftGraphToken] [-KeyVaultAccessToken $KeyVaultToken]

# Connect with Service principal/enterprise app secret
$password = ConvertTo-SecureString 'KWEFNOIRFIPMWL.--DWPNVFI._EDWWEF_ADF~SODNFBWRBIF' -AsPlainText -Force
$creds = New-Object
System.Management.Automation.PSCredential('2923847f-fca2-a420-df10-a01928bec653', $password)
Connect-AzAccount -ServicePrincipal -Credential $creds -Tenant 29sd87e56-a192-a934-bca3-0398471ab4e7d

#All the Azure AD cmdlets have the format *-AzAD*
Get-Command *azad*
#Cmdlets for other Azure resources have the format *Az*
Get-Command *az*
```
{{#endtab }}

{{#tab name="Raw PS" }}
```bash
#Using management
$Token = 'eyJ0eXAi..'
# List subscriptions
$URI = 'https://management.azure.com/subscriptions?api-version=2020-01-01'
$RequestParams = @{
Method  = 'GET'
Uri     = $URI
Headers = @{
'Authorization' = "Bearer $Token"
}
}
(Invoke-RestMethod @RequestParams).value

# Using graph
Invoke-WebRequest -Uri "https://graph.windows.net/myorganization/users?api-version=1.6" -Headers @{Authorization="Bearer {0}" -f $Token}
```
{{#endtab }}

{{#tab name="curl" }}
```bash
# Request tokens to access endpoints
# ARM
curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com&api-version=2017-09-01" -H secret:$IDENTITY_HEADER

# Vault
curl "$IDENTITY_ENDPOINT?resource=https://vault.azure.net&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
```
{{#endtab }}
{{#tab name="MS Graph" }}
```bash
Get-MgTenantRelationshipDelegatedAdminCustomer
# Install the Microsoft Graph PowerShell module if not already installed
Install-Module Microsoft.Graph -Scope CurrentUser

# Import the module
Import-Module Microsoft.Graph

# Login to Microsoft Graph
Connect-MgGraph -Scopes "User.Read.All", "Group.Read.All", "Directory.Read.All"

# Enumerate available commands in Microsoft Graph PowerShell
Get-Command -Module Microsoft.Graph*

# Example: List users
Get-MgUser -All

# Example: List groups
Get-MgGroup -All

# Example: Get roles assigned to a user
Get-MgUserAppRoleAssignment -UserId <UserId>

# Disconnect from Microsoft Graph
Disconnect-MgGraph
```
{{#endtab }}

{{#tab name="Azure AD" }}
```bash
Connect-AzureAD #Open browser
# Using credentials
$passwd = ConvertTo-SecureString "Welcome2022!" -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential ("test@corp.onmicrosoft.com", $passwd)
Connect-AzureAD -Credential $creds

# Using tokens
## AzureAD cannot request tokens, but can use AADGraph and MSGraph tokens to connect
Connect-AzureAD -AccountId test@corp.onmicrosoft.com -AadAccessToken $token
```
{{#endtab }}
{{#endtabs }}

Lorsque vous **vous connectez** via **CLI** à Azure avec n'importe quel programme, vous utilisez une **Application Azure** d'un **locataire** qui appartient à **Microsoft**. Ces Applications, comme celles que vous pouvez créer dans votre compte, **ont un identifiant client**. Vous **ne pourrez pas les voir toutes** dans les **listes d'applications autorisées** que vous pouvez voir dans la console, **mais elles sont autorisées par défaut**.

Par exemple, un **script powershell** qui **s'authentifie** utilise une application avec l'identifiant client **`1950a258-227b-4e31-a9cf-717495945fc2`**. Même si l'application n'apparaît pas dans la console, un administrateur système pourrait **bloquer cette application** afin que les utilisateurs ne puissent pas y accéder en utilisant des outils qui se connectent via cette application.

Cependant, il existe **d'autres identifiants clients** d'applications qui **vous permettront de vous connecter à Azure** :
```bash
# The important part is the ClientId, which identifies the application to login inside Azure

$token = Invoke-Authorize -Credential $credential `
-ClientId '1dfb5f98-f363-4b0f-b63a-8d20ada1e62d' `
-Scope 'Files.Read.All openid profile Sites.Read.All User.Read email' `
-Redirect_Uri "https://graphtryit-staging.azurewebsites.net/" `
-Verbose -Debug `
-InformationAction Continue

$token = Invoke-Authorize -Credential $credential `
-ClientId '65611c08-af8c-46fc-ad20-1888eb1b70d9' `
-Scope 'openid profile Sites.Read.All User.Read email' `
-Redirect_Uri "chrome-extension://imjekgehfljppdblckcmjggcoboemlah" `
-Verbose -Debug `
-InformationAction Continue

$token = Invoke-Authorize -Credential $credential `
-ClientId 'd3ce4cf8-6810-442d-b42e-375e14710095' `
-Scope 'openid' `
-Redirect_Uri "https://graphexplorer.azurewebsites.net/" `
-Verbose -Debug `
-InformationAction Continue
```
### Locataires

{{#tabs }}
{{#tab name="az cli" }}
```bash
# List tenants
az account tenant list
```
{{#endtab }}
{{#endtabs }}

### Utilisateurs

Pour plus d'informations sur les utilisateurs Entra ID, consultez :

{{#ref}}
../az-basic-information/
{{#endref}}

{{#tabs }}
{{#tab name="az cli" }}
```bash
# Enumerate users
az ad user list --output table
az ad user list --query "[].userPrincipalName"
# Get info of 1 user
az ad user show --id "test@corp.onmicrosoft.com"
# Search "admin" users
az ad user list --query "[].displayName" | findstr /i "admin"
az ad user list --query "[?contains(displayName,'admin')].displayName"
# Search attributes containing the word "password"
az ad user list | findstr /i "password" | findstr /v "null,"
# All users from Entra ID
az ad user list --query "[].{osi:onPremisesSecurityIdentifier,upn:userPrincipalName}[?osi==null]"
az ad user list --query "[?onPremisesSecurityIdentifier==null].displayName"
# All users synced from on-prem
az ad user list --query "[].{osi:onPremisesSecurityIdentifier,upn:userPrincipalName}[?osi!=null]"
az ad user list --query "[?onPremisesSecurityIdentifier!=null].displayName"
# Get groups where the user is a member
az ad user get-member-groups --id <email>
# Get roles assigned to the user in Azure (NOT in Entra ID)
az role assignment list --include-inherited --include-groups --include-classic-administrators true --assignee <email>
# Get ALL roles assigned in Azure in the current subscription (NOT in Entra ID)
az role assignment list --include-inherited --include-groups --include-classic-administrators true --all

# Get EntraID roles assigned to a user
## Get Token
export TOKEN=$(az account get-access-token --resource https://graph.microsoft.com/ --query accessToken -o tsv)
## Get users
curl -X GET "https://graph.microsoft.com/v1.0/users" \
-H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" | jq
## Get EntraID roles assigned to an user
curl -X GET "https://graph.microsoft.com/beta/rolemanagement/directory/transitiveRoleAssignments?\$count=true&\$filter=principalId%20eq%20'86b10631-ff01-4e73-a031-29e505565caa'" \
-H "Authorization: Bearer $TOKEN" \
-H "ConsistencyLevel: eventual" \
-H "Content-Type: application/json" | jq
## Get role details
curl -X GET "https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions/cf1c38e5-3621-4004-a7cb-879624dced7c" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" | jq
```
{{#endtab }}

{{#tab name="MS Graph" }}
```bash
# Enumerate users using Microsoft Graph PowerShell
Get-MgUser -All

# Get user details
Get-MgUser -UserId "test@corp.onmicrosoft.com" | Format-List *

# Search "admin" users
Get-MgUser -All | Where-Object { $_.DisplayName -like "*test*" } | Select-Object DisplayName

# Search attributes containing the word "password"
Get-MgUser -All | Where-Object { $_.AdditionalProperties.PSObject.Properties.Name -contains "password" }

# All users from Entra ID
Get-MgUser -Filter "startswith(userPrincipalName, 't')" -All | Select-Object DisplayName, UserPrincipalName

# Get groups where the user is a member
Get-MgUserMemberOf -UserId <UserId>

# Get roles assigned to the user in Entra ID
Get-MgUserAppRoleAssignment -UserId <UserId>

# List available commands in Microsoft Graph PowerShell
Get-Command -Module Microsoft.Graph.Users
```
{{#endtab }}

{{#tab name="Azure AD" }}
```bash
# Enumerate Users
Get-AzureADUser -All $true
Get-AzureADUser -All $true | select UserPrincipalName
# Get info of 1 user
Get-AzureADUser -ObjectId test@corp.onmicrosoft.com | fl
# Search "admin" users
Get-AzureADUser -SearchString "admin" #Search admin at the begining of DisplayName or userPrincipalName
Get-AzureADUser -All $true |?{$_.Displayname -match "admin"} #Search "admin" word in DisplayName
# Get all attributes of a user
Get-AzureADUser -ObjectId test@defcorphq.onmicrosoft.com|%{$_.PSObject.Properties.Name}
# Search attributes containing the word "password"
Get-AzureADUser -All $true |%{$Properties = $_;$Properties.PSObject.Properties.Name | % {if ($Properties.$_ -match 'password') {"$($Properties.UserPrincipalName) - $_ - $($Properties.$_)"}}}
# All users from AzureAD# All users from AzureAD
Get-AzureADUser -All $true | ?{$_.OnPremisesSecurityIdentifier -eq $null}
# All users synced from on-prem
Get-AzureADUser -All $true | ?{$_.OnPremisesSecurityIdentifier -ne $null}
# Objects created by a/any user
Get-AzureADUser [-ObjectId <email>] | Get-AzureADUserCreatedObject
# Devices owned by a user
Get-AzureADUserOwnedDevice -ObjectId test@corp.onmicrosoft.com
# Objects owned by a specific user
Get-AzureADUserOwnedObject -ObjectId test@corp.onmicrosoft.com
# Get groups & roles where the user is a member
Get-AzureADUserMembership -ObjectId 'test@corp.onmicrosoft.com'
# Get devices owned by a user
Get-AzureADUserOwnedDevice -ObjectId test@corp.onmicrosoft.com
# Get devices registered by a user
Get-AzureADUserRegisteredDevice -ObjectId test@defcorphq.onmicrosoft.com
# Apps where a user has a role (role not shown)
Get-AzureADUser -ObjectId roygcain@defcorphq.onmicrosoft.com | Get-AzureADUserAppRoleAssignment | fl *
# Get Administrative Units of a user
$userObj = Get-AzureADUser -Filter "UserPrincipalName eq 'bill@example.com'"
Get-AzureADMSAdministrativeUnit | where { Get-AzureADMSAdministrativeUnitMember -Id $_.Id | where { $_.Id -eq $userObj.ObjectId } }
```
{{#endtab }}

{{#tab name="Az" }}
```bash
# Enumerate users
Get-AzADUser
# Get details of a user
Get-AzADUser -UserPrincipalName test@defcorphq.onmicrosoft.com
# Search user by string
Get-AzADUser -SearchString "admin" #Search at the beginnig of DisplayName
Get-AzADUser | ?{$_.Displayname -match "admin"}
# Get roles assigned to a user
Get-AzRoleAssignment -SignInName test@corp.onmicrosoft.com
```
{{#endtab }}
{{#endtabs }}

#### Changer le mot de passe de l'utilisateur
```bash
$password = "ThisIsTheNewPassword.!123" | ConvertTo- SecureString -AsPlainText –Force

(Get-AzureADUser -All $true | ?{$_.UserPrincipalName -eq "victim@corp.onmicrosoft.com"}).ObjectId | Set- AzureADUserPassword -Password $password –Verbose
```
### MFA & Conditional Access Policies

Il est fortement recommandé d'ajouter MFA à chaque utilisateur, cependant, certaines entreprises ne le mettront pas en place ou pourraient le configurer avec un accès conditionnel : L'utilisateur sera **tenu de faire MFA si** il se connecte depuis un emplacement spécifique, un navigateur ou **une condition**. Ces politiques, si elles ne sont pas configurées correctement, pourraient être sujettes à des **bypasses**. Vérifiez :

{{#ref}}
../az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md
{{#endref}}

### Groups

Pour plus d'informations sur les groupes Entra ID, consultez :

{{#ref}}
../az-basic-information/
{{#endref}}

{{#tabs }}
{{#tab name="az cli" }}
```bash
# Enumerate groups
az ad group list
az ad group list --query "[].[displayName]" -o table
# Get info of 1 group
az ad group show --group <group>
# Get "admin" groups
az ad group list --query "[].displayName" | findstr /i "admin"
az ad group list --query "[?contains(displayName,'admin')].displayName"
# All groups from Entra ID
az ad group list --query "[].{osi:onPremisesSecurityIdentifier,displayName:displayName,description:description}[?osi==null]"
az ad group list --query "[?onPremisesSecurityIdentifier==null].displayName"
# All groups synced from on-prem
az ad group list --query "[].{osi:onPremisesSecurityIdentifier,displayName:displayName,description:description}[?osi!=null]"
az ad group list --query "[?onPremisesSecurityIdentifier!=null].displayName"
# Get members of group
az ad group member list --group <group> --query "[].userPrincipalName" -o table
# Check if member of group
az ad group member check --group "VM Admins" --member-id <id>
# Get which groups a group is member of
az ad group get-member-groups -g "VM Admins"
# Get roles assigned to the group in Azure (NOT in Entra ID)
az role assignment list --include-groups --include-classic-administrators true --assignee <group-id>

# To get Entra ID roles assigned check how it's done with users and use a group ID
```
{{#endtab }}

{{#tab name="Az" }}
```bash
# Get all groups
Get-AzADGroup
# Get details of a group
Get-AzADGroup -ObjectId <id>
# Search group by string
Get-AzADGroup -SearchString "admin" | fl * #Search at the beginnig of DisplayName
Get-AzADGroup |?{$_.Displayname -match "admin"}
# Get members of group
Get-AzADGroupMember -GroupDisplayName <resource_group_name>
# Get roles of group
Get-AzRoleAssignment -ResourceGroupName <resource_group_name>
```
{{#endtab }}
{{#tab name="MS Graph" }}
```bash
# Enumerate groups using Microsoft Graph PowerShell
Get-MgGroup -All

# Get group details
Get-MgGroup -GroupId <GroupId> | Format-List *

# Search "admin" groups
Get-MgGroup -All | Where-Object { $_.DisplayName -like "*admin*" } | Select-Object DisplayName

# Get members of a group
Get-MgGroupMember -GroupId <GroupId> -All

# Get groups a group is member of
Get-MgGroupMemberOf -GroupId <GroupId>

# Get roles assigned to the group in Entra ID
Get-MgGroupAppRoleAssignment -GroupId <GroupId>

# Get group owner
Get-MgGroupOwner -GroupId <GroupId>

# List available commands in Microsoft Graph PowerShell
Get-Command -Module Microsoft.Graph.Groups
```
{{#endtab }}
{{#tab name="Azure AD" }}
```bash
# Enumerate Groups
Get-AzureADGroup -All $true
# Get info of 1 group
Get-AzADGroup -DisplayName <resource_group_name> | fl
# Get "admin" groups
Get-AzureADGroup -SearchString "admin" | fl #Groups starting by "admin"
Get-AzureADGroup -All $true |?{$_.Displayname -match "admin"} #Groups with the word "admin"
# Get groups allowing dynamic membership
Get-AzureADMSGroup | ?{$_.GroupTypes -eq 'DynamicMembership'}
# All groups that are from Azure AD
Get-AzureADGroup -All $true | ?{$_.OnPremisesSecurityIdentifier -eq $null}
# All groups that are synced from on-prem (note that security groups are not synced)
Get-AzureADGroup -All $true | ?{$_.OnPremisesSecurityIdentifier -ne $null}
# Get members of a group
Get-AzureADGroupMember -ObjectId <group_id>
# Get roles of group
Get-AzureADMSGroup -SearchString "Contoso_Helpdesk_Administrators" #Get group id
Get-AzureADMSRoleAssignment -Filter "principalId eq '69584002-b4d1-4055-9c94-320542efd653'"
# Get Administrative Units of a group
$groupObj = Get-AzureADGroup -Filter "displayname eq 'TestGroup'"
Get-AzureADMSAdministrativeUnit | where { Get-AzureADMSAdministrativeUnitMember -Id $_.Id | where {$_.Id -eq $groupObj.ObjectId} }
# Get Apps where a group has a role (role not shown)
Get-AzureADGroup -ObjectId <id> | Get-AzureADGroupAppRoleAssignment | fl *
```
{{#endtab }}
{{#endtabs }}

#### Ajouter un utilisateur au groupe

Les propriétaires du groupe peuvent ajouter de nouveaux utilisateurs au groupe
```bash
Add-AzureADGroupMember -ObjectId <group_id> -RefObjectId <user_id> -Verbose
```
> [!WARNING]
> Les groupes peuvent être dynamiques, ce qui signifie essentiellement que **si un utilisateur remplit certaines conditions, il sera ajouté à un groupe**. Bien sûr, si les conditions sont basées sur des **attributs** qu'un **utilisateur** peut **contrôler**, il pourrait abuser de cette fonctionnalité pour **entrer dans d'autres groupes**.\
> Vérifiez comment abuser des groupes dynamiques sur la page suivante :

{{#ref}}
../az-privilege-escalation/az-entraid-privesc/dynamic-groups.md
{{#endref}}

### Principaux de service

Pour plus d'informations sur les principaux de service Entra ID, consultez :

{{#ref}}
../az-basic-information/
{{#endref}}

{{#tabs }}
{{#tab name="az cli" }}
```bash
# Get Service Principals
az ad sp list --all
az ad sp list --all --query "[].[displayName,appId]" -o table
# Get details of one SP
az ad sp show --id 00000000-0000-0000-0000-000000000000
# Search SP by string
az ad sp list --all --query "[?contains(displayName,'app')].displayName"
# Get owner of service principal
az ad sp owner list --id <id> --query "[].[displayName]" -o table
# Get service principals owned by the current user
az ad sp list --show-mine

# Get SPs with generated secret or certificate
az ad sp list --query '[?length(keyCredentials) > `0` || length(passwordCredentials) > `0`].[displayName, appId, keyCredentials, passwordCredentials]' -o json
```
{{#endtab }}

{{#tab name="Az" }}
```bash
# Get SPs
Get-AzADServicePrincipal
# Get info of 1 SP
Get-AzADServicePrincipal -ObjectId <id>
# Search SP by string
Get-AzADServicePrincipal | ?{$_.DisplayName -match "app"}
# Get roles of a SP
Get-AzRoleAssignment -ServicePrincipalName <String>
```
{{#endtab }}

{{#tab name="Raw" }}
```bash
$Token = 'eyJ0eX..'
$URI = 'https://graph.microsoft.com/v1.0/applications'
$RequestParams = @{
Method  = 'GET'
Uri     = $URI
Headers = @{
'Authorization' = "Bearer $Token"
}
}
(Invoke-RestMethod @RequestParams).value
```
{{#endtab }}
{{#tab name="MS Graph" }}
```bash
# Get Service Principals using Microsoft Graph PowerShell
Get-MgServicePrincipal -All

# Get details of one Service Principal
Get-MgServicePrincipal -ServicePrincipalId <ServicePrincipalId> | Format-List *

# Search SP by display name
Get-MgServicePrincipal -All | Where-Object { $_.DisplayName -like "*app*" } | Select-Object DisplayName

# Get owner of Service Principal
Get-MgServicePrincipalOwner -ServicePrincipalId <ServicePrincipalId>

# Get objects owned by a Service Principal
Get-MgServicePrincipalOwnedObject -ServicePrincipalId <ServicePrincipalId>

# Get groups where the SP is a member
Get-MgServicePrincipalMemberOf -ServicePrincipalId <ServicePrincipalId>

# List available commands in Microsoft Graph PowerShell
Get-Command -Module Microsoft.Graph.ServicePrincipals
```
{{#endtab }}

{{#tab name="Azure AD" }}
```bash
# Get Service Principals
Get-AzureADServicePrincipal -All $true
# Get details about a SP
Get-AzureADServicePrincipal -ObjectId <id> | fl *
# Get SP by string name or Id
Get-AzureADServicePrincipal -All $true | ?{$_.DisplayName -match "app"} | fl
Get-AzureADServicePrincipal -All $true | ?{$_.AppId -match "103947652-1234-5834-103846517389"}
# Get owner of SP
Get-AzureADServicePrincipal -ObjectId <id> | Get-AzureADServicePrincipalOwner |fl *
# Get objects owned by a SP
Get-AzureADServicePrincipal -ObjectId <id> | Get-AzureADServicePrincipalOwnedObject
# Get objects created by a SP
Get-AzureADServicePrincipal -ObjectId <id> | Get-AzureADServicePrincipalCreatedObject
# Get groups where the SP is a member
Get-AzureADServicePrincipal | Get-AzureADServicePrincipalMembership
Get-AzureADServicePrincipal -ObjectId <id> | Get-AzureADServicePrincipalMembership |fl *
```
{{#endtab }}
{{#endtabs }}

> [!WARNING]
> Le propriétaire d'un Service Principal peut changer son mot de passe.

<details>

<summary>Listez et essayez d'ajouter un secret client sur chaque application d'entreprise</summary>
```bash
# Just call Add-AzADAppSecret
Function Add-AzADAppSecret
{
<#
.SYNOPSIS
Add client secret to the applications.

.PARAMETER GraphToken
Pass the Graph API Token

.EXAMPLE
PS C:\> Add-AzADAppSecret -GraphToken 'eyJ0eX..'

.LINK
https://docs.microsoft.com/en-us/graph/api/application-list?view=graph-rest-1.0&tabs=http
https://docs.microsoft.com/en-us/graph/api/application-addpassword?view=graph-rest-1.0&tabs=http
#>

[CmdletBinding()]
param(
[Parameter(Mandatory=$True)]
[String]
$GraphToken = $null
)

$AppList = $null
$AppPassword = $null

# List All the Applications

$Params = @{
"URI"     = "https://graph.microsoft.com/v1.0/applications"
"Method"  = "GET"
"Headers" = @{
"Content-Type"  = "application/json"
"Authorization" = "Bearer $GraphToken"
}
}

try
{
$AppList = Invoke-RestMethod @Params -UseBasicParsing
}
catch
{
}

# Add Password in the Application

if($AppList -ne $null)
{
[System.Collections.ArrayList]$Details = @()

foreach($App in $AppList.value)
{
$ID = $App.ID
$psobj = New-Object PSObject

$Params = @{
"URI"     = "https://graph.microsoft.com/v1.0/applications/$ID/addPassword"
"Method"  = "POST"
"Headers" = @{
"Content-Type"  = "application/json"
"Authorization" = "Bearer $GraphToken"
}
}

$Body = @{
"passwordCredential"= @{
"displayName" = "Password"
}
}

try
{
$AppPassword = Invoke-RestMethod @Params -UseBasicParsing -Body ($Body | ConvertTo-Json)
Add-Member -InputObject $psobj -NotePropertyName "Object ID" -NotePropertyValue $ID
Add-Member -InputObject $psobj -NotePropertyName "App ID" -NotePropertyValue $App.appId
Add-Member -InputObject $psobj -NotePropertyName "App Name" -NotePropertyValue $App.displayName
Add-Member -InputObject $psobj -NotePropertyName "Key ID" -NotePropertyValue $AppPassword.keyId
Add-Member -InputObject $psobj -NotePropertyName "Secret" -NotePropertyValue $AppPassword.secretText
$Details.Add($psobj) | Out-Null
}
catch
{
Write-Output "Failed to add new client secret to '$($App.displayName)' Application."
}
}
if($Details -ne $null)
{
Write-Output ""
Write-Output "Client secret added to : "
Write-Output $Details | fl *
}
}
else
{
Write-Output "Failed to Enumerate the Applications."
}
}
```
</details>

### Applications

Pour plus d'informations sur les Applications, consultez :

{{#ref}}
../az-basic-information/
{{#endref}}

Lorsqu'une application est générée, 2 types de permissions sont accordées :

- **Permissions** accordées au **Service Principal**
- **Permissions** que l'**application** peut avoir et utiliser **au nom de l'utilisateur**.

{{#tabs }}
{{#tab name="az cli" }}
```bash
# List Apps
az ad app list
az ad app list --query "[].[displayName,appId]" -o table
# Get info of 1 App
az ad app show --id 00000000-0000-0000-0000-000000000000
# Search App by string
az ad app list --query "[?contains(displayName,'app')].displayName"
# Get the owner of an application
az ad app owner list --id <id> --query "[].[displayName]" -o table
# Get SPs owned by current user
az ad app list --show-mine
# Get apps with generated secret or certificate
az ad app list --query '[?length(keyCredentials) > `0` || length(passwordCredentials) > `0`].[displayName, appId, keyCredentials, passwordCredentials]' -o json
# Get Global Administrators (full access over apps)
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles/1b2256f9-46c1-4fc2-a125-5b2f51bb43b7/members"
# Get Application Administrators (full access over apps)
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles/1e92c3b7-2363-4826-93a6-7f7a5b53e7f9/members"
# Get Cloud Applications Administrators (full access over apps)
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles/0d601d27-7b9c-476f-8134-8e7cd6744f02/members"

```
{{#endtab }}

{{#tab name="Az" }}
```bash
# Get Apps
Get-AzADApplication
# Get details of one App
Get-AzADApplication -ObjectId <id>
# Get App searching by string
Get-AzADApplication | ?{$_.DisplayName -match "app"}
# Get Apps with password
Get-AzADAppCredential
```
{{#endtab }}

{{#tab name="MS Graph" }}
```bash
# List Applications using Microsoft Graph PowerShell
Get-MgApplication -All

# Get application details
Get-MgApplication -ApplicationId 7861f72f-ad49-4f8c-96a9-19e6950cffe1 | Format-List *

# Search App by display name
Get-MgApplication -Filter "startswith(displayName, 'app')" | Select-Object DisplayName

# Get owner of an application
Get-MgApplicationOwner -ApplicationId <ApplicationId>

# List available commands in Microsoft Graph PowerShell
Get-Command -Module Microsoft.Graph.Applications
```
{{#endtab }}

{{#tab name="Azure AD" }}
```bash
# List all registered applications
Get-AzureADApplication -All $true
# Get details of an application
Get-AzureADApplication -ObjectId <id>  | fl *
# List all the apps with an application password
Get-AzureADApplication -All $true | %{if(Get-AzureADApplicationPasswordCredential -ObjectID $_.ObjectID){$_}}
# Get owner of an application
Get-AzureADApplication -ObjectId <id> | Get-AzureADApplicationOwner |fl *
```
{{#endtab }}
{{#endtabs }}

> [!WARNING]
> Une application avec la permission **`AppRoleAssignment.ReadWrite`** peut **s'élever au statut d'Administrateur Global** en se donnant le rôle.\
> Pour plus d'informations [**vérifiez ceci**](https://posts.specterops.io/azure-privilege-escalation-via-azure-api-permissions-abuse-74aee1006f48).

> [!NOTE]
> Une chaîne secrète que l'application utilise pour prouver son identité lors de la demande d'un jeton est le mot de passe de l'application.\
> Donc, si vous trouvez ce **mot de passe**, vous pouvez accéder en tant que **service principal** **à l'intérieur** du **locataire**.\
> Notez que ce mot de passe n'est visible que lors de sa génération (vous pouvez le changer mais vous ne pouvez pas le récupérer).\
> Le **propriétaire** de l'**application** peut **ajouter un mot de passe** à celle-ci (afin qu'il puisse l'usurper).\
> Les connexions en tant que ces services principaux ne sont **pas marquées comme risquées** et elles **n'auront pas de MFA.**

Il est possible de trouver une liste d'ID d'application couramment utilisés appartenant à Microsoft sur [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)

### Identités Gérées

Pour plus d'informations sur les Identités Gérées, consultez :

{{#ref}}
../az-basic-information/
{{#endref}}

{{#tabs }}
{{#tab name="az cli" }}
```bash
# List all manged identities
az identity list --output table
# With the principal ID you can continue the enumeration in service principals
```
{{#endtab }}
{{#endtabs }}

### Rôles Azure

Pour plus d'informations sur les rôles Azure, consultez :

{{#ref}}
../az-basic-information/
{{#endref}}

{{#tabs }}
{{#tab name="az cli" }}
```bash
# Get roles
az role definition list
# Get all assigned roles
az role assignment list --all --query "[].roleDefinitionName"
az role assignment list --all | jq '.[] | .roleDefinitionName,.scope'
# Get info of 1 role
az role definition list --name "AzureML Registry User"
# Get only custom roles
az role definition list --custom-role-only
# Get only roles assigned to the resource group indicated
az role definition list --resource-group <resource_group>
# Get only roles assigned to the indicated scope
az role definition list --scope <scope>
# Get all the principals a role is assigned to
az role assignment list --all --query "[].{principalName:principalName,principalType:principalType,scope:scope,roleDefinitionName:roleDefinitionName}[?roleDefinitionName=='<ROLE_NAME>']"
# Get all the roles assigned to a user
az role assignment list --assignee "<email>" --all --output table
# Get all the roles assigned to a user by filtering
az role assignment list --all --query "[?principalName=='admin@organizationadmin.onmicrosoft.com']" --output table
# Get deny assignments
az rest --method GET --uri "https://management.azure.com/{scope}/providers/Microsoft.Authorization/denyAssignments?api-version=2022-04-01"
## Example scope of subscription
az rest --method GET --uri "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/providers/Microsoft.Authorization/denyAssignments?api-version=2022-04-01"
```
{{#endtab }}

{{#tab name="MS Graph" }}
```bash

# List all available role templates using Microsoft Graph PowerShell
Get-MgDirectoryRoleTemplate -All

# List enabled built-in Entra ID roles
Get-MgDirectoryRole -All

# List all Entra ID roles with their permissions (including custom roles)
Get-MgDirectoryRoleDefinition -All

# List members of a Entra ID role
Get-MgDirectoryRoleMember -DirectoryRoleId <RoleId> -All

# List available commands in Microsoft Graph PowerShell
Get-Command -Module Microsoft.Graph.Identity.DirectoryManagement
```
{{#endtab }}

{{#tab name="Az" }}
```bash
# Get role assignments on the subscription
Get-AzRoleDefinition
# Get Role definition
Get-AzRoleDefinition -Name "Virtual Machine Command Executor"
# Get roles of a user or resource
Get-AzRoleAssignment -SignInName test@corp.onmicrosoft.com
Get-AzRoleAssignment -Scope /subscriptions/<subscription-id>/resourceGroups/<res_group_name>/providers/Microsoft.Compute/virtualMachines/<vm_name>
# Get deny assignments
Get-AzDenyAssignment # Get from current subscription
Get-AzDenyAssignment -Scope '/subscriptions/96231a05-34ce-4eb4-aa6a-70759cbb5e83/resourcegroups/testRG/providers/Microsoft.Web/sites/site1'
```
{{#tab name="Brut" }}
```bash
# Get permissions over a resource using ARM directly
$Token = (Get-AzAccessToken).Token
$URI = 'https://management.azure.com/subscriptions/b413826f-108d-4049-8c11-d52d5d388768/resourceGroups/Research/providers/Microsoft.Compute/virtualMachines/infradminsrv/providers/Microsoft.Authorization/permissions?api-version=2015-07-01'
$RequestParams = @{
Method = 'GET'
Uri = $URI
Headers = @{
'Authorization' = "Bearer $Token"
}
}
(Invoke-RestMethod @RequestParams).value
```
{{#endtab }}
{{#endtabs }}

### Rôles Entra ID

Pour plus d'informations sur les rôles Azure, consultez :

{{#ref}}
../az-basic-information/
{{#endref}}

{{#tabs }}
{{#tab name="az cli" }}
```bash
# List template Entra ID roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/directoryRoleTemplates"

# List enabled built-in Entra ID roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/directoryRoles"

# List all Entra ID roles with their permissions (including custom roles)
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions"

# List only custom Entra ID roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions" | jq '.value[] | select(.isBuiltIn == false)'

# List all assigned Entra ID roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments"

# List members of a Entra ID roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/directoryRoles/<role-id>/members"

# List Entra ID roles assigned to a user
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/users/<user-id>/memberOf/microsoft.graph.directoryRole" \
--query "value[]" \
--output json

# List Entra ID roles assigned to a group
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/groups/$GROUP_ID/memberOf/microsoft.graph.directoryRole" \
--query "value[]" \
--output json

# List Entra ID roles assigned to a service principal
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/servicePrincipals/$SP_ID/memberOf/microsoft.graph.directoryRole" \
--query "value[]" \
--output json
```
{{#endtab }}

{{#tab name="Azure AD" }}
```bash
# Get all available role templates
Get-AzureADDirectoryroleTemplate
# Get enabled roles (Assigned roles)
Get-AzureADDirectoryRole
Get-AzureADDirectoryRole -ObjectId <roleID> #Get info about the role
# Get custom roles - use AzureAdPreview
Get-AzureADMSRoleDefinition | ?{$_.IsBuiltin -eq $False} | select DisplayName
# Users assigned a role (Global Administrator)
Get-AzureADDirectoryRole -Filter "DisplayName eq 'Global Administrator'" | Get-AzureADDirectoryRoleMember
Get-AzureADDirectoryRole -ObjectId <id> | fl
# Roles of the Administrative Unit (who has permissions over the administrative unit and its members)
Get-AzureADMSScopedRoleMembership -Id <id> | fl *
```
{{#endtab }}
{{#endtabs }}

### Appareils

{{#tabs }}
{{#tab name="az cli" }}
```bash
# If you know how to do this send a PR!
```
{{#endtab }}
{{#tab name="MS Graph" }}
```bash
# Enumerate devices using Microsoft Graph PowerShell
Get-MgDevice -All

# Get device details
Get-MgDevice -DeviceId <DeviceId> | Format-List *

# Get devices managed using Intune
Get-MgDevice -Filter "isCompliant eq true" -All

# Get devices owned by a user
Get-MgUserOwnedDevice -UserId test@corp.onmicrosoft.com

# List available commands in Microsoft Graph PowerShell
Get-Command -Module Microsoft.Graph.Identity.DirectoryManagement
```
{{#endtab }}

{{#tab name="Azure AD" }}
```bash
# Enumerate Devices
Get-AzureADDevice -All $true | fl *
# List all the active devices (and not the stale devices)
Get-AzureADDevice -All $true | ?{$_.ApproximateLastLogonTimeStamp -ne $null}
# Get owners of all devices
Get-AzureADDevice -All $true | Get-AzureADDeviceRegisteredOwner
Get-AzureADDevice -All $true | %{if($user=Get-AzureADDeviceRegisteredOwner -ObjectId $_.ObjectID){$_;$user.UserPrincipalName;"`n"}}
# Registred users of all the devices
Get-AzureADDevice -All $true | Get-AzureADDeviceRegisteredUser
Get-AzureADDevice -All $true | %{if($user=Get-AzureADDeviceRegisteredUser -ObjectId $_.ObjectID){$_;$user.UserPrincipalName;"`n"}}
# Get dives managed using Intune
Get-AzureADDevice -All $true | ?{$_.IsCompliant -eq "True"}
# Get devices owned by a user
Get-AzureADUserOwnedDevice -ObjectId test@corp.onmicrosoft.com
# Get Administrative Units of a device
Get-AzureADMSAdministrativeUnit | where { Get-AzureADMSAdministrativeUnitMember -ObjectId $_.ObjectId | where {$_.ObjectId -eq $deviceObjId} }
```
{{#endtab }}
{{#endtabs }}

> [!WARNING]
> Si un appareil (VM) est **joint à AzureAD**, les utilisateurs d'AzureAD vont **pouvoir se connecter**.\
> De plus, si l'utilisateur connecté est **Propriétaire** de l'appareil, il sera **administrateur local**.

### Unités administratives

Pour plus d'informations sur les unités administratives, consultez :

{{#ref}}
../az-basic-information/
{{#endref}}

{{#tabs }}
{{#tab name="az cli" }}
```bash
# List all administrative units
az rest --method GET --uri "https://graph.microsoft.com/v1.0/directory/administrativeUnits"
# Get AU info
az rest --method GET --uri "https://graph.microsoft.com/v1.0/directory/administrativeUnits/a76fd255-3e5e-405b-811b-da85c715ff53"
# Get members
az rest --method GET --uri "https://graph.microsoft.com/v1.0/directory/administrativeUnits/a76fd255-3e5e-405b-811b-da85c715ff53/members"
# Get principals with roles over the AU
az rest --method GET --uri "https://graph.microsoft.com/v1.0/directory/administrativeUnits/a76fd255-3e5e-405b-811b-da85c715ff53/scopedRoleMembers"
```
{{#endtab }}

{{#tab name="AzureAD" }}
```bash
# Get Administrative Units
Get-AzureADMSAdministrativeUnit
Get-AzureADMSAdministrativeUnit -Id <id>
# Get ID of admin unit by string
$adminUnitObj = Get-AzureADMSAdministrativeUnit -Filter "displayname eq 'Test administrative unit 2'"
# List the users, groups, and devices affected by the administrative unit
Get-AzureADMSAdministrativeUnitMember -Id <id>
# Get the roles users have over the members of the AU
Get-AzureADMSScopedRoleMembership -Id <id> | fl #Get role ID and role members
```
{{#endtab }}
{{#endtabs }}

## Escalade de privilèges Entra ID

{{#ref}}
../az-privilege-escalation/az-entraid-privesc/
{{#endref}}

## Escalade de privilèges Azure

{{#ref}}
../az-privilege-escalation/az-authorization-privesc.md
{{#endref}}

## Mécanismes de défense

### Gestion des identités privilégiées (PIM)

La Gestion des identités privilégiées (PIM) dans Azure aide à **prévenir l'attribution de privilèges excessifs** aux utilisateurs de manière inutile.

L'une des principales fonctionnalités fournies par PIM est qu'elle permet de ne pas attribuer de rôles à des principaux qui sont constamment actifs, mais de les rendre **éligibles pour une période de temps (par exemple, 6 mois)**. Ensuite, chaque fois que l'utilisateur souhaite activer ce rôle, il doit en faire la demande en indiquant le temps pendant lequel il a besoin du privilège (par exemple, 3 heures). Ensuite, un **administrateur doit approuver** la demande.\
Notez que l'utilisateur pourra également demander à **prolonger** le temps.

De plus, **PIM envoie des e-mails** chaque fois qu'un rôle privilégié est attribué à quelqu'un.

<figure><img src="../../../images/image (354).png" alt=""><figcaption></figcaption></figure>

Lorsque PIM est activé, il est possible de configurer chaque rôle avec certaines exigences telles que :

- Durée maximale (heures) d'activation
- Exiger MFA lors de l'activation
- Exiger un contexte d'authentification d'accès conditionnel
- Exiger une justification lors de l'activation
- Exiger des informations sur le ticket lors de l'activation
- Exiger une approbation pour activer
- Temps maximum pour expirer les attributions éligibles
- Beaucoup plus de configurations sur quand et qui envoyer des notifications lorsque certaines actions se produisent avec ce rôle

### Politiques d'accès conditionnel

Vérifiez :

{{#ref}}
../az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md
{{#endref}}

### Protection des identités Entra

La Protection des identités Entra est un service de sécurité qui permet de **détecter lorsqu'un utilisateur ou une connexion est trop risqué** pour être accepté, permettant de **bloquer** l'utilisateur ou la tentative de connexion.

Il permet à l'administrateur de le configurer pour **bloquer** les tentatives lorsque le risque est "Faible et au-dessus", "Moyen et au-dessus" ou "Élevé". Cependant, par défaut, il est complètement **désactivé** :

<figure><img src="../../../images/image (356).png" alt=""><figcaption></figcaption></figure>

> [!TIP]
> De nos jours, il est recommandé d'ajouter ces restrictions via des politiques d'accès conditionnel où il est possible de configurer les mêmes options.

### Protection par mot de passe Entra

La Protection par mot de passe Entra ([https://portal.azure.com/index.html#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade](https://portal.azure.com/#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade)) est une fonctionnalité de sécurité qui **aide à prévenir l'abus de mots de passe faibles en verrouillant les comptes lorsque plusieurs tentatives de connexion infructueuses se produisent**.\
Elle permet également de **interdire une liste de mots de passe personnalisée** que vous devez fournir.

Elle peut être **appliquée à la fois** au niveau du cloud et sur Active Directory sur site.

Le mode par défaut est **Audit** :

<figure><img src="../../../images/image (355).png" alt=""><figcaption></figcaption></figure>

## Références

- [https://learn.microsoft.com/en-us/azure/active-directory/roles/administrative-units](https://learn.microsoft.com/en-us/azure/active-directory/roles/administrative-units)

{{#include ../../../banners/hacktricks-training.md}}
