Incident Response Workflow: OAuth Application Compromise.
The password had been changed.
MFA had been reset. Active sessions had been revoked. The user looked secure again.
But the attacker still had access.
Agent Foskett realised the compromise was no longer about the user's password. The user had granted trust to a malicious OAuth application, and that application was now doing the work for the attacker.
Lesson overview
Learn how to investigate malicious OAuth consent, delegated permissions, token abuse and persistent Microsoft 365 access using Microsoft Defender XDR and Microsoft Entra ID telemetry.
Why OAuth application compromise matters
The OAuth application compromise workflow
Step 1 — Review OAuth and application consent events
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let TimeFrame = 30d;
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where ActionType has_any ("Consent", "OAuth", "Add service principal", "Add app role assignment")
| project Timestamp,
AccountDisplayName,
ActionType,
Application,
AppId,
ObjectName,
IPAddress,
RawEventData
| order by Timestamp descStep 2 — Build the user's cloud activity timeline
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
let TimeFrame = 30d;
let UserToInvestigate = "user@contoso.com";
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where AccountDisplayName =~ UserToInvestigate
| where Application has_any ("Office 365", "Microsoft 365", "Azure Active Directory")
| project Timestamp,
AccountDisplayName,
ActionType,
Application,
ObjectName,
IPAddress,
RawEventData
| order by Timestamp ascStep 3 — Search for high-risk permissions
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let TimeFrame = 30d;
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where RawEventData has_any ("Mail.Read", "Mail.Send", "Files.Read", "Files.Read.All", "offline_access", "User.Read", "Directory.Read")
| project Timestamp,
AccountDisplayName,
ActionType,
Application,
AppId,
ObjectName,
IPAddress,
RawEventData
| order by Timestamp descStep 4 — Review identity activity around consent
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let TimeFrame = 14d;
let SuspectUser = "user@contoso.com";
IdentityLogonEvents
| where Timestamp > ago(TimeFrame)
| where AccountUpn =~ SuspectUser
| project Timestamp,
AccountUpn,
ActionType,
IPAddress,
Location,
DeviceName,
FailureReason
| order by Timestamp ascStep 5 — Scope the suspicious application
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
let TimeFrame = 30d;
let SuspectApp = "Suspicious App Name";
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where Application has SuspectApp or ObjectName has SuspectApp or RawEventData has SuspectApp
| summarize EventCount = count(),
Users = make_set(AccountDisplayName, 50),
Actions = make_set(ActionType, 50),
IPAddresses = make_set(IPAddress, 50),
FirstSeen = min(Timestamp),
LastSeen = max(Timestamp)
by Application,
AppId
| order by EventCount descStep 6 — Build the OAuth compromise timeline
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
let TimeFrame = 30d;
let SuspectUser = "user@contoso.com";
let IdentityActivity =
IdentityLogonEvents
| where Timestamp > ago(TimeFrame)
| where AccountUpn =~ SuspectUser
| project Timestamp,
Source = "IdentityLogonEvents",
Account = AccountUpn,
Activity = ActionType,
Detail = strcat(IPAddress, " ", Location);
let CloudActivity =
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where AccountDisplayName =~ SuspectUser
| project Timestamp,
Source = "CloudAppEvents",
Account = AccountDisplayName,
Activity = ActionType,
Detail = strcat(Application, " ", ObjectName);
union IdentityActivity, CloudActivity
| order by Timestamp ascCommon OAuth compromise clues
False positives to consider
Investigation checklist
Related Agent Foskett Academy lessons
Coming next
Final thought
Incident Response Workflow OAuth Application Compromise in Microsoft Defender XDR
Agent Foskett Academy Lesson 118 teaches defenders how to investigate OAuth application compromise using Microsoft Defender XDR, Microsoft Entra ID, CloudAppEvents, identity telemetry, delegated permissions and KQL hunting workflows.
Learn OAuth application compromise investigation with KQL and Microsoft Defender XDR
OAuth compromise investigations help Microsoft security analysts identify malicious application consent, delegated permissions, token abuse, cloud access and persistent attacker activity across Microsoft 365 services.
Microsoft Entra ID OAuth consent investigation tutorial
This lesson explains how to investigate suspicious OAuth consent, malicious Enterprise Applications, service principals, delegated Graph permissions, offline access and cloud persistence using Microsoft security telemetry.
