Detecting and remediating emails with Defender XDR correlation

One of my customers have seen an interesting campaign, and they wanted help detecting and remediating it. Here’s a short summary of what they had observed:

  1. An email is sent to a shared mailbox from a consumer email address, such as Gmail. The purpose of these shared mailboxes is to allow consumers to contact via email, and therefore the users reading the mailboxes are used to getting lots of legitimate email from consumer email addresses. In this case, the same email is actually being sent to multiple shared mailboxes, but of course the users reading the email do not know that. The first email itself does not have any links or attachments, but simply asks for something specific. From the user’s perspective, there’s nothing suspicious about this email at this point.
  2. Once the user replies, they get another email continuing the story, this time there is a link asking them to fill in a form (or something like that). The link is to some legitimate cloud service (DropBox, Google Drive, what have you).
  3. When the user opens the link, it downloads a malicious piece of software. However, the software is benign enough not to be detected by the anti-malware engine (the EDR may detect it afterwards).

As these emails are coming from consumer email addresses, they will pass all the basic email authentication requirements (SPF, DKIM, DMARC). The customer is using Safe Links from Defender of Office (MDO), but that hasn’t been helping either (probably because the links are pointing to legitimate 3rd party cloud services). We cannot block these cloud services completely, because they have legitimate use in the organization.

A few options come to mind, which are not mutually exclusive:

  1. Try to protect the endpoint, and prevent the user from downloading the malicious file (or at least detect/prevent the file during execution).
  2. Try to identify the link in the second mail being malicious. Move the mail to Junk folder.
  3. Detect, when email is being sent from the same consumer email address to multiple shared mailboxes of this type. Move this email to the junk folder. If we’re fast enough, the user never sees the first email, and won’t reply to it. Or, if they reply to it, maybe we are able to move the second email (with the link) to Junk folder.

We could try to use Defender for Endpoint (MDE) to protect the endpoint (option 1), and in any case having an EDR is important for many reasons. However, unfortunately not all of the users reading these email have MDE installed (these are typically shared workstations). And for this particular case, remediating this threat via MDE is challenging. The users may also be getting legitimate links to the same cloud service, so we cannot really block that (e.g., using MDE Network Protection). And if the downloaded file is not detected by the anti-malware engine, how to separate valid links from malicious ones. Again, I still highly recommend having MDE in place, but it’s probably not our best solution for this particular threat.

We might be able to resolve option 2 with Exchange Online Protection (EOP) and Defender for Office 365 (MDO), by using transport rules and/or anti-spam policies. However, the challenge with this one is that these rules are analyzed on a per-mail basis. Again, how do we differentiate between malicious and legitimate emails, if both might be sent from the same consumer email provider, and have a link to the same cloud service?

Hence, we decided to try the option 3 instead.

Option 3: Detecting and remediating malicious emails via Defender XDR correlation

Our use case is pretty simple: if multiple shared mailboxes receive email from the same sender (using a consumer email address) during a short time period, move the email to Junk folder.

We could use either Microsoft Defender XDR for the detection, or we could use Microsoft Sentinel (if we’re sending the MDO events into Sentinel). If we use Sentinel, we need to automate the remediation with playbooks (at least until Sentinel becomes integrated with the Defender XDR portal). There doesn’t seem to be an easy way to do this with the Exchange Online or Defender XDR APIs, so I decided to create the detection logic directly in Defender XDR instead.

First, let’s send the same email from an outlook.com address to three different recipients in our test tenant. In this case, I’m adding all recipients into the same email, but in the real scenario they would be separate emails (this is tested later in the blog):

Once the email is sent, I’ll use the following KQL query to correlate the emails:

// Threshold: How many emails are tolerated from the sender
let Threshold = 2;
// Timespam: How far back are we looking into
let TimeSpan = 1h;
// List of sender domains that we are interested in (mainly consumer email)
let SenderDomains = dynamic([
"outlook.com",
"gmail.com",
]);
// Recipients that will be protected
let RecipientList = dynamic([
"recipient1@yourdomain.com",
"recipient2@yourdomain.com",
"recipient3@yourdomain.com"
]);
EmailEvents
| where Timestamp > ago(TimeSpan)
// Take only emails that are from specific domains (use envelope sender address)
| where SenderMailFromDomain in~ (SenderDomains)
// Take only emails that are sent to the list of recipients we are interested in
| where RecipientEmailAddress in~ (RecipientList)
// Filter based on number of emails sent from a single address
| summarize TotalEmailCount = count(), MessageIdList = make_set(NetworkMessageId), SubjectList = make_set(Subject) by SenderMailFromAddress
| where TotalEmailCount > Threshold
// Join back with EmailEvents table to get more information about each email, filter out emails that have already been remediated
| mv-expand MessageIdList
| extend NetworkMessageId = tostring(MessageIdList)
| join (
EmailEvents
| where LatestDeliveryLocation == "Inbox/folder"
) on NetworkMessageId
// Project relevant columns (note, that we need ReportId for the custom detection rule)
| project Timestamp, SenderMailFromAddress, RecipientEmailAddress, Subject, TotalEmailCount, LatestDeliveryLocation, LatestDeliveryAction, NetworkMessageId, ReportId
| sort by Timestamp desc

By running the query, you can see the results. Each line represents a recipient, and the TotalEmailCount shows the total number of recipients that got the email from this sender. The query will filter out emails that have already been remediated by using LatestDeliveryLocation column (we’ll see how this works later in the blog).

Now, let’s create a detection rule based on the query:

Enter basic information for the alert, such as:

  • Frequency: Every hour (minimum)
  • Severity: Info (we will automatically remediate the issue)

Select RecipientEmailAddress under Mailbox as the entity. This way we can target remediation actions for that mailbox.

In the Actions section, you can determine what to do with the emails. In my case, I want to move them to Junk folder.

Finalize the wizard:

One you’ve submitted the rule, it will run immediately. When looking at the detection rule, you can see that it has submitted actions on the three emails we sent (or in this case one email to three recipients):

It takes a few minutes for the action to be finalized. Once it’s done, we can rerun the advanced hunting query used for the custom detection rule, and see that there are no results:

If we comment out the LatestDeliveryLocation filter, we can see that all three emails have been moved to the Junk folder, just as we wanted.

Now, let’s try again. This time I’ll send three separate emails to individual recipients:

As we can see, the email gets delivered to inbox, because the detection rule is only executed once an hour.

We can also see the entries in the EmailEvents table, and that the latest delivery location is inbox. Note also, that the TotalEmailCount is now 6, because it counts in also the ones that were already delivered to junk (they were received within the 1-hour time window).

After an hour, the detection rule is triggered again. In the Incidents page, there are now four incidents. The first email that we sent to multiple recipients triggered one incident an hour earlier (with 3 mailboxes), while the individual emails will each trigger their own incident.

From one of the corresponding alerts, we can see that the Move to mailbox folder action has been triggered (there are two actions, because it shows also the action done for the first email sent to all three recipients):

When querying the EmailEvents table again, we can see that also these emails were delivered to the Junk folder.

And lo and behold, both emails are indeed in the recipient’s Junk Email folder:

Overall, the custom detection rules are very handy, when you want to perform automatic remediations for certain scenarios, that might be complex with Microsoft Sentinel automation/playbooks. We could also leverage other information available in Defender XDR, e.g., use the EmailAttachmentInfo and/or EmailUrlInfo tables to further correlate information. But in our case, we wanted to catch the first mail, which doesn’t have any links or attachments. It’s still not perfect, as we have the 1 hour window, when the user may respond to the email, receive the reply, and then click the link. But it’s good first step, and we can easily use the query for threat hunting first, and tweak the query accordingly.

As always, feedback is more than welcome! And if you’ve used some other way of remediating these kinds of campaigns, feel free to share :).

Leave a comment