Applications with Mail.Read or Mail.ReadWrite permissions may indicate unauthorized access to email data, as adversaries often exploit such permissions to exfiltrate information. SOC teams should proactively hunt for this behavior in Azure Sentinel to detect potential compromise of user credentials or data leakage via malicious applications.
KQL Query
let auditLookback = 1d;
CloudAppEvents
| where Timestamp > ago(auditLookback)
| where ActionType == "Add delegated permission grant."
| extend RawEventData = parse_json(RawEventData)
| where RawEventData.ResultStatus =~ "success"
| extend UserId = tostring(RawEventData.UserId)
| extend UserAgent = parse_json(replace('-','',tostring(RawEventData.ExtendedPRoperties[0].Value))).UserAgent
| extend properties = RawEventData.ModifiedProperties
| mvexpand properties
| extend Permissions = properties.NewValue
| where Permissions has_any ("Mail.Read", "Mail.ReadWrite")
| extend PermissionsAddedTo = tostring(RawEventData.Target[3].ID) // Get target of permissions
| project-away properties, RawEventData
| join kind=leftouter (CloudAppEvents
| where Timestamp > ago(auditLookback)
| where ActionType == "Consent to application."
| where isnotempty(AccountDisplayName)
| extend RawEventData = parse_json(RawEventData)
| extend UserId = tostring(RawEventData.UserId)
| extend targetInfo = RawEventData.Target
| extend AppName = tostring(targetInfo[3].ID) // Find app name
| extend AppId = tostring(targetInfo[4].ID) // Find appId
| project ConsentTimestamp=Timestamp, UserId, AccountDisplayName, AppName, AppId
) on UserId
| extend ConsentTimestamp = todatetime(format_datetime(ConsentTimestamp, 'MM/dd/yyyy HH:mm')) // Ensure app consent happend close to the same time as the permissions were granted
| extend PermsTimestamp = todatetime(format_datetime(Timestamp, 'MM/dd/yyyy HH:mm'))
| where PermsTimestamp -2m <= ConsentTimestamp // ensure consent happened near permissions grant
| where PermsTimestamp +2m >= ConsentTimestamp
| project Timestamp, ActionType, InitiatingUser=AccountDisplayName, UserId, InitiatingIP=IPAddress, UserAgent, PermissionsAddedTo, AppName, AppId
id: 2c80af05-53c1-4a77-82e7-a649e8e32506
name: MailPermissionsAddedToApplication[Nobelium]
description: |
This query will find applications that have been granted Mail.Read or Mail.ReadWrite permissions in which the corresponding user recently consented to. It can help identify applications that have been abused to gain access to user email.
The actor, Nobelium, was observed modifying existing tenant application permissions to allow them to read user email through the Microsoft Graph API. See Customer Guidance on Recent Nation-State Cyber Attacks.
This query is insprired by an Azure Sentinel detection.
References:
https://msrc-blog.microsoft.com/2020/12/13/customer-guidance-on-recent-nation-state-cyber-attacks/
https://github.com/Azure/Azure-Sentinel/blob/master/Detections/AuditLogs/MailPermissionsAddedToApplication.yaml
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- CloudAppEvents
tactics:
- Defense evasion
tags:
- Nobelium
query: |
let auditLookback = 1d;
CloudAppEvents
| where Timestamp > ago(auditLookback)
| where ActionType == "Add delegated permission grant."
| extend RawEventData = parse_json(RawEventData)
| where RawEventData.ResultStatus =~ "success"
| extend UserId = tostring(RawEventData.UserId)
| extend UserAgent = parse_json(replace('-','',tostring(RawEventData.ExtendedPRoperties[0].Value))).UserAgent
| extend properties = RawEventData.ModifiedProperties
| mvexpand properties
| extend Permissions = properties.NewValue
| where Permissions has_any ("Mail.Read", "Mail.ReadWrite")
| extend PermissionsAddedTo = tostring(RawEventData.Target[3].ID) // Get target of permissions
| project-away properties, RawEventData
| join kind=leftouter (CloudAppEvents
| where Timestamp > ago(auditLookback)
| where ActionType == "Consent to application."
| where isnotempty(AccountDisplayName)
| extend RawEventData = parse_json(RawEventData)
| extend UserId = tostring(RawEventData.UserId)
| extend targetInfo = RawEventData.Target
| extend AppName = tostring(targetInfo[3].ID) // Find app name
| extend AppId = tostring(targetInfo[4].ID) // Find appId
| project ConsentTimestamp=Timestamp, UserId, AccountDisplayName, AppName, AppId
) on UserId
| extend ConsentTimestamp = todatetime(format_datetime(ConsentTimestamp, 'MM/dd/yyyy HH:mm')) // Ensure app consent happend close to the same time as the permissions were granted
| extend PermsTimestamp = todatetime(format_datetime(Timestamp, 'MM/dd/yyyy HH:mm'))
| where PermsTimestamp -2m <= ConsentTimestamp // ensure consent happened near permissions grant
| where PermsTimestamp +2m >= ConsentTimestamp
| project Timestamp, ActionType, InitiatingUser=AccountDisplayName, UserId, InitiatingIP=IPAddress, UserAgent, PermissionsAddedTo, AppName, AppId
| Sentinel Table | Notes |
|---|---|
CloudAppEvents | Ensure this data connector is enabled |
Scenario: User Consent for Email Access During Onboarding
Description: A new user is onboarded and granted Mail.Read permissions as part of their initial setup, which is a legitimate administrative task.
Filter/Exclusion: Exclude users who are newly onboarded within the last 7 days or users with the “User” role in Azure AD.
Scenario: Scheduled Email Reporting Job
Description: A scheduled job runs daily to generate email reports using Mail.Read permissions, which is a common practice in enterprise environments.
Filter/Exclusion: Exclude activities related to the “Email Reporting” service or tasks scheduled under a known reporting service account.
Scenario: Admin Task to Audit Email Permissions
Description: An administrator is reviewing email permissions as part of a routine security audit, which involves temporarily granting Mail.Read access.
Filter/Exclusion: Exclude activities initiated by admin accounts with the “Global Administrator” or “Security Administrator” role.
Scenario: Integration with Microsoft Teams or Outlook
Description: A legitimate integration between an internal application and Microsoft Teams or Outlook requires Mail.ReadWrite permissions for calendar or email synchronization.
Filter/Exclusion: Exclude applications that are known integrations with Microsoft 365 services (e.g., Teams, Outlook) and use registered service principals.
Scenario: User Consent for Email Access via Microsoft 365 Admin Center
Description: An admin grants a user Mail.Read permissions via the Microsoft 365 Admin Center as part of a collaboration setup.
Filter/Exclusion: Exclude consents granted by admin accounts or users with the “Global Administrator” role.