Threat Hunting Exercise: Analyzing Azure AD Illicit OAuth Consent Grant Phishing Dataset
This hunt uses a simulated Azure AD sign-in/audit dataset (azuread_oauth_consent_2022-07-02T130000.json) capturing T1528: Steal Application Access Token, where a user is phished into granting a malicious multi-tenant OAuth application broad permissions (Mail.Read, Files.ReadWrite.All), giving the attacker persistent, MFA-bypassing access to the mailbox and files without ever knowing the user's password.
Step 1: Hypothesis Formation
Hypothesis: A user consents to a newly-registered, unverified multi-tenant OAuth application requesting high-privilege delegated permissions (mail, files, or directory read/write), after which the application immediately begins making Graph API calls consistent with mailbox enumeration or bulk file access, from an IP/ASN inconsistent with the user's normal location. Indicators:
- Azure AD Audit log:
Consent to applicationevent for an app withVerified Publisher: Noand permissions includingMail.Read,Mail.ReadWrite, orFiles.ReadWrite.All. - App registration is recent (creation date within days of the consent event) and has a low or zero prior tenant-wide usage count.
- Immediately following consent, Graph API sign-in logs show the application making high-volume
Mail.Readcalls from an unfamiliar IP. - The consent event itself may show
Sign-in risk: highor an atypical sign-in location for the consenting user, if the phishing link led through a fake login flow.
Null Hypothesis: The user legitimately consented to a productivity add-in (e.g., a calendar or note-taking app) that reasonably requires broad mail/file permissions. Invalidate via checking the application's publisher verification status, requested-permission-to-stated-purpose fit, and any user report of a suspicious consent prompt.
Rationale: Illicit consent grant attacks bypass password resets, MFA, and even conditional access in many configurations, since the attacker never needs the user's credentials at all - this hunt validates detection via app-registration metadata and post-consent API behavior rather than traditional sign-in anomaly detection.
Step 2: Data Sources and Scope
- Sources: Azure AD Audit logs (
Consent to application,Add OAuth2PermissionGrant); Azure AD Sign-in logs (application sign-ins); Microsoft Graph Activity logs (API call volume/type per app). - Scope: ~2022-07-02T13:00:00-14:00:00 UTC; Tenant: contoso.onmicrosoft.com; User: r.patel@contoso.com; App: "Quick Notes Sync" (App ID a1b2c3d4...).
- SIEM Queries (Splunk/ELK or KQL):
- Consent events:
AuditLogs | where OperationName == "Consent to application" | where Permissions has_any ("Mail.Read","Files.ReadWrite.All") - Publisher verification:
| where TargetResources has "verifiedPublisher" and TargetResources !has "verified: true" - Post-consent API burst:
MicrosoftGraphActivityLogs | where AppId == "a1b2c3d4..." | summarize count() by bin(TimeGenerated, 5m)
Step 3: Key Findings
Parsed events (6 shown) confirm a user consented to an unverified app requesting mail-read permissions, followed within minutes by a high-volume mailbox enumeration burst from a foreign IP.
| Timestamp (UTC) | User | Event | Details | IOC/Why Suspicious? |
|---|---|---|---|---|
| 2022-07-02 13:04:11 | r.patel | Consent to application | App=Quick Notes Sync; Permissions=Mail.Read, Mail.Send, Files.ReadWrite.All, offline_access; Publisher=Unverified | Permission-scope IOC: requested permissions (mail send, full file read/write, offline access) far exceed what a "notes sync" app plausibly needs. |
| - | - | (App registration metadata) | App created 2022-06-29 (3 days prior); zero other consents tenant-wide | Novelty IOC: brand-new, single-use app registration - not an established internal or widely-adopted third-party tool. |
| 2022-07-02 13:06:02 | Quick Notes Sync (as r.patel) | Graph API: GET /me/messages x340 | From IP 41.203.72.18 (Nigeria) - user's normal sign-in location is US-East | Location-anomaly IOC: application's API calls originate from a geography inconsistent with the user's established pattern, despite using a legitimately-issued OAuth token (no sign-in/MFA challenge triggered, since consent already granted access). |
| 2022-07-02 13:06:02 - 13:09:00 | Quick Notes Sync | Graph API: mailbox search for "invoice", "wire", "password" | Targeted keyword search across the mailbox | Intent IOC: search terms indicate targeted financial/credential-fraud reconnaissance, not legitimate note-syncing functionality. |
| 2022-07-02 13:10:15 | Quick Notes Sync | Graph API: POST /me/mailFolders/inbox/rules | New inbox rule created: forward matching "invoice" to external address, mark as read | Persistence/exfil IOC: identical technique to classic mailbox-rule BEC setup, but achieved via OAuth token abuse rather than direct account compromise - MFA and password reset would not revoke this access. |
| - | (offline_access scope) | N/A | Refresh token issued with offline_access, valid independent of the user's session or password changes | Durability IOC: this is precisely why illicit consent grants are dangerous - a password reset alone does not revoke the attacker's access; the OAuth grant itself must be explicitly revoked. |
Validation:
- Timeline: Consent → immediate mailbox enumeration → targeted keyword search → inbox rule creation, all within 6 minutes - a fast, automated, script-driven abuse pattern.
- False Positives: Publisher-verification status and the permission-to-stated-purpose mismatch rule out legitimate productivity-app use; no user report of intentional business use of this app exists.
- Correlation: Single user, single app, tight temporal chain - high-confidence illicit consent grant.
Step 4: Recommendations & Next Steps
- Immediate Response: Revoke the application's OAuth grant immediately (
Remove-AzureADOAuth2PermissionGrantor via the Enterprise Applications portal) - this is the only action that actually cuts off access; delete the malicious inbox rule; force a password reset AND revoke all refresh tokens for r.patel as defense-in-depth; notify the user and check for any wire-fraud follow-through with Finance. - Detection: Sigma/KQL-style rule:
title: Consent to Unverified App with High-Privilege Mail/File Permissions→selection: OperationName == "Consent to application" AND Permissions has_any (high_risk_scope_list) AND VerifiedPublisher == false- alert in real time, not just via periodic review. - Pro Tip: Configure Azure AD user consent settings to disallow user consent for apps entirely (require admin consent workflow) - this single tenant-wide setting change eliminates the entire illicit-consent-grant attack class rather than relying on after-the-fact detection.
Hypothesis confirmed - a user was phished into granting a malicious unverified OAuth application high-privilege mailbox access, which was immediately abused for reconnaissance and BEC-style inbox rule creation!