Skip to content

Latest commit

 

History

History
104 lines (70 loc) · 4.16 KB

T1528.Entra.ServicePrincipalAccessTokenReplay.md

File metadata and controls

104 lines (70 loc) · 4.16 KB

T1528.Entra.ServicePrincipalAccessTokenReplay

Detect access token theft/replay for Microsoft Entra Service Principals / Workload Identities.

Hunt Tags

ID: T1528.Entra.ServicePrincipalAccessTokenReplay

Author: Nicola Suter

License: MIT License

References: Link to medium post

ATT&CK Tags

Tactic: Credential Access (TA0006)

Technique: Steal Application Access Token (T1528)

Technical description of the attack

Attackers can steal access tokens from service principals and use them to access resources for the valid duration of the token. This is an attack vector for service principals that are used in CI/CD pipelines and are already hardened by leveraging only short lived tokens with workload identity federation.

Access tokens can be exfiltrated by adding a simple step to the CI pipeline and sending the access token to an attacker controlled server. The access token can then be used to access resources for the valid duration of the token.

Permission required to execute the technique

Access to the device or service where the service principal is being used, such as a CI/CD pipeline running on GitHub Actions.

Detection description

As access tokens are issued after the service principal has authenticated, the IP address of the token issuance is different from the IP address of the token usage. This difference can be used to detect access token theft.

Utilized Data Source

Event ID Event Name Log Provider ATT&CK Data Source
- MicrosoftGraphActivityLogs Entra ID Cloud Service
- AADServicePrincipalSignInLogs Entra ID Cloud Service
- AzureActivity Azure Cloud Service

Hunt details

KQL

FP Rate: Low

Source: Entra ID

Description: This detection looks at differences within the IP adresses between the access token issuance and usage.

Query:

// Hunt for differences between the token issuance and token usage of entra service principals based on the public IP address
let lookback = 30d;
union
    (MicrosoftGraphActivityLogs
    | where ResponseStatusCode between (100 .. 300) // only include HTTP success status codes
    | extend UniqueTokenIdentifier = SignInActivityId
    | extend ActivityIPAddress = IPAddress
    ),
    (AzureActivity
    | extend UniqueTokenIdentifier = tostring(Claims_d.uti)
    | extend ActivityIPAddress = CallerIpAddress
    )
| where ingestion_time() > ago(lookback)
| lookup kind=inner AADServicePrincipalSignInLogs on UniqueTokenIdentifier
| extend SigninInIPAddress = IPAddress1
| where SigninInIPAddress != ActivityIPAddress
| where isnotempty(SigninInIPAddress)
| project-away *1
| project
    TimeGenerated,
    ServicePrincipalName,
    SigninInIPAddress,
    ActivityIPAddress,
    ServicePrincipalId,
    ServicePrincipalCredentialThumbprint,
    ServicePrincipalCredentialKeyId

Considerations

  • Only ActivityLogs with a corresponding SignIn are considered (due to inner join).
  • The AADManagedIdentitySignInLogs do not contain the IPAddress field, therefore only AADServicePrincipalSignInLogs are considered.

False Positives

False positives are unlikely but could occur in the following cases:

  • Multiple public IP addresses are pooled and used by the same service principal (e.g. NAT gateways) after access token retrieval.
  • The service principal passes the access token to another service principal with a different public IP address.

Detection Blind Spots

  • When the access token is reused behind the same Public IP address, this detection will not work as it relies on the public IP.
  • The detection only covers the Microsoft Graph and Azure Activity APIs, other APIs are not covered.

References