Detection rules › Kusto
Possible AiTM Phishing Attempt Against Microsoft Entra ID
Threat actors may attempt to phish users in order to hijack a users sign-in session, and skip the authentication process even if the user had enabled multifactor authentication (MFA) by stealing and replaying stolen credentials and session cookies. This detection looks for successful Microsoft Entra ID sign ins that had a high risk profile, indicating it had suspicious characteristics such as an unusual location, ISP, user agent, or use of anonymizer services. It then looks for a network connection to the IP address that made the sign in immediately before the sign in, that may indicate a user connecting to a phishing site at that IP address and having their authentication session hijacked. Ref: https://www.microsoft.com/security/blog/2022/07/12/from-cookie-theft-to-bec-attackers-use-aitm-phishing-sites-as-entry-point-to-further-financial-fraud/
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Stealth | |
| Credential Access |
Telemetry coverage
Rules detecting the same action
These rules filter on the same operation.
- [Entra ID] Suspicious Continuous OAuth Token Usage (Kusto)
- Anomalous sign-in location by user account and authenticating application (Kusto)
- Anomalous Single Factor Signin (Kusto)
- Authentications of Privileged Accounts Outside of Expected Controls (Kusto)
- Azure Portal sign in from another Azure Tenant (Kusto)
- Azure Service Principal Sign-In Followed by Arc Cluster Credential Access (Elastic)
- Azure SignIn via Legacy Authentication Protocol (Panther)
- Cisco - firewall block but success logon to Microsoft Entra ID (Kusto)
Rule body
id: 16daa67c-b137-48dc-8eb7-76598a44791a
name: Possible AiTM Phishing Attempt Against Microsoft Entra ID
description: |
'Threat actors may attempt to phish users in order to hijack a users sign-in session, and skip the authentication process even if the user had enabled multifactor authentication (MFA) by stealing and replaying stolen credentials and session cookies.
This detection looks for successful Microsoft Entra ID sign ins that had a high risk profile, indicating it had suspicious characteristics such as an unusual location, ISP, user agent, or use of anonymizer services.
It then looks for a network connection to the IP address that made the sign in immediately before the sign in, that may indicate a user connecting to a phishing site at that IP address and having their authentication session hijacked.
Ref: https://www.microsoft.com/security/blog/2022/07/12/from-cookie-theft-to-bec-attackers-use-aitm-phishing-sites-as-entry-point-to-further-financial-fraud/'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
- connectorId: Zscaler
dataTypes:
- CommonSecurityLog (Zscaler)
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- DefenseEvasion
- CredentialAccess
relevantTechniques:
- T1078.004
- T1557
- T1111
query: |
let time_threshold = 10m;
let RiskySignins = materialize (SigninLogs
| where TimeGenerated > ago(1d)
| where ResultType == 0
| where RiskLevelDuringSignIn =~ "high" or RiskLevelAggregated =~ "high"
| extend SignInTime = TimeGenerated, Name=split(UserPrincipalName, "@")[0], UPNSuffix=split(UserPrincipalName, "@")[1]);
let ips = todynamic(toscalar(RiskySignins | summarize make_list(IPAddress)));
RiskySignins
| join kind=inner (_Im_WebSession(starttime=ago(1d), ipaddr_has_any_prefix=ips, eventresult="Success", pack=True))
on $left.IPAddress == $right.DstIpAddr
| where EventStartTime < TimeGenerated
| extend TimeDelta = TimeGenerated - EventStartTime
| where TimeDelta <= time_threshold
| extend NetworkEventStartTime = EventStartTime, NetworkEventEndTime = EventEndTime
| extend SrcUsername = column_ifexists("SrcUsername", "Unknown")
| project-reorder SignInTime, UserPrincipalName, IPAddress, AppDisplayName, ClientAppUsed, DeviceDetail, LocationDetails, NetworkLocationDetails, RiskEventTypes, UserAgent, NetworkEventStartTime, NetworkEventEndTime, SrcIpAddr, DstIpAddr, DstPortNumber, Dvc, DvcHostname, SrcBytes, NetworkProtocol, SrcUsername
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
alertDetailsOverride:
alertDisplayNameFormat: Possible AiTM Phishing Attempt Against {{UserPrincipalName}} From {{IPAddress}}
alertDescriptionFormat: |
Threat actors may attempt to phish users in order to hijack a users sign-in session, and skip the authentication process even if the user had enabled multifactor authentication (MFA) by stealing and replaying stolen credentials and session cookies.
This detection looks for successful Microsoft Entra ID sign ins (in this case from {{UserPrincipalName}}) that had a high risk profile, indicating it had suspicious characteristics such as an unusual location, ISP, user agent, or use of anonymizer services.
It then looks for a network connection to the IP address (in this case {{IPAddress}}) that made the sign in immediately before the sign in, that may indicate a user connecting to a phishing site at that IP address and having their authentication session hijacked.
Ref: https://www.microsoft.com/security/blog/2022/07/12/from-cookie-theft-to-bec-attackers-use-aitm-phishing-sites-as-entry-point-to-further-financial-fraud/
version: 1.0.4
kind: Scheduled
Stages and Predicates
Parameters
let time_threshold = 10m;
let RiskySignins is inlined into the numbered stages below.
Let binding: ips
let ips = todynamic(toscalar(RiskySignins | summarize make_list(IPAddress)));
Stages 1 to 5 define let RiskySignins (the rule's main pipeline source); stages 6 to 12 run on it.
Stage 1: source
SigninLogs
Stage 2: where
| where TimeGenerated > ago(1d)
Stage 3: where
| where ResultType == 0
Stage 4: where
| where RiskLevelDuringSignIn =~ "high" or RiskLevelAggregated =~ "high"
Stage 5: extend
| extend SignInTime = TimeGenerated, Name=split(UserPrincipalName, "@")[0], UPNSuffix=split(UserPrincipalName, "@")[1]
Stage 6: join
RiskySignins
| join kind=inner (_Im_WebSession(starttime=ago(1d), ipaddr_has_any_prefix=ips, eventresult="Success", pack=True))
on $left.IPAddress == $right.DstIpAddr
Stage 7: where
| where EventStartTime < TimeGenerated
Stage 8: extend
| extend TimeDelta = TimeGenerated - EventStartTime
Stage 9: where
| where TimeDelta <= time_threshold
Stage 10: extend
| extend NetworkEventStartTime = EventStartTime, NetworkEventEndTime = EventEndTime
Stage 11: extend
| extend SrcUsername = column_ifexists("SrcUsername", "Unknown")
Stage 12: project-reorder
| project-reorder SignInTime, UserPrincipalName, IPAddress, AppDisplayName, ClientAppUsed, DeviceDetail, LocationDetails, NetworkLocationDetails, RiskEventTypes, UserAgent, NetworkEventStartTime, NetworkEventEndTime, SrcIpAddr, DstIpAddr, DstPortNumber, Dvc, DvcHostname, SrcBytes, NetworkProtocol, SrcUsername
Indicators
These rows show field, operator, and value matches.
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Name | extend |
SignInTime | extend |
UPNSuffix | extend |
TimeDelta | extend |
NetworkEventEndTime | extend |
NetworkEventStartTime | extend |
SrcUsername | extend |