Detect OAuth and Consent Phishing Abuse
IR AnalystSwitch roles in the top navigation to see different perspectives.
Identify malicious OAuth application consent grants that provide the attacker persistent access to user data without needing credentials. Consent phishing tricks users into granting permissions to attacker-controlled applications.
Actions
- 1.Enumerate all OAuth permission grants for compromised users: `Get-AzureADUserOAuth2PermissionGrant -ObjectId <user_id> -All $true | Select ClientId, ConsentType, Scope, PrincipalId`. Cross-reference ClientId with known legitimate applications.
- 2.Identify suspicious application registrations created during the investigation window: `Get-AzureADApplication -Filter "createdDateTime ge T_START" | Select DisplayName, AppId, CreatedDateTime, Homepage, ReplyUrls`.
- 3.Check for high-privilege consent grants (Mail.ReadWrite, Files.ReadWrite.All, Directory.ReadWrite.All): `AuditLogs | where OperationName == "Consent to application" | where TargetResources has "Mail.ReadWrite" or TargetResources has "Files.ReadWrite"`. These are the most dangerous grants.
- 4.Review service principal sign-in logs for the malicious application: `AADServicePrincipalSignInLogs | where AppId == "<malicious_app_id>" | summarize by IPAddress, ResourceDisplayName, ServicePrincipalName` -- this shows what data the app accessed.
- 5.Revoke malicious consent grants: `Remove-AzureADOAuth2PermissionGrant -ObjectId <grant_id>` and disable the malicious application: `Set-AzureADApplication -ObjectId <app_id> -AvailableToOtherTenants $false`.
Queries
AuditLogs | where TimeGenerated between (datetime(T_START) .. datetime(T_END)) | where OperationName in ("Consent to application","Add OAuth2PermissionGrant","Add app role assignment grant to user") | project TimeGenerated, InitiatedBy, TargetResources, AdditionalDetails | order by TimeGenerated ascCloudAppEvents | where Timestamp between (datetime(T_START) .. datetime(T_END)) | where ActionType == "Consent to application." | project Timestamp, AccountDisplayName, IPAddress, RawEventData | extend AppName=tostring(parse_json(RawEventData).Target[0].ID) | order by Timestamp asc
AADServicePrincipalSignInLogs | where TimeGenerated between (datetime(T_START) .. datetime(T_END)) | where AppId in ("<suspicious_app_id_1>","<suspicious_app_id_2>") | summarize AccessCount=count(), Resources=make_set(ResourceDisplayName) by AppId, ServicePrincipalName, IPAddressNotes
- OAuth consent grants survive password resets. The attacker retains access even after the user changes their password. Always review and revoke consent grants during account remediation.
- Legitimate OAuth apps rarely request Mail.ReadWrite or Directory.ReadWrite.All. Any app with these permissions that is not a known enterprise tool should be treated as suspicious.