Hunting Mail Forwarding with Azure Sentinel
Do you know what is occurring inside your Exchange environment? Probably no… in a single week, there are hundreds of changes inside Exchange Online by the IT team and some users’ changes. The Hunting Mail Forwarding with Azure Sentinel post will guide how to hunt mail forwarding via KQL.
Most of the time, these changes are legitimate, but there are malicious changes internally and externally from time to time. One of these changes is Email forwarding that can be configured by IT or by the user.
Email forwarding enables a threat actor to secure a foothold inside an account even after losing direct access.
It’s usually a stepping stone to execute lateral movement within your environment from the Exchange infrastructure.
This threat vector is usually financially motivated, and according to the 2018-2020 Data Breach Investigations Report (DBIR), over 65 percent of breaches are financially motivated.
In a typical attack, malware or phishing usually compromise the end user’s account. According to Verizon’s DBIR, up to four percent of users will click on any given phishing email.
After the initial compromise, the threat actor signs in and enables auto-forwarding on the mailbox to an external account, and with access to the user’s email, the threat actor can:
- Spoof convincing emails to re-route payments to bank accounts they control
- Craft extremely topical and convincing spear-phishing messages to other users, enabling them to compromise additional accounts until the threat actor reaches the target
- Access confidential information, such as bank account numbers information that could be utilized for insider trading
Identify Forwarding with Kusto
There are numerous ways to identify email forwarding, and one of them is Azure Sentinel.
First, we must meet all information and variables to identify Exchange activities in Azure Sentinel. We can start from the OfficeWorkload table that provides information on which Office365 service it is related to.
The operation column will tell what kind of actions was performed, and for example, if we run the following queries, we can know what is running within Exchange.
We will start with a simple KQL query for OfficeWorkload with Exchange and the specific operation for Set-Mailbox.
| where OfficeWorkload == “Exchange” and Operation == “Set-Mailbox”
Then it returns results based on changes. Configuring a simple mail forwarder rule falls under the Set-Mailbox category, but other Exchange activities fall under that category.
That means we need to make sure and verify the KQL queries.
Because one of the parameters use the DeliverToMailboxAndForward parameter, we can add a command to the query and run the updated query with the query below:
OfficeActivity| where OfficeWorkload == “Exchange”and Operation == “Set-Mailbox” and Parameters has”DeliverToMailboxAndForward”
The parameters column contains data in a JSON format. It exposes a unique keyword that we can filter, and it shows another information for DeliverToMailboxAndForward.
If this value is exposed, so the user sets a mail forwarder rule on an inbox.
With this query, we’ve got beneficial information for the mail forwarding action. The critical information is:
UserId that contains the user principal name, which is the user that has set the forwarder rule
OfficeObjectId includes the user where the forwarder rule was placed on.
Parameters contain the mail was used as a mail forwarder rule, and if we expand the ForwardingSmtpAddress, we can know the forward email address.
Now we need to run the query with a new column that will create the name Value_, and it shows us which mail was used as a forwarder rule. This means that we don’t need to expand the Parameters column and look for the mail.
TIP: The value is essentially using the parse_json scalar operator
The final query will be with extending email and with the Project to show columns. We are interested in it.
OfficeActivity| where OfficeWorkload == “Exchange”and Operation == “Set-Mailbox”and Parameters has”DeliverToMailboxAndForward”| extend Email = tostring(parse_json(Parameters).Value)| project TimeGenerated, OfficeWorkload, UserId, OfficeObjectId, Email