Microsoft Cloud App Security: The Hunt in a multi-stage incident
Published Mar 09 2021 12:55 AM 21.7K Views

Welcome to our first post in the “Microsoft Cloud App Security: The Hunt blog series!  
Using Microsoft 365 Defender, our integrated solution, we will address common alerts customers receive in Microsoft Cloud App Security (called “MCAS” by users and enthusiasts) to determine the full scope and impact of a threat. We will show case how Microsoft 365 Defender assists security engineers by providing critical details such as how the threat entered the environment, what it has affected and how it is currently impacting the enterprise.


We will do this by taking the details we are given from an alert from Cloud App Security, using Kusto Query Language or KQL to query logs from various products across the Microsoft security stack that are available in Microsoft 365 defender Advanced hunting today.
Additionally, we will use the mapping of the MITRE ATT&CK Framework tactics and techniques available in 
Cloud App Security to assist our investigation on where or how an adversary may move next.


Throughout this blog series, we will address the alerts and scenarios we have seen most frequently from customers and apply simple but effective queries that can be used in everyday investigations. 

To begin this exciting journey, our first use case will walk you through a possible investigation path you could follow once receiving a multi-stage incidents from Cloud App Security. 


Use case 

Contoso implemented Microsoft 365 and is monitoring users at risk using Microsoft’s security solutions. 
While reviewing the new incidents, our security analyst notices a new multi-staged incident for a user named Megan Bowens. 

Multi-stage incidentMulti-stage incident



By opening the incident, our analyst can immediately identify the incident alerts and the mapped MITRE tactics. Based on those, it looks like the user account might have been compromised. Let’s confirm this using M365 Defender!  




Step 1: review the alerts to understand the incident context 

By looking at the timeline, it seems that the user connected from a location she did not use in the last six months (Activity from infrequent country:( Romania.



Microsoft Cloud App Security then triggered an out-of-the-box alert regarding activities from distant locations (Impossible travel activity). Using the information from this alert, admins can review activities from anywhere in the world: Belgium, Romania but also Belarus! 




Finally, it appears that during this session, the user created an inbox rule forwarding emails to, which is considered as suspicious by Microsoft Cloud App Security. 




Now that we understand the context, let’s investigate to understand the scope of the breach. 



Step 2: understand user’s specific context 

Before spending time in logs, we must understand the user’s context. The easiest way is to open her user page and review the provided information: 





On the user page, we are immediately provided information confirming that something happened with this user account: Megan’s account is considered a high risk by Azure Active Directory and her Investigation priority score suddenly increased in the last few days, plus her score is higher than 90% of the organization. We can also see from this page that she’s located in the United States. 



To understand her habits, let’s open the Locations details: 



This shows us the different locations used by the user in the last 30 days and the percentage of activities performed from those locations. 
It immediately appears that she is usually working from the US and Belgium, so activities performed from those countries are normal:


 If we go further, we can also see that some activities have been performed from other locations: Romania and Belarus: 




Now that we understand what is anomalous behavior for Megan (bases on the information above and her tracked "Locations" in her user profile), let’s hunt! 


Step 3: review the suspicious activities to understand the scope of the breach 

Our investigation will go through in different phases (list non-exhaustive). 



Why ? 

Summarize all the performed actions from the suspicious IP/location for that account 

Understand the risk based on performed activities (ex: reading an email = low risk, downloading/sharing files = medium risk, creating inbox rule/admin activities = high risk).  
If low risk activities, from mobile device for example, no further investigation might be required as this could be the user using a VPN client on her phone. 

Provide details on all accessed emails and their path in the mailbox 

Understand if access was targeted to sensitive information (finance, secrets, …). 
If the information seems sensitive and the device type seems suspicious, further investigation required. 

Also review the user agent to identify suspicious access. 

If emails were sent, review the recipients and message details. 

Identify potential phishing attempts or identify other compromised accounts. 
We will also use the user agent to identify potential tools using Graph API or SMTP. 

Review the accessed files 

Understand if access was targeted to sensitive information (finance, secrets, …). 

Review the created inbox rules 

Inbox rules can be used to exfiltrate data or hide conversations between the attacker and other recipients. 

Review other users using this IP address 

Identify potential compromised users or identify new potential corporate IP address used by a new office. 


  1. Obtain the user’s account object Id. 
    The Azure AD Account object ID is the unique identifier of a user account. Therefore, we will use this identifier for hunting scenarios as it is exposed in the different tables. You can get the user’s account object ID from the user entity page (screenshot below), or by querying the IdentityInfo table:


     Querying the table: 

    IdentityInfo | where AccountUpn =~ '' 


  2. Review our user’s signings to identify other potential suspicious locations or IP addresses.
    Using this query, you can get an overview of the users signing activity and identify potential anomalies. Note that if the user is using an AAD joined device and passing through a conditional access policy, the details of the managed device are exposed:

    let timeToSearch = startofday(datetime('2020-11-14')); 
    | where AccountObjectId == 'eababd92-9dc7-40e3-9359-6c106522db19' and Timestamp >= timeToSearch  
    | distinct Application, ResourceDisplayName, Country, City, IPAddress, DeviceName, DeviceTrustType, OSPlatform, IsManaged, IsCompliant, AuthenticationRequirement, RiskState, UserAgent, ClientAppUsed




  3. Summarize all the performed actions from the suspicious IP/location for that account. 
    Using this Advanced hunting query scoped to the alerts date, we can easily identify the performed actions: 

    let accountId = 'eababd92-9dc7-40e3-9359-6c106522db19'; 
    let locations = pack_array('RO', 'BY'); 
    let timeToSearch = startofday(datetime('2020-11-14')); 
        | where AccountObjectId == accountId and CountryCode in (locations) and Timestamp >= timeToSearch  
    | summarize by ActionType, CountryCode, AccountObjectId  
    | sort by ActionType asc 

    We can see that the malicious actor accessed and deleted emails, opened files, created and deleted inbox rules. 
    That’s a great start! We know now what we are looking for. 


  4. Review the accessed emails. 
    To understand what the actor was looking for, we can use the following query. It’s using events available with advanced auditing and the EmailEvents table to enrich emails details (subject, sender, recipients, …) when possible.

    let accountId = 'eababd92-9dc7-40e3-9359-6c106522db19'; 
    let locations = pack_array('RO', 'BY'); 
    let timeToSearch = startofday(datetime('2020-11-14')); 
        | where ActionType == 'MailItemsAccessed' and CountryCode in (locations) and AccountObjectId == accountId and Timestamp >= timeToSearch 
        | mv-expand todynamic(RawEventData.Folders)  
        | extend Path = todynamic(RawEventData_Folders.Path), SessionId = tostring(RawEventData.SessionId) 
        | mv-expand todynamic(RawEventData_Folders.FolderItems) 
        | project SessionId, Timestamp, AccountObjectId, DeviceType, CountryCode, City, IPAddress, UserAgent, Path, Message = tostring(RawEventData_Folders_FolderItems.InternetMessageId) 
        | join kind=leftouter ( 
            | where RecipientObjectId == accountId  
            | project Subject, RecipientEmailAddress , SenderMailFromAddress , DeliveryLocation , ThreatTypes, AttachmentCount , UrlCount , InternetMessageId  
            ) on $left.Message == $right.InternetMessageId  
    | sort by Timestamp desc

    Note the clients used: a browser and REST, indicating potential script accessing the emails:



  5. Review the accessed folders and files:
    let accountId = 'eababd92-9dc7-40e3-9359-6c106522db19'; 
    let locations = pack_array('RO', 'BY'); 
    let timeToSearch = startofday(datetime('2020-11-14')); 
        | where ActionType == 'FilePreviewed' and CountryCode in (locations) and AccountObjectId == accountId and Timestamp >= timeToSearch 
        | project Timestamp, CountryCode , IPAddress , ISP, UserAgent , Application, ActivityObjects, AccountObjectId 
        | mv-expand ActivityObjects 
        | where ActivityObjects['Type'] in ('File', 'Folder')  
        | evaluate bag_unpack(ActivityObjects) 




  6. Review the deleted emails. This might indicate that the actor tried to remove traces of discussions with other users or deletion of alerting emails: 
    let accountId = 'eababd92-9dc7-40e3-9359-6c106522db19'; 
    let locations = pack_array('RO', 'BY'); 
    let timeToSearch = startofday(datetime('2020-11-14')); 
        | where ActionType in~ ('MoveToDeletedItems', 'SoftDelete') and CountryCode in (locations) and AccountObjectId == accountId and Timestamp >= timeToSearch 
        | mv-expand ActivityObjects 
        | where ActivityObjects['Type'] in ('Email', 'Folder') 
        | evaluate bag_unpack(ActivityObjects) 
        | distinct Timestamp, AccountObjectId, ActionType, CountryCode, IPAddress, Type, Name, Id 
    | sort by Timestamp desc 

  7. Review the created/enabled/modified inbox rules. You can see here that the rule if looking for specific keywords, like “Credit Card” or “Password”: 
    let accountId = 'eababd92-9dc7-40e3-9359-6c106522db19'; 
    let locations = pack_array('RO', 'BY'); 
    let timeToSearch = startofday(datetime('2020-11-14')); 
        | where ActionType contains_cs 'InboxRule' and CountryCode in (locations) 
        | extend RuleParameters = RawEventData.Parameters 
    | project Timestamp, CountryCode , IPAddress , ISP, ActionType , ObjectName , RuleParameters  
    | sort by Timestamp desc 


  8. Now is time for our latest query that will identify scope of the breach. We hunted to get more information on Megan, our impacted user we got alerted from the incident. But there might be additional compromised users, we’ll use the IP addresses from the initial breach and search for other users having activities from those IP addresses:
    let accountId = 'eababd92-9dc7-40e3-9359-6c106522db19'; 
    let locations = pack_array('RO', 'BY'); 
    let timeToSearch = startofday(datetime('2020-11-14')); 
    let ips = (CloudAppEvents 
            | where CountryCode in (locations )  
            | distinct IPAddress , AccountObjectId  
    | join (CloudAppEvents | project ActivityIP = IPAddress, UserId = AccountObjectId ) on $left.IPAddress == $right.ActivityIP  
    | distinct UserId  
    | join IdentityInfo on $left.UserId == $right.AccountObjectId 
    | distinct AccountDisplayName , AccountUpn , Department , Country , City, AccountObjectId  



Step 4: time to remediate! 

Now that we have confirmed that Megan’s account had been compromised and we confirmed she was the only impacted user, it’s time to take action. 

The required actions will of course depend on your specific procedures, but a good start is confirming the user as compromised by clicking on “Take actions” or by going back to the user page and apply actions like suspending the user or requesting the user to sign-in again. 


take actions.png

confirm compromised.png


If you are syncing your accounts from Active Directory, you must perform the remediation steps on-premises. 
Also, note that integrating non-Microsoft apps to Microsoft Cloud App Security allows you to apply remediation to those apps too. 





A huge Thanks to @Tali Ash for the review!




For more information about the features discussed in this article, read: 

Learn more 

For further information on how your organization can benefit from Microsoft Cloud App Security, connect with us at the links below: 

Join the conversation on Tech Community 

Stay up to date—subscribe to our blog.  

Upload a log file from your network firewall or enable logging via Microsoft Defender for Endpoint to discover Shadow IT in your network. 

Learn more—download Top 20 use cases for CASB. 

Connect your cloud apps to detect suspicious user activity and exposed sensitive data. 

Search documentation on Microsoft Cloud App Security 

Enable out-of-the-box anomaly detection policies and start detecting cloud threats in your environment. 

Understand your licensing options​.  

Continue with more advanced use cases across information protection, compliance, and more. 

Follow the Microsoft Cloud App Security Ninja blog and learn about Ninja Training 

Go deeper these interactive guides: 



To experience the benefits of full-featured CASB, sign up for a free trial—Microsoft Cloud App Security. 

Follow us on LinkedIn as #CloudAppSecurity. To learn more about Microsoft Security solutions visit our website. Bookmark the Security blog to keep up with our expert coverage on security matters. Also, follow us at @MSFTSecurity on Twitter, and Microsoft Security on LinkedIn for the latest news and updates on cybersecurity. 

Version history
Last update:
‎Mar 09 2021 01:11 AM
Updated by: