Pen Testing AzureAD

Azure is Microsoft’s cloud service with several offerings. One of the most popular functions is Azure Active Directory. Although similar in name it is not the same as the “Active Directory” we are used to in internal environments. We do not need access to a workstation to complete any tasks; only a valid account. The audit itself is also a little different as it requires a few PowerShell Modules. I have found it easiest to use on a Windows 10/11 Virtual Machine (Or just your own host if you are comfortable with that). The focus is going to be on AzureAD, however you may run into VM’s, SQL servers, Key Vaults, and Blobs among other things.

Tools

ToolLink / Installation/ Command
TrevorSprayhttps://github.com/blacklanternsecurity/TREVORspray.git
AzureHoundhttps://github.com/BloodHoundAD/AzureHound.git
PowerZurehttps://github.com/hausec/PowerZure.git
CrowdStrike Reporting Tool (Requires GA)https://github.com/CrowdStrike/CRT.git
ROADtoolshttps://github.com/dirkjanm/ROADtools.git
AADInternals ModuleInstall-Module AADInternals
Azure Powershell ModuleInstall-Module -Name Az
PowerShellaz Connect-AzAccount Connect-AzureAD
Bloodhound (Required to view data)https://github.com/BloodHoundAD/BloodHound.git

Terminology

TermDefinition
TenantThe organizations subscription to Azure. Everything within AzureAD falls under the Tenant. Think of it like a Top Level Domain. All users groups and applications belong to the Tenant
Tenant IDA unique way to identify an Azure AD instance within an Azure subscription
SubscriptionA group of resources that the tenant pays for and can access. A tenant can have multiple subscriptions
Service PrincipalAn application identity that can access Azure resources. It has credentials and can be logged in to and are granted permissions
Security PrincipalA user identity with a specific role to access specific resources for management purposes
Key VaultsStores API keys, credentials, and certificates. Located within an application. You can log into a key vault with proper authentication (ie: Service Principal)

Installation

Install Tools on your Windows Machine:

  • Windows has been flagging the AzureHound.zip as malicious so you may need to disable the firewall
  • Open a PowerShell terminal as an Administrator and paste this code block
Set-ExecutionPolicy Bypass -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
choco install -y git
choco install -y python --version=3.8.0
py -m pip install --upgrade pip
cd "\Users\$([Environment]::UserName)\Desktop"
New-Item -Path "C:\Users\$([Environment]::UserName)\Desktop\AzureTools" -ItemType directory
cd AzureTools
Install-Module -Name Az -Repository PSGallery -Force
Install-Module -Name AADInternals
Install-Module -Name PSWSMan
Install-Module -Name ExchangePowerShell
Install-Module -Name ExchangeOnlineManagement
Install-Module -Name pip
Invoke-WebRequest -Uri https://aka.ms/installazurecliwindows -OutFile .\AzureCLI.msi; Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet'; rm .\AzureCLI.msi
Invoke-WebRequest -Uri https://github.com/BloodHoundAD/AzureHound/releases/download/v1.1.2/azurehound-windows-amd64.zip -OutFile AzureHound.zip
Expand-Archive .\AzureHound.zip
Remove-Item "C:\Users\$([Environment]::UserName)\Desktop\AzureTools\AzureHound.zip" -Recurse
py -m pip install roadrecon
  • When Complete close the PowerShell window and then run these commands
cd "\Users\$([Environment]::UserName)\Desktop\AzureTools"
git clone https://github.com/hausec/PowerZure.git
git clone https://github.com/CrowdStrike/CRT

Configure Bloodhound to ingest Azure Data

  1. Open up bloodhound and add custom queries. Create them with the names and ciphers from the table.
Query NameCipher for Query
Return All Azure Users that are part of the ‘Global Administrator’ RoleMATCH p =(n)-[r:AZGlobalAdmin*1..]->(m) RETURN p
Return All On-Prem users with edges to AzureMATCH p=(m:User)-[r:AZResetPassword|AZOwns|AZUserAccessAdministrator|AZContributor|AZAddMembers|AZGlobalAdmin|AZVMContributor|AZOwnsAZAvereContributor]->(n) WHERE m.objectid CONTAINS ‘S-1-5-21’ RETURN p
Find all paths to an Azure VMMATCH p = (n)-[r]->(g:AZVM) RETURN p
Find all paths to an Azure KeyVaultMATCH p = (n)-[r]->(g:AZKeyVault) RETURN p
Return All Azure Users and their GroupsMATCH p=(m:AZUser)-[r:MemberOf]->(n) WHERE NOT m.objectid CONTAINS ‘S-1-5’ RETURN p
Return All Azure AD Groups that are synchronized with On-Premise ADMATCH (n:Group) WHERE n.objectid CONTAINS ‘S-1-5’ AND n.azsyncid IS NOT NULL RETURN n
Find all Privileged Service PrincipalsMATCH p = (g:AZServicePrincipal)-[r]->(n) RETURN p
Find all Owners of Azure ApplicationsMATCH p = (n)-[r:AZOwns]->(g:AZApp) RETURN p

Execution

We want to audit for weak passwords, lack of MFA, lack of Conditional Access Policies, miss-configurations in AzureAD, identify improper permissions and high privileged users. We do this by using a collection of tools to extract interesting data and then we will format that data to an easy to read and understand document.

  • I run TrevorSpray and Bloodhound from Kali and run all other tools on a Windows VM. This guide assumes you will be doing the same.

Get the token_endpoint/ tenant domains:

trevorspray --recon clientdomain.com

Check For MFA Bypasses (Use our client provided email address and pass):

Use a provisioned account, if we recover any breached creds try those as well

trevorspray -u user@clientdomain.com -p 'Welcome123'
  1. Try to login to azure cli with a username and password (If MFA is not enabled)
  2. If MFA is enabled use az login and sign in with the browser that opens up
  3. You can merge all 4 of these tables into one excel document.
  4. From a PowerShell terminal run the following commands
az login --allow-no-subscriptions -u user@domain.com -p password
New-Item -Path "C:\Users\$([Environment]::UserName)\Desktop\AzFiles" -ItemType directory
cd "C:\Users\$([Environment]::UserName)\Desktop\AzFiles"
az ad app list --query "[].[displayName,appId]" -o tsv > Apps.csv
az ad sp list --query "[].[displayName,appOwnerOrganizationId,appId,id]" --all -o tsv > ServicePrincipals.csv
az ad group list --query "[].[displayName,description,onPremisesNetBiosName,onPremisesDomainName,mail,id]" -o tsv > Groups.csv
az ad user list --query "[].[displayName,mail,businessPhones,mobilePhone,id,jobTitle,officeLocation,givenName,surname,userPrincipalName]" -o tsv > Users.csv
az vm list -o tsv > VMs.csv
az storage account list -o tsv > StorageAccts.csv
az keyvault list -o tsv > KeyVaults.csv
  1. Once created the documents can be combined into one .xlsx file with each section separated by tabs.
  2. Get an access token (this is also used to bypass MFA)
    1. Use the “id” from the output of az account list
az account list
az account get-access-token
$token = "eyJ0e..................hw"
Connect-AzAccount -AccessToken $token -AccountId "<ACCOUNT ID>"

You may need generate multiple access tokens, they last 90 minutes

Enumerate our provisioned account

MFA ENABLED

  • From an elevated PowerShell window run:
cd "C:\Users\$([Environment]::UserName)\Desktop\AzureTools\PowerZure"
Import-Module ./PowerZure.psd1
Get-AzureTarget
  • Save any output from Get-AzureTarget

MFA NOT ENABLED

  • From an elevated PowerShell window run:
cd "C:\Users\$([Environment]::UserName)\Desktop\AzureTools\PowerZure"
Connect-AzAccount
Import-Module ./PowerZure.psd1
Get-AzureTarget
Get-AADIntAccessTokenForAADGraph -SaveToCache
  • Save any output from Get-AzureTarget

Enumerate Privileged Users

  1. Paste this entire code block into PowerShell
$body = @{
    "client_id" =     "1950a258-227b-4e31-a9cf-717495945fc2"
    "resource" =      "https://graph.microsoft.com"
}
$UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
$Headers=@{}
$Headers["User-Agent"] = $UserAgent
$authResponse = Invoke-RestMethod `
    -UseBasicParsing `
    -Method Post `
    -Uri "https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0" `
    -Headers $Headers `
    -Body $body
$authResponse
  1. Follow the Device Login link to https://microsoft.com/devicelogin and enter the code provided. Login like you would normally
  2. Then paste this
$body=@{
    "client_id" =  "1950a258-227b-4e31-a9cf-717495945fc2"
    "grant_type" = "urn:ietf:params:oauth:grant-type:device_code"
    "code" =       $authResponse.device_code
}
$Tokens = Invoke-RestMethod `
    -UseBasicParsing `
    -Method Post `
    -Uri "https://login.microsoftonline.com/Common/oauth2/token?api-version=1.0" `
    -Headers $Headers `
    -Body $body
$Tokens
  1. The token we want to save is called the refresh_token
  1. We may need to use that refresh token to run AzureHoundcd "C:\Users\$([Environment]::UserName)\Desktop\AzureTools\AzureHound" ./azurehound.exe configure
  2. Select Cloud
  3. Enter the tenantId and Id we saved from before
  4. Select Certificate and select “YES” to create a certificate, do not create a password, N for all options
./azurehound.exe start -r "0.AXwAdas-fsq-........" list -o azure_out.json

Get Conditional Access Policy:

pip install roadrecon is supposed to add roadrecon to your path, if it doesn’t just browse to the directory in step #1

cd "C:\Users\$([Environment]::UserName)\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\Scripts"

MFA
roadrecon auth --device-code

No MFA
roadrecon auth -u user@mytenant.onmicrosoft.com -p Passwordhere
roadrecon gather
roadrecon dump
roadrecon plugin policies
Look in the directory for "caps.html" for policies
roadrecon-gui

Browse to the server at http://127.0.0.1:5000
We can compare this data to the data gathered from AzureHound

Get MFA Status of All Users

$Report = @()
$AzUsers = Get-MsolUser -All
ForEach ($AzUser in $AzUsers) {
$DefaultMFAMethod = ($AzUser.StrongAuthenticationMethods | ? { $_.IsDefault -eq "True" }).MethodType
$MFAState = $AzUser.StrongAuthenticationRequirements.State
if ($MFAState -eq $null) {$MFAState = "Disabled"}
$objReport = [PSCustomObject]@{
User = $AzUser.UserPrincipalName
MFAState = $MFAState
MFAPhone = $AzUser.StrongAuthenticationUserDetails.PhoneNumber
MFAMethod = $DefaultMFAMethod
}
$Report += $objReport
}
$Report

Export to CSV

$Report| Export-CSV -NoTypeInformation -Encoding UTF8 "C:\Users\$([Environment]::UserName)\Desktop\AzureUsersMFAstatus.csv"

Exchange Online (O365) Audit Report (Requires Global Admin Permissions)

  • This is not verified at the moment, it will generate a report automatically if the client uses the services and we are running the command from an exchange server
  • Run this command from a new PowerShell window
cd "C:\Users\$([Environment]::UserName)\Desktop\AzureTools/CRT"
.\Get-CRTReport.ps1
  1. A folder named with date and time (YYYYDDMMTHHMM) will be created automatically in the directory the script is being run from. To support MFA, the default authentication method will prompt the user to login for each connection.
  2. It is okay to see multiple errors, it could just be a result of insufficient permissions