Business Email Compromise (BEC) is a growing threat vector that often results in significant financial and reputational damage. Typically, BEC attacks aim to commit fraud, steal data, or compromise supply chains. A common characteristic of these attacks is gaining access to the victim’s emails, often going in pair with the creation of rules, such as those for forwarding emails.
Stolen information can be leveraged for months, even after the incident has been mitigated. For instance, the attackers could follow up on legitimate email conversations with fraudulent content, such as fake invoices or bank account change requests, or leverage the gathered information for other malicious purposes.
For organizations, understanding which emails were accessed and what information the attacker now holds is vital. This insight allows you to make your environment investigation-friendly, in preparation for future incidents.
This blog post aims to address the critical question:
“Which emails were accessed, and what information does the attacker potentially have now?”
In past incidents, we discovered that Unified Audit Logging (UAL) is often not enabled, even though it is supposed to be enabled by default since 2019. This result in missing audit logs, which are critical for tracking email access events and other actions. Therefore, it is highly recommended for organizations to ensure that UAL is activated.
To check the status of your tenant’s audit logging, follow these steps:
AdminAuditLogEnabled : True
LogLevel : None
TestCmdletLoggingEnabled : False
AdminAuditLogCmdlets : {*}
AdminAuditLogParameters : {*}
AdminAuditLogExcludedCmdlets : {}
AdminAuditLogAgeLimit : 90.00:00:00
LoadBalancerCount : 3
RefreshInterval : 10
PartitionInfo : {}
AdminAuditLogMailbox :
UnifiedAuditLogIngestionEnabled : True
UnifiedAuditLogFirstOptInDate : 02/04/2024 18:05:29
AdminDisplayName :
[...]
Example
If the UnifiedAuditLogIngestionEnabled value appears as False, it indicates that logging is disabled. In such cases, activate it by using the command:
Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true
It’s important to note that audit logs are not retroactive; if Unified Audit Logging was not enabled at the time of an incident, you will lack visibility into historic events.
For users with Microsoft 365 E3 licenses or higher, the Purview Audit (Standard) provides access to the MailItemsAccessed feature, which is crucial for tracking email access.
To access or export those events, several methods such as using the Purview Portal (Audit-Search) or Microsoft-Extractor-Suite can be employed.
In addition to these, Microsoft offers PowerShell cmdlets, although they may not effectively manage certain limitations. For more robust, enterprise-grade solutions, API-based versions are also available.
Once the data is gathered the analysis can start. For this article we use the Microsoft-Extractor-Suite and aim to import the Unified Audit Log data into Azure Data Explorer for easy analysis using the Kusto Query Language (KQL).
In this article, we will illustrate a mock scenario inspired by past cases where customers alerted a company after receiving unexpected emails requesting changes to bank account information. Upon verification, these messages were found to be illegitimate, prompting the IT department to initiate an investigation. This investigation uncovered suspicious activity involving the finance email account (i.e., [email protected]), which showed log-in activity from an unfamiliar IP address originating from an atypical location. Consequently, a compromise was suspected, leading to immediate response actions such as resetting the password and enforcing multi-factor authentication (MFA). A more in-depth investigation was then launched to determine the extent of the breach. At a certain stage in the investigation, the critical question arises: what information did the attackers access?
The investigation of MailItemsAccessed can be conducted at different stages, based on prioritization or objectives, such as scoping or eviction. To begin, it is essential to identify the set of mailboxes that have been compromised and determine the timeframe during which the attacker had access to these mailboxes within your organization.
As a preliminary step in the investigation, it is crucial to check for throttling. Throttling occurs when more than 1,000 MailItemsAccessed events are generated within a 24-hour period, resulting in a pause in logging for the next 24 hours.
During this pause, any access by attackers goes unrecorded, necessitating the assumption that the entire mailbox may have been compromised. Identifying throttling can streamline the investigation process by allowing you to focus on the potential for full mailbox access, rather than reconstructing fragmented data.
To identify potential throttling, the following KQL query can be utilized:
// Check if Throttled events exist
set notruncation;
let StartDate = datetime("2025-06-20 00:00:00"); // Filter for Timeframe (Start)
let EndDate = datetime("2025-07-10 00:00:00"); // Filter for Timeframe (End)
let UsersInScope = dynamic(["[email protected]"]); // Filter for Users in scope
UAL
| evaluate bag_unpack(AuditData, "_")
| where CreationDate between (StartDate .. EndDate)
| where UserIds has_any(UsersInScope)
| where Operations == "MailItemsAccessed"
| extend OperationPropertiesJson = parse_json(_OperationProperties)
| mv-apply OperationProperty = OperationPropertiesJson on (
where OperationProperty.Name == "IsThrottled" and OperationProperty.Value == "True"
)
Kusto
In our scenario, no throttled events were present.
Secondly, investigating synchronization activities is recommended, as these can indicate that an attacker has used a desktop version of Outlook for Windows or Mac to download messages from a mailbox.
Detection of sync activities suggests that a substantial number of messages have been downloaded to a local computer. For desktop versions, only the synchronization event is logged, capturing just the synced folder. This means that specific mail access is not recorded in the logs. This scenario implies that the attacker maintains access to the emails even if their access is revoked or the system is disconnected. Consequently, all synced folders must be considered compromised, as the attacker may still possess the downloaded data.
The following KQL query can be used to identify synchronization events:
// Check for Sync Events
set notruncation;
let StartDate = datetime("2025-06-20 00:00:00"); // Filter for Timeframe (Start)
let EndDate = datetime("2025-07-10 00:00:00"); // Filter for Timeframe (End)
let UsersInScope = dynamic(["[email protected]"]); // Filter for Users in scope
UAL
| evaluate bag_unpack(AuditData, "_")
| where CreationDate between (StartDate .. EndDate)
| where UserIds has_any(UsersInScope)
| where Operations == "MailItemsAccessed"
// Extend with GeoLocation
| extend GeoLocation = geo_info_from_ip_address(_ClientIPAddress)
// Process MailAccessType and filter for Sync Events
| extend OperationPropertiesJson = parse_json(_OperationProperties)
| mv-apply _OperationProperty = OperationPropertiesJson on (
where _OperationProperty.Name == "MailAccessType"
| extend MailAccessType = _OperationProperty.Value
| where MailAccessType == "Sync")
// Process FolderName for Sync events
| extend Item = parse_json(_Item)
| extend SyncParentFolder = tostring(Item["ParentFolder"]["Name"])
// Reorder columns for final output
| project-reorder CreationDate, _UserId, _Workload, RecordType, _Operation, MailAccessType, _OperationCount, SyncParentFolder, _ClientIPAddress, _ClientInfoString, _ActorInfoString, GeoLocation, _SessionId, _LogonType
Kusto
Below is an excerpt of a MailItemsAccessed sync event. This example illustrates how the synchronization of a mailbox folder appears in the logs. In this case, the Inbox folder was synchronized:
[…]
"_Item": {
"Id": "LgAAAABBBBBDtulRRIr26W1aTIXUAQC3nmcgmDUfTqyWpO/zvtOvAAAAAABBBBBB",
"ImmutableId": "ErrorDuringIdConversion",
"ParentFolder": {
"Id": " LgAAAABBBBBDtulRRIr26W1aTIXUAQC3nmcgmDUfTqyWpO/zvtOvAAAAAABBBBBB",
"Path": "Not Available",
"Name": "Inbox"
}
}
[…]
Example
Examining these events will also encompass legitimate activities. To differentiate between legitimate and malicious synchronization events, the following fields can be useful:
Field | Description |
---|---|
ClientIPAddress | IP address of the client machine. |
ClientInfoString | Describes protocol, client (includes version) |
ActorInfoString | The more detailed UserAgent used to access the mail. |
SessionId | Session ID helps to differentiate attacker actions vs day-to-day user activities on the same account (useful for compromised accounts) |
UserId | UPN of the user reading the message. |
GeoLocation | Simple indicator based on the IP Address of the client machine. |
In this example, we examine a mix of legitimate and malicious sync events. Most of the fields mentioned earlier differ between legitimate and malicious actions. However, the ActorInfoString warrants particular attention, as it contains detailed user-agent information and should be reviewed throughout the environment to identify any uncommon mail clients. By closely analyzing this field in our scenario, you can observe a switch between Outlook versions. Typically, you would expect to see only an increase in this version due to updates, assuming that a single client is being used. However, a downgrade followed by an upgrade suggests the presence of a second client with a different version, potentially indicating malicious activity.
Additionally, the SessionID is a valuable field for tracking actions even when the IP address changes. If a malicious action or a UserLoggedIn event is identified, pivoting the actions associated with the same SessionID can provide insights into the attacker’s activities.
In our scenario, actions originating from the United States with the Outlook version ending in “.20164” are deemed malicious, as they correspond to a compromised login with other suspicious activities. As shown in the screenshot, this indicates that all emails within the folders Sent Items, Junk Email, Deleted Items and Inbox were synced by the attacker. Consequently, emails within these folders should be considered compromised.
Focusing on these indicators could help to differentiate between legitimate and malicious activities.
In our case, some Sync events were present, but to understand the full extent of the situation, it was opted to also check for Bind events, as described in the next section.
The final step in the investigation is to examine Bind events. These events encompass all other email accesses that have not been scrutinized so far, such as access via Outlook Web or Mobile apps.
Bind events indicate individual access to email messages. For this type of access, an aggregated event is recorded, including all InternetMessageIds that were accessed within a 2-minute period. To provide a clearer view of the number of messages accessed, a separate field called OperationCount (found in AuditData) is included.
The following KQL query can be used to check the Bind events:
// Check for Bind Events
set notruncation;
let StartDate = datetime("2025-06-20 00:00:00"); // Filter for Timeframe (Start)
let EndDate = datetime("2025-07-10 00:00:00"); // Filter for Timeframe (End)
let UsersInScope = dynamic(["[email protected]"]); // Filter for Users in scope
UAL
| evaluate bag_unpack(AuditData, "_")
| where CreationDate between (StartDate .. EndDate)
| where UserIds has_any(UsersInScope)
| where Operations == "MailItemsAccessed"
// Extend with GeoLocation
| extend GeoLocation = geo_info_from_ip_address(_ClientIPAddress)
// Process MailAccessType and filter for Bind Events
| extend OperationPropertiesJson = parse_json(_OperationProperties)
| mv-apply _OperationProperty = OperationPropertiesJson on (
where _OperationProperty.Name == "MailAccessType"
| extend MailAccessType = _OperationProperty.Value
| where MailAccessType == "Bind")
| project-reorder CreationDate, _UserId, _Workload, RecordType, _Operation, MailAccessType, _OperationCount, _ClientIPAddress, _ClientInfoString, _ActorInfoString, GeoLocation, _SessionId, _LogonType
Kusto
Below is an excerpt of a Bind event, focusing on the messages accessed. In this example, four emails were accessed, as indicated by the OperationCount field. Additionally, you can see that all these emails were located in the Inbox.
[…]
"_OperationCount": 4,
"_Folders": [
{
"Id": "LgAAAAAdFAKE123FAKE456FAKE789FAKEABC/DEF123FAKE456FAKE789FAKE",
"Path": "\\Inbox",
"FolderItems": [
{
"Id": "LgAAAAAdFAKE123FAKE456FAKE789FAKEABC/DEF123FAKE456FAKE789FAKE",
"ImmutableId": "LgAAAAAdFAKE123FAKE456FAKE789FAKEABC/DEF123FAKE456FAKE789FAKE",
"InternetMessageId": "<[email protected]>",
"SizeInBytes": 72105
},
{
"Id": "LgAAAAAdFAKE123FAKE456FAKE789FAKEABC/DEF123FAKE456FAKE789FAKE",
"ImmutableId": "LgAAAAAdFAKE123FAKE456FAKE789FAKEABC/DEF123FAKE456FAKE789FAKE",
"InternetMessageId": "<ABC1234567896ABC1234567896ABC1234567896A@domain>",
"SizeInBytes": 13796326
},
{
"Id": "LgAAAAAdFAKE123FAKE456FAKE789FAKEABC/DEF123FAKE456FAKE789FAKE",
"ImmutableId": "LgAAAAAdFAKE123FAKE456FAKE789FAKEABC/DEF123FAKE456FAKE789FAKE",
"InternetMessageId": "<ABC1234567896ABC1234567896ABC1234567896A@domain>",
"SizeInBytes": 153729
},
{
"Id": "LgAAAAAdFAKE123FAKE456FAKE789FAKEABC/DEF123FAKE456FAKE789FAKE",
"ImmutableId": "LgAAAAAdFAKE123FAKE456FAKE789FAKEABC/DEF123FAKE456FAKE789FAKE",
"InternetMessageId": "<ABC1234567896ABC1234567896ABC1234567896A@domain>",
"SizeInBytes": 100891
},
]
}
],
[…]
Example
To obtain more information about the emails themselves, the InternetMessageID can be used to cross-reference with other logs, such as the MessageTraceLog.
By analyzing the InternetMessageIds contained in these events, you can check for sensitive information in emails or verify whether specific emails of concern were accessed. To retrieve the respective message IDs, you can use the following KQL query:
// Get MessageIds
set notruncation;
let StartDate = datetime("2025-06-20 00:00:00"); // Filter for Timeframe (Start)
let EndDate = datetime("2025-07-10 00:00:00"); // Filter for Timeframe (End)
let UsersInScope = dynamic(["[email protected]"]); // Filter for Users in scope
UAL
| evaluate bag_unpack(AuditData, "_")
| where CreationDate between (StartDate .. EndDate)
| where UserIds has_any(UsersInScope)
| where Operations == "MailItemsAccessed"
// Extend with GeoLocation
| extend GeoLocation = geo_info_from_ip_address(_ClientIPAddress)
// Process MailAccessType and filter for Bind Events
| extend OperationPropertiesJson = parse_json(_OperationProperties)
| mv-apply _OperationProperty = OperationPropertiesJson on (
where _OperationProperty.Name == "MailAccessType"
| extend MailAccessType = _OperationProperty.Value
| where MailAccessType == "Bind")
// Process MessageId's for Bind events
| extend Folders = parse_json(_Folders)
| mv-expand Folder = Folders
| mv-expand Item = Folder.FolderItems
| extend InternetMessageId = Item.InternetMessageId
| summarize count() by tostring(InternetMessageId)
Kusto
Despite Microsoft’s efforts to remove duplicates within a one-hour interval, duplicates of message IDs may still occur due to multiple accesses. To ensure each email is represented only once, you can summarize the InternetMessageIds. This approach helps confirm that each email was accessed at least once.
Addressing Business Email Compromise (BEC) incidents requires a comprehensive approach that goes beyond simply examining accessed emails. It is crucial to investigate other potential persistence mechanisms, such as OAuth applications and forwarding rules, as well as any additional actions performed by the attacker. Removing all active sessions, changing passwords and review/enforcing Multi-Factor Authentication (MFA) are essential steps in securing compromised accounts.
The significance of Unified Audit Logging (UAL) and mail access logs cannot be overstated in BEC cases, as they provide critical visibility into the actions taken during an attack.
Ultimately, prevention is the most effective strategy against BEC. This includes mechanisms such as rate-limiting accounts to avoid mass-sending malicious mails from compromised accounts. Additionally, user education is vital as informed employees can help prevent BEC attacks by recognizing suspicious emails and reporting unusual activities promptly, such as missing emails or emails not being received.
Protecting your organization is crucial in today's digital world. Our Incident Response services offers rapid solutions to cybersecurity incidents, while our assessments ensure your Microsoft 365 environment is secure.
Field | Description |
---|---|
UserId | The UPN of the user reading the message. |
ClientIPAddress | IP address of the client machine. |
MailAccessType | Whether the access is a bind or a sync operation. |
SessionId | Session ID helps to differentiate attacker actions vs day-to-day user activities on the same account (useful for compromised accounts). |
ClientInfoString | The client protocol, client used to access the mailbox. |
ActorInfoString | The more detailed UserAgent used to access the mail. |
OperationCount | Count of mail items accessed within this aggregated event. |
Item.ParentFolder | The full folder path of the mail item that was accessed. |
ClientIPAddress | IP address of the client computer. |
Logon_type | The logon type of the user who performed the action. The logon types (and their corresponding Enum value) are Owner (0), Admin (1), or Delegate (2). |
MailboxUPN | The UPN of the mailbox where the message being read is located. |
Kilian Neumair is a GCFA-certified Incident Response & Digital Forensics Analyst within NVISO’s CSIRT.