Azure Active Directory (Azure AD) serves as Microsoft's cloud-based service for identity and access management. It is instrumental in enabling employees to sign in and gain access to resources, both within and beyond the organization, encompassing Microsoft 365, the Azure portal, and a multitude of other SaaS applications. The design of Azure AD focuses on delivering essential identity services, prominently including authentication, authorization, and user management.
Key features of Azure AD involve multi-factor authentication and conditional access, alongside seamless integration with other Microsoft security services. These features significantly elevate the security of user identities and empower organizations to effectively implement and enforce their access policies. As a fundamental component of Microsoft's cloud services ecosystem, Azure AD is pivotal for the cloud-based management of user identities.
Enumeration
Connection
azlogin#This will open the browser (if not use --use-device-code)azlogin-u<username>-p<password>#Specify user and passwordazlogin--identity#Use the current machine managed identity (metadata)azlogin--identity-u/subscriptions/<subscriptionId>/resourcegroups/myRG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myID#Login with user managed identity# Login as service principal## With passwordazlogin--service-principal-u<applicationID>-pVerySecret--tenantcontoso.onmicrosoft.com# Tenant can also be the tenant UUID## With certazlogin--service-principal-u<applicationID>-p~/mycertfile.pem--tenantcontoso.onmicrosoft.com# Request access token (ARM)azaccountget-access-token# Request access token for different resource. Supported tokens: aad-graph, arm, batch, data-lake, media, ms-graph, oss-rdbmsazaccountget-access-token--resource-typeaad-graph# If you want to configure some defaultsazconfigure# Get user logged-in alreadyazadsigned-in-usershow# Helpazfind"vm"# Find vm commandsazvm-h# Get subdomainsazaduserlist--query-examples# Get examples
# Login Open browserConnect-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 credentialsConnect-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 -ForceConnect-MgGraph-AccessToken $secureToken# Find commandsFind-MgGraphCommand-command *Mg*
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(Get-AzAccessToken).Token# Request access token to other endpoints: AadGraph, AnalysisServices, Arm, Attestation, Batch, DataLake, KeyVault, MSGraph, OperationalInsights, ResourceManager, Storage, Synapse(Get-AzAccessToken-ResourceTypeName MSGraph).Token(Get-AzAccessToken-Resource "https://graph.microsoft.com").Token# Connect with access tokenConnect-AzAccount-AccountId test@corp.onmicrosoft.com -AccessToken $tokenConnect-AzAccount-AccessToken $token -GraphAccessToken $graphaccesstoken -AccountId <ACCOUNT-ID>## The -AccessToken is from management.azure.com# 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*
#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 graphInvoke-WebRequest-Uri "https://graph.windows.net/myorganization/users?api-version=1.6"-Headers @{Authorization="Bearer {0}"-f $Token}
# Request tokens to access endpoints# ARMcurl"$IDENTITY_ENDPOINT?resource=https://management.azure.com&api-version=2017-09-01"-Hsecret:$IDENTITY_HEADER# Vaultcurl"$IDENTITY_ENDPOINT?resource=https://vault.azure.net&api-version=2017-09-01"-Hsecret:$IDENTITY_HEADER
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 connectConnect-AzureAD-AccountId test@corp.onmicrosoft.com -AadAccessToken $token
When you login via CLI into Azure with any program, you are using an Azure Application from a tenant that belongs to Microsoft. These Applications, like the ones you can create in your account, have a client id. You won't be able to see all of them in the allowed applications lists you can see in the console, but they are allowed by default.
For example a powershell script that authenticates use an app with client id 1950a258-227b-4e31-a9cf-717495945fc2. Even if the app doesn't appear in the console, a sysadmin could block that application so users cannot access using tools that connects via that App.
However, there are other client-ids of applications that will allow you to connect to Azure:
# 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
Tenants
# List tenantsazaccounttenantlist
Users
For more information about Entra ID users check:
# Enumerate usersazaduserlist--outputtableazaduserlist--query"[].userPrincipalName"# Get info of 1 userazadusershow--id"test@corp.onmicrosoft.com"# Search "admin" usersazaduserlist--query"[].displayName"|findstr/i"admin"azaduserlist--query"[?contains(displayName,'admin')].displayName"# Search attributes containing the word "password"azaduserlist|findstr/i"password"|findstr/v"null,"# All users from Entra IDazaduserlist--query"[].{osi:onPremisesSecurityIdentifier,upn:userPrincipalName}[?osi==null]"azaduserlist--query"[?onPremisesSecurityIdentifier==null].displayName"# All users synced from on-premazaduserlist--query"[].{osi:onPremisesSecurityIdentifier,upn:userPrincipalName}[?osi!=null]"azaduserlist--query"[?onPremisesSecurityIdentifier!=null].displayName"# Get groups where the user is a memberazaduserget-member-groups--id<email># Get roles assigned to the user in Azure (NOT in Entra ID)azroleassignmentlist--include-inherited--include-groups--include-classic-administratorstrue--assignee<email># Get ALL roles assigned in Azure in the current subscription (NOT in Entra ID)azroleassignmentlist--include-inherited--include-groups--include-classic-administratorstrue--all# Get EntraID roles assigned to a user## Get Tokenexport TOKEN=$(azaccountget-access-token--resourcehttps://graph.microsoft.com/--queryaccessToken-otsv)## Get userscurl-XGET"https://graph.microsoft.com/v1.0/users" \-H"Authorization: Bearer $TOKEN" \ -H"Content-Type: application/json"|jq## Get EntraID roles assigned to an usercurl-XGET"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 detailscurl-XGET"https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions/cf1c38e5-3621-4004-a7cb-879624dced7c" \-H "Authorization: Bearer $TOKEN" \-H "Content-Type: application/json"|jq
# Enumerate UsersGet-AzureADUser-All $trueGet-AzureADUser-All $true| select UserPrincipalName# Get info of 1 userGet-AzureADUser-ObjectId test@corp.onmicrosoft.com | fl# Search "admin" usersGet-AzureADUser-SearchString "admin"#Search admin at the begining of DisplayName or userPrincipalNameGet-AzureADUser-All $true|?{$_.Displayname-match"admin"} #Search "admin" word in DisplayName# Get all attributes of a userGet-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 AzureADGet-AzureADUser-All $true|?{$_.OnPremisesSecurityIdentifier-eq$null}# All users synced from on-premGet-AzureADUser-All $true|?{$_.OnPremisesSecurityIdentifier-ne$null}# Objects created by a/any userGet-AzureADUser [-ObjectId<email>] |Get-AzureADUserCreatedObject# Devices owned by a userGet-AzureADUserOwnedDevice-ObjectId test@corp.onmicrosoft.com# Objects owned by a specific userGet-AzureADUserOwnedObject-ObjectId test@corp.onmicrosoft.com# Get groups & roles where the user is a memberGet-AzureADUserMembership-ObjectId 'test@corp.onmicrosoft.com'# Get devices owned by a userGet-AzureADUserOwnedDevice-ObjectId test@corp.onmicrosoft.com# Get devices registered by a userGet-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 } }
# Enumerate usersGet-AzADUser# Get details of a userGet-AzADUser-UserPrincipalName test@defcorphq.onmicrosoft.com# Search user by stringGet-AzADUser-SearchString "admin"#Search at the beginnig of DisplayNameGet-AzADUser|?{$_.Displayname-match"admin"}# Get roles assigned to a userGet-AzRoleAssignment-SignInName test@corp.onmicrosoft.com
It's highly recommended to add MFA to every user, however, some companies won't set it or might set it with a Conditional Access: The user will be required MFA if it logs in from an specific location, browser or some condition. These policies, if not configured correctly might be prone to bypasses. Check:
Groups
For more information about Entra ID groups check:
# Enumerate groupsaz ad group listaz ad group list --query "[].[displayName]"-o table# Get info of 1 groupaz ad group show --group <group># Get "admin" groupsaz ad group list --query "[].displayName"| findstr /i "admin"az ad group list --query "[?contains(displayName,'admin')].displayName"# All groups from Entra IDaz 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-premaz ad group list --query "[].{osi:onPremisesSecurityIdentifier,displayName:displayName,description:description}[?osi!=null]"az ad group list --query "[?onPremisesSecurityIdentifier!=null].displayName"# Get members of groupaz ad group member list --group <group>--query "[].userPrincipalName"-o table# Check if member of groupaz ad group member check --group "VM Admins"--member-id <id># Get which groups a group is member ofaz 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
# Enumerate GroupsGet-AzureADGroup-All $true# Get info of 1 groupGet-AzADGroup-DisplayName <resource_group_name>| fl# Get "admin" groupsGet-AzureADGroup-SearchString "admin"| fl #Groups starting by "admin"Get-AzureADGroup-All $true|?{$_.Displayname-match"admin"} #Groups with the word "admin"# Get groups allowing dynamic membershipGet-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 groupGet-AzureADGroupMember-ObjectId <group_id># Get roles of groupGet-AzureADMSGroup-SearchString "Contoso_Helpdesk_Administrators"#Get group idGet-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 *
# Get all groupsGet-AzADGroup# Get details of a groupGet-AzADGroup-ObjectId <id># Search group by stringGet-AzADGroup-SearchString "admin"| fl *#Search at the beginnig of DisplayNameGet-AzADGroup|?{$_.Displayname-match"admin"}# Get members of groupGet-AzADGroupMember-GroupDisplayName <resource_group_name># Get roles of groupGet-AzRoleAssignment-ResourceGroupName <resource_group_name>
Add user to group
Owners of the group can add new users to the group
Groups can be dynamic, which basically means that if a user fulfil certain conditions it will be added to a group. Of course, if the conditions are based in attributes a user can control, he could abuse this feature to get inside other groups.
Check how to abuse dynamic groups in the following page:
Service Principals
For more information about Entra ID service principals check:
# Get Service Principalsazadsplist--allazadsplist--all--query"[].[displayName,appId]"-otable# Get details of one SPazadspshow--id00000000-0000-0000-0000-000000000000# Search SP by stringazadsplist--all--query"[?contains(displayName,'app')].displayName"# Get owner of service principalazadspownerlist--id<id>--query"[].[displayName]"-otable# Get service principals owned by the current userazadsplist--show-mine# Get SPs with generated secret or certificateazadsplist--query'[?length(keyCredentials) > `0` || length(passwordCredentials) > `0`].[displayName, appId, keyCredentials, passwordCredentials]'-ojson
# Get Service PrincipalsGet-AzureADServicePrincipal-All $true# Get details about a SPGet-AzureADServicePrincipal-ObjectId <id>| fl *# Get SP by string name or IdGet-AzureADServicePrincipal-All $true|?{$_.DisplayName-match"app"} | flGet-AzureADServicePrincipal-All $true|?{$_.AppId-match"103947652-1234-5834-103846517389"}# Get owner of SPGet-AzureADServicePrincipal-ObjectId <id>|Get-AzureADServicePrincipalOwner|fl *# Get objects owned by a SPGet-AzureADServicePrincipal-ObjectId <id>|Get-AzureADServicePrincipalOwnedObject# Get objects created by a SPGet-AzureADServicePrincipal-ObjectId <id>|Get-AzureADServicePrincipalCreatedObject# Get groups where the SP is a memberGet-AzureADServicePrincipal|Get-AzureADServicePrincipalMembershipGet-AzureADServicePrincipal-ObjectId <id>|Get-AzureADServicePrincipalMembership|fl *
# Get SPsGet-AzADServicePrincipal# Get info of 1 SPGet-AzADServicePrincipal-ObjectId <id># Search SP by stringGet-AzADServicePrincipal|?{$_.DisplayName-match"app"}# Get roles of a SPGet-AzRoleAssignment-ServicePrincipalName <String>
The Owner of a Service Principal can change its password.
List and try to add a client secret on each Enterprise App
# Just call Add-AzADAppSecretFunctionAdd-AzADAppSecret{<#.SYNOPSIS Add client secret to the applications..PARAMETERGraphToken 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 Applicationif($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 $IDAdd-Member-InputObject $psobj -NotePropertyName "App ID"-NotePropertyValue $App.appIdAdd-Member-InputObject $psobj -NotePropertyName "App Name"-NotePropertyValue $App.displayNameAdd-Member-InputObject $psobj -NotePropertyName "Key ID"-NotePropertyValue $AppPassword.keyIdAdd-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." }}
Applications
For more information about Applications check:
When an App is generated 2 types of permissions are given:
Permissions given to the Service Principal
Permissions the app can have and use on behalf of the user.
# List Appsazadapplistazadapplist--query"[].[displayName,appId]"-otable# Get info of 1 Appazadappshow--id00000000-0000-0000-0000-000000000000# Search App by stringazadapplist--query"[?contains(displayName,'app')].displayName"# Get the owner of an applicationazadappownerlist--id<id>--query"[].[displayName]"-otable# Get SPs owned by current userazadapplist--show-mine# Get apps with generated secret or certificateazadapplist--query'[?length(keyCredentials) > `0` || length(passwordCredentials) > `0`].[displayName, appId, keyCredentials, passwordCredentials]'-ojson
# List all registered applicationsGet-AzureADApplication-All $true# Get details of an applicationGet-AzureADApplication-ObjectId <id>| fl *# List all the apps with an application passwordGet-AzureADApplication-All $true|%{if(Get-AzureADApplicationPasswordCredential-ObjectID $_.ObjectID){$_}}# Get owner of an applicationGet-AzureADApplication-ObjectId <id>|Get-AzureADApplicationOwner|fl *
# Get AppsGet-AzADApplication# Get details of one AppGet-AzADApplication-ObjectId <id># Get App searching by stringGet-AzADApplication|?{$_.DisplayName-match"app"}# Get Apps with passwordGet-AzADAppCredential
An app with the permission AppRoleAssignment.ReadWrite can escalate to Global Admin by grating itself the role.
For more information check this.
A secret string that the application uses to prove its identity when requesting a token is the application password.
So, if find this password you can access as the service principalinside the tenant.
Note that this password is only visible when generated (you could change it but you cannot get it again).
The owner of the application can add a password to it (so he can impersonate it).
Logins as these service principals are not marked as risky and they won't have MFA.
For more information about Managed Identities check:
# List all manged identitiesazidentitylist--outputtable# With the principal ID you can continue the enumeration in service principals
Azure Roles
For more information about Azure roles check:
# Get rolesazroledefinitionlist# Get all assigned rolesazroleassignmentlist--all--query"[].roleDefinitionName"azroleassignmentlist--all|jq'.[] | .roleDefinitionName,.scope'# Get info of 1 roleazroledefinitionlist--name"AzureML Registry User"# Get only custom rolesazroledefinitionlist--custom-role-only# Get only roles assigned to the resource group indicatedazroledefinitionlist--resource-group<resource_group># Get only roles assigned to the indicated scopeazroledefinitionlist--scope<scope># Get all the principals a role is assigned toazroleassignmentlist--all--query"[].{principalName:principalName,principalType:principalType,resourceGroup:resourceGroup,roleDefinitionName:roleDefinitionName}[?roleDefinitionName=='<ROLE_NAME>']"# Get all the roles assigned to a userazroleassignmentlist--assignee"<email>"--all--outputtable# Get all the roles assigned to a user by filteringazroleassignmentlist--all--query"[?principalName=='carlos@carloshacktricks.onmicrosoft.com']"--outputtable
# Get role assignments on the subscriptionGet-AzRoleDefinition# Get Role definitionGet-AzRoleDefinition-Name "Virtual Machine Command Executor"# Get roles of a user or resourceGet-AzRoleAssignment-SignInName test@corp.onmicrosoft.comGet-AzRoleAssignment-Scope /subscriptions/<subscription-id>/resourceGroups/<res_group_name>/providers/Microsoft.Compute/virtualMachines/<vm_name>
# 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
Entra ID Roles
For more information about Azure roles check:
# List template Entra ID rolesazrest--methodGET \--uri"https://graph.microsoft.com/v1.0/directoryRoleTemplates"# List enabled built-in Entra ID rolesazrest--methodGET \--uri"https://graph.microsoft.com/v1.0/directoryRoles"# List all Entra ID roles with their permissions (including custom roles)azrest--methodGET \--uri"https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions"# List only custom Entra ID rolesazrest--methodGET \--uri"https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions"|jq'.value[] | select(.isBuiltIn == false)'# List all assigned Entra ID rolesazrest--methodGET \--uri"https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments"# List members of a Entra ID rolesazrest--methodGET \--uri"https://graph.microsoft.com/v1.0/directoryRoles/<role-id>/members"# List Entra ID roles assigned to a userazrest--methodGET \--uri"https://graph.microsoft.com/v1.0/users/<user-id>/memberOf/microsoft.graph.directoryRole" \--query"value[]" \--outputjson# List Entra ID roles assigned to a groupazrest--methodGET \--uri"https://graph.microsoft.com/v1.0/groups/$GROUP_ID/memberOf/microsoft.graph.directoryRole" \--query"value[]" \--outputjson# List Entra ID roles assigned to a service principalazrest--methodGET \--uri"https://graph.microsoft.com/v1.0/servicePrincipals/$SP_ID/memberOf/microsoft.graph.directoryRole" \--query"value[]" \--outputjson
# Get all available role templatesGet-AzureADDirectoryroleTemplate# Get enabled roles (Assigned roles)Get-AzureADDirectoryRoleGet-AzureADDirectoryRole-ObjectId <roleID>#Get info about the role# Get custom roles - use AzureAdPreviewGet-AzureADMSRoleDefinition|?{$_.IsBuiltin-eq$False} | select DisplayName# Users assigned a role (Global Administrator)Get-AzureADDirectoryRole-Filter "DisplayName eq 'Global Administrator'"|Get-AzureADDirectoryRoleMemberGet-AzureADDirectoryRole-ObjectId <id>| fl# Roles of the Administrative Unit (who has permissions over the administrative unit and its members)Get-AzureADMSScopedRoleMembership-Id <id>| fl *
Devices
# If you know how to do this send a PR!
# Enumerate DevicesGet-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 devicesGet-AzureADDevice-All $true|Get-AzureADDeviceRegisteredOwnerGet-AzureADDevice-All $true|%{if($user=Get-AzureADDeviceRegisteredOwner-ObjectId $_.ObjectID){$_;$user.UserPrincipalName;"`n"}}# Registred users of all the devicesGet-AzureADDevice-All $true|Get-AzureADDeviceRegisteredUserGet-AzureADDevice-All $true|%{if($user=Get-AzureADDeviceRegisteredUser-ObjectId $_.ObjectID){$_;$user.UserPrincipalName;"`n"}}# Get dives managed using IntuneGet-AzureADDevice-All $true|?{$_.IsCompliant-eq"True"}# Get devices owned by a userGet-AzureADUserOwnedDevice-ObjectId test@corp.onmicrosoft.com# Get Administrative Units of a deviceGet-AzureADMSAdministrativeUnit|where { Get-AzureADMSAdministrativeUnitMember-ObjectId $_.ObjectId|where {$_.ObjectId-eq $deviceObjId} }
If a device (VM) is AzureAD joined, users from AzureAD are going to be able to login.
Moreover, if the logged user is Owner of the device, he is going to be local admin.
Administrative Units
For more information about administrative units check:
# List all administrative unitsazrest--methodGET--uri"https://graph.microsoft.com/v1.0/directory/administrativeUnits"# Get AU infoazrest--methodGET--uri"https://graph.microsoft.com/v1.0/directory/administrativeUnits/a76fd255-3e5e-405b-811b-da85c715ff53"# Get membersazrest--methodGET--uri"https://graph.microsoft.com/v1.0/directory/administrativeUnits/a76fd255-3e5e-405b-811b-da85c715ff53/members"# Get principals with roles over the AUazrest--methodGET--uri"https://graph.microsoft.com/v1.0/directory/administrativeUnits/a76fd255-3e5e-405b-811b-da85c715ff53/scopedRoleMembers"
# Get Administrative UnitsGet-AzureADMSAdministrativeUnitGet-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 unitGet-AzureADMSAdministrativeUnitMember-Id <id># Get the roles users have over the members of the AUGet-AzureADMSScopedRoleMembership-Id <id>| fl #Get role ID and role members
Entra ID Privilege Escalation
Azure Privilege Escalation
Defensive Mechanisms
Privileged Identity Management (PIM)
Privileged Identity Management (PIM) in Azure helps to prevent excessive privileges to being assigned to users unnecessarily.
One of the main features provided by PIM is that It allows to not assign roles to principals that are constantly active, but make them eligible for a period of time (e.g. 6months). Then, whenever the user wants to activate that role, he needs to ask for it indicating the time he needs the privilege (e.g. 3 hours). Then an admin needs to approve the request.
Note that the user will also be able to ask to extend the time.
Moreover, PIM send emails whenever a privileged role is being assigned to someone.
When PIM is enabled it's possible to configure each role with certain requirements like:
A lot more configuration on when and who to send notifications when certain actions happen with that role
Conditional Access Policies
Check:
Entra Identity Protection
Entra Identity Protection is a security service that allows to detect when a user or a sign-in is too risky to be accepted, allowing to block the user or the sig-in attempt.
It allows the admin to configure it to block attempts when the risk is "Low and above", "Medium and above" or "High". Although, by default it's completely disabled:
Nowadays it's recommended to add these restrictions via Conditional Access policies where it's possible to configure the same options.